1    // Copyright 2003 Adam Megacz, see the COPYING file for licensing [GPL] 
2    package org.xwt;
3    import java.io.*;
4    import org.xwt.js.*;
5    import org.xwt.util.*;
6    import org.xwt.translators.*;
7    
8    /** Interface implemented by classes capable of decoding an image file into an int[] */
9    public abstract class ImageDecoder {
10       
11       /** returns the width of the image */
12       public abstract int getWidth();
13   
14       /** returns the height of the image */
15       public abstract int getHeight();
16   
17       /** returns the data of the image, as an array of 32-bit AARRGGBB samples */
18       public abstract int[] getData();
19   
20       /** loads the image described by string str, possibly blocking for a network load */
21       public static ImageDecoder getImageDecoder(String str, final JS.Callable callback) {
22   
23           if (str.indexOf(':') == -1) {
24               String s = str;
25               byte[] b = Resources.getResource(Resources.resolve(s + ".png", null));
26               if (b != null) return PNG.decode(new ByteArrayInputStream(b), str);
27               b = Resources.getResource(Resources.resolve(s + ".jpeg", null));
28               if (b != null) return Platform.decodeJPEG(new ByteArrayInputStream(b), str);
29               return null;
30               
31           } else {
32               java.lang.Thread thread = java.lang.Thread.currentThread();
33               if (!(thread instanceof ThreadMessage)) {
34                   if (Log.on) Log.log(Box.class, "HTTP images can not be loaded from the foreground thread");
35                   return null;
36               }
37               // FIXME: use primitives here
38               ThreadMessage mythread = (ThreadMessage)thread;
39               mythread.setPriority(java.lang.Thread.MIN_PRIORITY);
40               mythread.done.release();
41               try {
42                   HTTP http = new HTTP(str);
43                   final HTTP.HTTPInputStream in = http.GET();
44                   final int contentLength = in.getContentLength();
45                   InputStream is = new FilterInputStream(in) {
46                           int bytesDownloaded = 0;
47                           boolean clear = true;
48                           public int read() throws IOException {
49                               bytesDownloaded++;
50                               return super.read();
51                           }
52                           public int read(byte[] b, int off, int len) throws IOException {
53                               int ret = super.read(b, off, len);
54                               if (ret != -1) bytesDownloaded += ret;
55                               if (clear && callback != null) {
56                                   clear = false;
57                                   ThreadMessage.newthread(new JS.Callable() {
58                                           public Object call(JS.Array args_) throws JS.Exn {
59                                               try {
60                                                   JS.Array args = new JS.Array();
61                                                   args.addElement(new Double(bytesDownloaded));
62                                                   args.addElement(new Double(contentLength));
63                                                   callback.call(args);
64                                               } finally {
65                                                   clear = true;
66                                               }
67                                               return null;
68                                           }
69                                       });
70                               }
71                               return ret;
72                           }
73                       };
74   
75                   if (str.endsWith(".gif")) return GIF.decode(is, str);
76                   else if (str.endsWith(".jpeg") || str.endsWith(".jpg")) return Platform.decodeJPEG(is, str);
77                   else return PNG.decode(is, str);
78   
79               } catch (IOException e) {
80                   if (Log.on) Log.log(Box.class, "error while trying to load an image from " + str);
81                   if (Log.on) Log.log(Box.class, e);
82                   return null;
83   
84               } finally {
85                   MessageQueue.add(mythread);
86                   mythread.setPriority(java.lang.Thread.NORM_PRIORITY);
87                   mythread.go.block();
88               }
89           }
90       }
91   
92       /** gets an Image using getImage(), adds it to the cache, and creates a Picture from it */
93       public static Picture getPicture(String os) {
94           Picture ret = null;
95           ret = (Picture)pictureCache.get(os);
96           if (ret != null) return ret;
97           ImageDecoder id = ImageDecoder.getImageDecoder(os, null);
98           if (id == null) return null;
99           ret = Platform.createPicture(id);
100          pictureCache.put(os, ret);
101          imageToNameMap.put(ret, os);
102          return ret;
103      }
104  
105      /** caches images, keyed on resource name or url */
106      public static Hash pictureCache = new Hash();
107  
108      /** stores image names, keyed on image object */
109      static Hash imageToNameMap = new Hash();
110  
111  }
112