1:
37:
38:
39: package ;
40:
41: import ;
42:
43: import ;
44: import ;
45: import ;
46: import ;
47: import ;
48: import ;
49: import ;
50: import ;
51: import ;
52: import ;
53: import ;
54: import ;
55: import ;
56: import ;
57: import ;
58: import ;
59: import ;
60:
61: import ;
62: import ;
63: import ;
64: import ;
65: import ;
66: import ;
67: import ;
68: import ;
69: import ;
70: import ;
71: import ;
72: import ;
73:
74: public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
75: {
76: static
77: {
78: if (Configuration.INIT_LOAD_LIBRARY)
79: {
80: System.loadLibrary("gtkpeer");
81: }
82: initStaticState ();
83: }
84:
85: static native void initStaticState();
86: private final int native_state = GtkGenericPeer.getUniqueInteger ();
87:
88:
89: private boolean needsClose = false;
90:
91:
92: Vector curr;
93:
94:
95: native void initState ();
96: native void pumpBytes (byte[] bytes, int len) throws IOException;
97: native void pumpDone () throws IOException;
98: native void finish (boolean needsClose);
99: static native void streamImage(int[] bytes, String format, int width, int height, boolean hasAlpha, DataOutput sink);
100:
101:
102: static final ColorModel cm = new DirectColorModel (32, 0xff000000,
103: 0x00ff0000,
104: 0x0000ff00,
105: 0x000000ff);
106: public GdkPixbufDecoder (DataInput datainput)
107: {
108: super (datainput);
109: }
110:
111: public GdkPixbufDecoder (InputStream in)
112: {
113: super (in);
114: }
115:
116: public GdkPixbufDecoder (String filename)
117: {
118: super (filename);
119: }
120:
121: public GdkPixbufDecoder (URL url)
122: {
123: super (url);
124: }
125:
126: public GdkPixbufDecoder (byte[] imagedata, int imageoffset, int imagelength)
127: {
128: super (imagedata, imageoffset, imagelength);
129: }
130:
131:
132: void areaPrepared (int width, int height)
133: {
134:
135: if (curr == null)
136: return;
137:
138: for (int i = 0; i < curr.size (); i++)
139: {
140: ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
141: ic.setDimensions (width, height);
142: ic.setColorModel (cm);
143: ic.setHints (ImageConsumer.RANDOMPIXELORDER);
144: }
145: }
146:
147:
148: void areaUpdated (int x, int y, int width, int height,
149: int pixels[], int scansize)
150: {
151: if (curr == null)
152: return;
153:
154: for (int i = 0; i < curr.size (); i++)
155: {
156: ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
157: ic.setPixels (x, y, width, height, cm, pixels, 0, scansize);
158: }
159: }
160:
161:
162:
163:
164:
165:
166:
167:
168: public void produce (Vector v, InputStream is) throws IOException
169: {
170: curr = v;
171:
172: byte bytes[] = new byte[4096];
173: int len = 0;
174: initState();
175: needsClose = true;
176: while ((len = is.read (bytes)) != -1)
177: pumpBytes (bytes, len);
178: pumpDone();
179: needsClose = false;
180:
181: for (int i = 0; i < curr.size (); i++)
182: {
183: ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
184: ic.imageComplete (ImageConsumer.STATICIMAGEDONE);
185: }
186:
187: curr = null;
188: }
189:
190: public void finalize()
191: {
192: finish(needsClose);
193: }
194:
195:
196: public static class ImageFormatSpec
197: {
198: public String name;
199: public boolean writable = false;
200: public ArrayList mimeTypes = new ArrayList();
201: public ArrayList extensions = new ArrayList();
202:
203: public ImageFormatSpec(String name, boolean writable)
204: {
205: this.name = name;
206: this.writable = writable;
207: }
208:
209: public synchronized void addMimeType(String m)
210: {
211: mimeTypes.add(m);
212: }
213:
214: public synchronized void addExtension(String e)
215: {
216: extensions.add(e);
217: }
218: }
219:
220: static ArrayList imageFormatSpecs;
221:
222: public static ImageFormatSpec registerFormat(String name, boolean writable)
223: {
224: ImageFormatSpec ifs = new ImageFormatSpec(name, writable);
225: synchronized(GdkPixbufDecoder.class)
226: {
227: if (imageFormatSpecs == null)
228: imageFormatSpecs = new ArrayList();
229: imageFormatSpecs.add(ifs);
230: }
231: return ifs;
232: }
233:
234: static String[] getFormatNames(boolean writable)
235: {
236: ArrayList names = new ArrayList();
237: synchronized (imageFormatSpecs)
238: {
239: Iterator i = imageFormatSpecs.iterator();
240: while (i.hasNext())
241: {
242: ImageFormatSpec ifs = (ImageFormatSpec) i.next();
243: if (writable && !ifs.writable)
244: continue;
245: names.add(ifs.name);
246:
247:
252:
253: Iterator j = ifs.extensions.iterator();
254: while (j.hasNext())
255: names.add((String) j.next());
256: }
257: }
258: Object[] objs = names.toArray();
259: String[] strings = new String[objs.length];
260: for (int i = 0; i < objs.length; ++i)
261: strings[i] = (String) objs[i];
262: return strings;
263: }
264:
265: static String[] getFormatExtensions(boolean writable)
266: {
267: ArrayList extensions = new ArrayList();
268: synchronized (imageFormatSpecs)
269: {
270: Iterator i = imageFormatSpecs.iterator();
271: while (i.hasNext())
272: {
273: ImageFormatSpec ifs = (ImageFormatSpec) i.next();
274: if (writable && !ifs.writable)
275: continue;
276: Iterator j = ifs.extensions.iterator();
277: while (j.hasNext())
278: extensions.add((String) j.next());
279: }
280: }
281: Object[] objs = extensions.toArray();
282: String[] strings = new String[objs.length];
283: for (int i = 0; i < objs.length; ++i)
284: strings[i] = (String) objs[i];
285: return strings;
286: }
287:
288: static String[] getFormatMimeTypes(boolean writable)
289: {
290: ArrayList mimeTypes = new ArrayList();
291: synchronized (imageFormatSpecs)
292: {
293: Iterator i = imageFormatSpecs.iterator();
294: while (i.hasNext())
295: {
296: ImageFormatSpec ifs = (ImageFormatSpec) i.next();
297: if (writable && !ifs.writable)
298: continue;
299: Iterator j = ifs.mimeTypes.iterator();
300: while (j.hasNext())
301: mimeTypes.add((String) j.next());
302: }
303: }
304: Object[] objs = mimeTypes.toArray();
305: String[] strings = new String[objs.length];
306: for (int i = 0; i < objs.length; ++i)
307: strings[i] = (String) objs[i];
308: return strings;
309: }
310:
311:
312: static String findFormatName(Object ext, boolean needWritable)
313: {
314: if (ext == null)
315: return null;
316:
317: if (!(ext instanceof String))
318: throw new IllegalArgumentException("extension is not a string");
319:
320: String str = (String) ext;
321:
322: Iterator i = imageFormatSpecs.iterator();
323: while (i.hasNext())
324: {
325: ImageFormatSpec ifs = (ImageFormatSpec) i.next();
326:
327: if (needWritable && !ifs.writable)
328: continue;
329:
330: if (ifs.name.equals(str))
331: return str;
332:
333: Iterator j = ifs.extensions.iterator();
334: while (j.hasNext())
335: {
336: String extension = (String)j.next();
337: if (extension.equals(str))
338: return ifs.name;
339: }
340:
341: j = ifs.mimeTypes.iterator();
342: while (j.hasNext())
343: {
344: String mimeType = (String)j.next();
345: if (mimeType.equals(str))
346: return ifs.name;
347: }
348: }
349: throw new IllegalArgumentException("unknown extension '" + str + "'");
350: }
351:
352: private static GdkPixbufReaderSpi readerSpi;
353: private static GdkPixbufWriterSpi writerSpi;
354:
355: public static synchronized GdkPixbufReaderSpi getReaderSpi()
356: {
357: if (readerSpi == null)
358: readerSpi = new GdkPixbufReaderSpi();
359: return readerSpi;
360: }
361:
362: public static synchronized GdkPixbufWriterSpi getWriterSpi()
363: {
364: if (writerSpi == null)
365: writerSpi = new GdkPixbufWriterSpi();
366: return writerSpi;
367: }
368:
369: public static void registerSpis(IIORegistry reg)
370: {
371: reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class);
372: reg.registerServiceProvider(getWriterSpi(), ImageWriterSpi.class);
373: }
374:
375: public static class GdkPixbufWriterSpi extends ImageWriterSpi
376: {
377: public GdkPixbufWriterSpi()
378: {
379: super("GdkPixbuf", "2.x",
380: GdkPixbufDecoder.getFormatNames(true),
381: GdkPixbufDecoder.getFormatExtensions(true),
382: GdkPixbufDecoder.getFormatMimeTypes(true),
383: "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriter",
384: new Class[] { ImageOutputStream.class },
385: new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReaderSpi" },
386: false, null, null, null, null,
387: false, null, null, null, null);
388: }
389:
390: public boolean canEncodeImage(ImageTypeSpecifier ts)
391: {
392: return true;
393: }
394:
395: public ImageWriter createWriterInstance(Object ext)
396: {
397: return new GdkPixbufWriter(this, ext);
398: }
399:
400: public String getDescription(java.util.Locale loc)
401: {
402: return "GdkPixbuf Writer SPI";
403: }
404:
405: }
406:
407: public static class GdkPixbufReaderSpi extends ImageReaderSpi
408: {
409: public GdkPixbufReaderSpi()
410: {
411: super("GdkPixbuf", "2.x",
412: GdkPixbufDecoder.getFormatNames(false),
413: GdkPixbufDecoder.getFormatExtensions(false),
414: GdkPixbufDecoder.getFormatMimeTypes(false),
415: "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReader",
416: new Class[] { ImageInputStream.class },
417: new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriterSpi" },
418: false, null, null, null, null,
419: false, null, null, null, null);
420: }
421:
422: public boolean canDecodeInput(Object obj)
423: {
424: return true;
425: }
426:
427: public ImageReader createReaderInstance(Object ext)
428: {
429: return new GdkPixbufReader(this, ext);
430: }
431:
432: public String getDescription(Locale loc)
433: {
434: return "GdkPixbuf Reader SPI";
435: }
436: }
437:
438: private static class GdkPixbufWriter
439: extends ImageWriter
440: {
441: String ext;
442: public GdkPixbufWriter(GdkPixbufWriterSpi ownerSpi, Object ext)
443: {
444: super(ownerSpi);
445: this.ext = findFormatName(ext, true);
446: }
447:
448: public IIOMetadata convertImageMetadata (IIOMetadata inData,
449: ImageTypeSpecifier imageType,
450: ImageWriteParam param)
451: {
452: return null;
453: }
454:
455: public IIOMetadata convertStreamMetadata (IIOMetadata inData,
456: ImageWriteParam param)
457: {
458: return null;
459: }
460:
461: public IIOMetadata getDefaultImageMetadata (ImageTypeSpecifier imageType,
462: ImageWriteParam param)
463: {
464: return null;
465: }
466:
467: public IIOMetadata getDefaultStreamMetadata (ImageWriteParam param)
468: {
469: return null;
470: }
471:
472: public void write (IIOMetadata streamMetadata, IIOImage i, ImageWriteParam param)
473: throws IOException
474: {
475: RenderedImage image = i.getRenderedImage();
476: Raster ras = image.getData();
477: int width = ras.getWidth();
478: int height = ras.getHeight();
479: ColorModel model = image.getColorModel();
480: int[] pixels = GdkGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras);
481:
482: if (pixels == null)
483: {
484: BufferedImage img = new BufferedImage(width, height,
485: (model != null && model.hasAlpha() ?
486: BufferedImage.TYPE_INT_ARGB
487: : BufferedImage.TYPE_INT_RGB));
488: int[] pix = new int[4];
489: for (int y = 0; y < height; ++y)
490: for (int x = 0; x < width; ++x)
491: img.setRGB(x, y, model.getRGB(ras.getPixel(x, y, pix)));
492: pixels = GdkGraphics2D.findSimpleIntegerArray (img.getColorModel(),
493: img.getRaster());
494: model = img.getColorModel();
495: }
496:
497: processImageStarted(1);
498: streamImage(pixels, this.ext, width, height, model.hasAlpha(),
499: (DataOutput) this.getOutput());
500: processImageComplete();
501: }
502: }
503:
504: private static class GdkPixbufReader
505: extends ImageReader
506: implements ImageConsumer
507: {
508:
509: GdkPixbufDecoder dec;
510: BufferedImage bufferedImage;
511: ColorModel defaultModel;
512: int width;
513: int height;
514: String ext;
515:
516: public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext)
517: {
518: super(ownerSpi);
519: this.ext = findFormatName(ext, false);
520: }
521:
522: public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext, GdkPixbufDecoder d)
523: {
524: this(ownerSpi, ext);
525: dec = d;
526: }
527:
528: public void setDimensions(int w, int h)
529: {
530: processImageStarted(1);
531: width = w;
532: height = h;
533: }
534:
535: public void setProperties(Hashtable props) {}
536:
537: public void setColorModel(ColorModel model)
538: {
539: defaultModel = model;
540: }
541:
542: public void setHints(int flags) {}
543:
544: public void setPixels(int x, int y, int w, int h,
545: ColorModel model, byte[] pixels,
546: int offset, int scansize)
547: {
548: }
549:
550: public void setPixels(int x, int y, int w, int h,
551: ColorModel model, int[] pixels,
552: int offset, int scansize)
553: {
554: if (model == null)
555: model = defaultModel;
556:
557: if (bufferedImage == null)
558: {
559: bufferedImage = new BufferedImage (width, height, (model != null && model.hasAlpha() ?
560: BufferedImage.TYPE_INT_ARGB
561: : BufferedImage.TYPE_INT_RGB));
562: }
563:
564: int pixels2[];
565: if (model != null)
566: {
567: pixels2 = new int[pixels.length];
568: for (int yy = 0; yy < h; yy++)
569: for (int xx = 0; xx < w; xx++)
570: {
571: int i = yy * scansize + xx;
572: pixels2[i] = model.getRGB (pixels[i]);
573: }
574: }
575: else
576: pixels2 = pixels;
577:
578: bufferedImage.setRGB (x, y, w, h, pixels2, offset, scansize);
579: processImageProgress(y / (height == 0 ? 1 : height));
580: }
581:
582: public void imageComplete(int status)
583: {
584: processImageComplete();
585: }
586:
587: public BufferedImage getBufferedImage()
588: {
589: if (bufferedImage == null && dec != null)
590: dec.startProduction (this);
591: return bufferedImage;
592: }
593:
594:
595:
596: public int getNumImages(boolean allowSearch)
597: throws IOException
598: {
599: return 1;
600: }
601:
602: public IIOMetadata getImageMetadata(int i)
603: {
604: return null;
605: }
606:
607: public IIOMetadata getStreamMetadata()
608: throws IOException
609: {
610: return null;
611: }
612:
613: public Iterator getImageTypes(int imageIndex)
614: throws IOException
615: {
616: BufferedImage img = getBufferedImage();
617: Vector vec = new Vector();
618: vec.add(new ImageTypeSpecifier(img));
619: return vec.iterator();
620: }
621:
622: public int getHeight(int imageIndex)
623: throws IOException
624: {
625: return getBufferedImage().getHeight();
626: }
627:
628: public int getWidth(int imageIndex)
629: throws IOException
630: {
631: return getBufferedImage().getWidth();
632: }
633:
634: public void setInput(Object input,
635: boolean seekForwardOnly,
636: boolean ignoreMetadata)
637: {
638: super.setInput(input, seekForwardOnly, ignoreMetadata);
639: Object get = getInput();
640: if (get instanceof InputStream)
641: dec = new GdkPixbufDecoder((InputStream) get);
642: else if (get instanceof DataInput)
643: dec = new GdkPixbufDecoder((DataInput) get);
644: else
645: throw new IllegalArgumentException("input object not supported: "
646: + get);
647: }
648:
649: public BufferedImage read(int imageIndex, ImageReadParam param)
650: throws IOException
651: {
652: return getBufferedImage ();
653: }
654: }
655:
656:
657:
658:
659:
660: public static BufferedImage createBufferedImage (String filename)
661: {
662: GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(),
663: "png",
664: new GdkPixbufDecoder (filename));
665: return r.getBufferedImage ();
666: }
667:
668: public static BufferedImage createBufferedImage (URL u)
669: {
670: GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(),
671: "png",
672: new GdkPixbufDecoder (u));
673: return r.getBufferedImage ();
674: }
675:
676: public static BufferedImage createBufferedImage (byte[] imagedata, int imageoffset,
677: int imagelength)
678: {
679: GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(),
680: "png",
681: new GdkPixbufDecoder (imagedata,
682: imageoffset,
683: imagelength));
684: return r.getBufferedImage ();
685: }
686:
687: public static BufferedImage createBufferedImage (ImageProducer producer)
688: {
689: GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), "png" , null);
690: producer.startProduction(r);
691: return r.getBufferedImage ();
692: }
693:
694: }