Source for gnu.java.awt.peer.gtk.GdkPixbufDecoder

   1: /* GdkPixbufDecoder.java -- Image data decoding object
   2:    Copyright (C) 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
   3: 
   4: This file is part of GNU Classpath.
   5: 
   6: GNU Classpath is free software; you can redistribute it and/or modify
   7: it under the terms of the GNU General Public License as published by
   8: the Free Software Foundation; either version 2, or (at your option)
   9: any later version.
  10: 
  11: GNU Classpath is distributed in the hope that it will be useful, but
  12: WITHOUT ANY WARRANTY; without even the implied warranty of
  13: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  14: General Public License for more details.
  15: 
  16: You should have received a copy of the GNU General Public License
  17: along with GNU Classpath; see the file COPYING.  If not, write to the
  18: Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
  19: 02110-1301 USA.
  20: 
  21: Linking this library statically or dynamically with other modules is
  22: making a combined work based on this library.  Thus, the terms and
  23: conditions of the GNU General Public License cover the whole
  24: combination.
  25: 
  26: As a special exception, the copyright holders of this library give you
  27: permission to link this library with independent modules to produce an
  28: executable, regardless of the license terms of these independent
  29: modules, and to copy and distribute the resulting executable under
  30: terms of your choice, provided that you also meet, for each linked
  31: independent module, the terms and conditions of the license of that
  32: module.  An independent module is a module which is not derived from
  33: or based on this library.  If you modify this library, you may extend
  34: this exception to your version of the library, but you are not
  35: obligated to do so.  If you do not wish to do so, delete this
  36: exception statement from your version. */
  37: 
  38: 
  39: package gnu.java.awt.peer.gtk;
  40: 
  41: import java.awt.image.BufferedImage;
  42: import java.awt.image.ColorModel;
  43: import java.awt.image.DirectColorModel;
  44: import java.awt.image.ImageConsumer;
  45: import java.awt.image.Raster;
  46: import java.awt.image.RenderedImage;
  47: import java.io.DataInput;
  48: import java.io.DataOutput;
  49: import java.io.IOException;
  50: import java.io.InputStream;
  51: import java.net.URL;
  52: import java.util.ArrayList;
  53: import java.util.Hashtable;
  54: import java.util.Iterator;
  55: import java.util.Locale;
  56: import java.util.Vector;
  57: 
  58: import javax.imageio.IIOImage;
  59: import javax.imageio.ImageReadParam;
  60: import javax.imageio.ImageReader;
  61: import javax.imageio.ImageTypeSpecifier;
  62: import javax.imageio.ImageWriteParam;
  63: import javax.imageio.ImageWriter;
  64: import javax.imageio.metadata.IIOMetadata;
  65: import javax.imageio.spi.IIORegistry;
  66: import javax.imageio.spi.ImageReaderSpi;
  67: import javax.imageio.spi.ImageWriterSpi;
  68: import javax.imageio.stream.ImageInputStream;
  69: import javax.imageio.stream.ImageOutputStream;
  70: 
  71: public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
  72: {
  73:   static 
  74:   {
  75:     System.loadLibrary("gtkpeer");
  76: 
  77:     initStaticState ();
  78:   }
  79:   
  80:   /**
  81:    * Lock that should be held for all gdkpixbuf operations. We don't use
  82:    * the global gdk_threads_enter/leave functions since gdkpixbuf
  83:    * operations can be done in parallel to drawing and manipulating gtk
  84:    * widgets.
  85:    */
  86:   static Object pixbufLock = new Object();
  87: 
  88:   static native void initStaticState();
  89:   private final int native_state = GtkGenericPeer.getUniqueInteger ();
  90: 
  91:   // initState() has been called, but pumpDone() has not yet been called.
  92:   private boolean needsClose = false;
  93: 
  94:   // the current set of ImageConsumers for this decoder
  95:   Vector curr;
  96: 
  97:   // interface to GdkPixbuf
  98:   // These native functions should be called with the pixbufLock held.
  99:   native void initState ();
 100:   native void pumpBytes (byte[] bytes, int len) throws IOException;
 101:   native void pumpDone () throws IOException;
 102:   native void finish (boolean needsClose);
 103: 
 104:   /**
 105:    * Converts given image to bytes.
 106:    * Will call the GdkPixbufWriter for each chunk.
 107:    */
 108:   static native void streamImage(int[] bytes, String format,
 109:                                  int width, int height,
 110:                                  boolean hasAlpha, GdkPixbufWriter writer);
 111: 
 112:   // gdk-pixbuf provids data in RGBA format
 113:   static final ColorModel cm = new DirectColorModel (32, 0xff000000, 
 114:                                                      0x00ff0000, 
 115:                                                      0x0000ff00, 
 116:                                                      0x000000ff);
 117:   public GdkPixbufDecoder (DataInput datainput)
 118:   {
 119:     super (datainput);
 120:   }
 121: 
 122:   public GdkPixbufDecoder (InputStream in)
 123:   {
 124:     super (in);
 125:   }
 126: 
 127:   public GdkPixbufDecoder (String filename)
 128:   {
 129:     super (filename);
 130:   }
 131:   
 132:   public GdkPixbufDecoder (URL url)
 133:   {
 134:     super (url);
 135:   }
 136: 
 137:   public GdkPixbufDecoder (byte[] imagedata, int imageoffset, int imagelength)
 138:   {
 139:     super (imagedata, imageoffset, imagelength);
 140:   }
 141: 
 142:   // called back by native side: area_prepared_cb
 143:   void areaPrepared (int width, int height)
 144:   {
 145: 
 146:     if (curr == null)
 147:       return;
 148: 
 149:     for (int i = 0; i < curr.size (); i++)
 150:       {
 151:         ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
 152:         ic.setDimensions (width, height);
 153:         ic.setColorModel (cm);
 154:         ic.setHints (ImageConsumer.RANDOMPIXELORDER);
 155:       }
 156:   }
 157:   
 158:   // called back by native side: area_updated_cb
 159:   void areaUpdated (int x, int y, int width, int height, 
 160:                     int pixels[], int scansize)
 161:   {
 162:     if (curr == null)
 163:       return;
 164:     
 165:     for (int i = 0; i < curr.size (); i++)
 166:       {
 167:         ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
 168:         ic.setPixels (x, y, width, height, cm, pixels, 0, scansize);
 169:       }
 170:   }
 171:   
 172:   // called from an async image loader of one sort or another, this method
 173:   // repeatedly reads bytes from the input stream and passes them through a
 174:   // GdkPixbufLoader using the native method pumpBytes. pumpBytes in turn
 175:   // decodes the image data and calls back areaPrepared and areaUpdated on
 176:   // this object, feeding back decoded pixel blocks, which we pass to each
 177:   // of the ImageConsumers in the provided Vector.
 178: 
 179:   public void produce (Vector v, InputStream is) throws IOException
 180:   {
 181:     curr = v;
 182: 
 183:     byte bytes[] = new byte[4096];
 184:     int len = 0;
 185:     synchronized(pixbufLock)
 186:       {
 187:     initState();
 188:       }
 189:     needsClose = true;
 190: 
 191:     // Note: We don't want the pixbufLock while reading from the InputStream.
 192:     while ((len = is.read (bytes)) != -1)
 193:       {
 194:     synchronized(pixbufLock)
 195:       {
 196:         pumpBytes (bytes, len);
 197:       }
 198:       }
 199: 
 200:     synchronized(pixbufLock)
 201:       {
 202:     pumpDone();
 203:       }
 204: 
 205:     needsClose = false;
 206:     
 207:     for (int i = 0; i < curr.size (); i++)
 208:       {
 209:         ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
 210:         ic.imageComplete (ImageConsumer.STATICIMAGEDONE);
 211:       }
 212: 
 213:     curr = null;
 214:   }
 215: 
 216:   public void finalize()
 217:   {
 218:     synchronized(pixbufLock)
 219:       {
 220:     finish(needsClose);
 221:       }
 222:   }
 223: 
 224: 
 225:   public static class ImageFormatSpec
 226:   {
 227:     public String name;
 228:     public boolean writable = false;    
 229:     public ArrayList mimeTypes = new ArrayList();
 230:     public ArrayList extensions = new ArrayList();
 231: 
 232:     public ImageFormatSpec(String name, boolean writable)
 233:     {
 234:       this.name = name;
 235:       this.writable = writable;
 236:     }
 237: 
 238:     public synchronized void addMimeType(String m)
 239:     {
 240:       mimeTypes.add(m);
 241:     }
 242: 
 243:     public synchronized void addExtension(String e)
 244:     {
 245:       extensions.add(e);
 246:     }    
 247:   }
 248: 
 249:   static ArrayList imageFormatSpecs;
 250: 
 251:   public static ImageFormatSpec registerFormat(String name, boolean writable) 
 252:   {
 253:     ImageFormatSpec ifs = new ImageFormatSpec(name, writable);
 254:     synchronized(GdkPixbufDecoder.class)
 255:       {
 256:         if (imageFormatSpecs == null)
 257:           imageFormatSpecs = new ArrayList();
 258:         imageFormatSpecs.add(ifs);
 259:       }
 260:     return ifs;
 261:   }
 262: 
 263:   static String[] getFormatNames(boolean writable)
 264:   {
 265:     ArrayList names = new ArrayList();
 266:     synchronized (imageFormatSpecs) 
 267:       {
 268:         Iterator i = imageFormatSpecs.iterator();
 269:         while (i.hasNext())
 270:           {
 271:             ImageFormatSpec ifs = (ImageFormatSpec) i.next();
 272:             if (writable && !ifs.writable)
 273:               continue;
 274:             names.add(ifs.name);
 275: 
 276:             /* 
 277:              * In order to make the filtering code work, we need to register
 278:              * this type under every "format name" likely to be used as a synonym.
 279:              * This generally means "all the extensions people might use". 
 280:              */
 281: 
 282:             Iterator j = ifs.extensions.iterator();
 283:             while (j.hasNext())
 284:               names.add((String) j.next());
 285:           }
 286:       }
 287:     Object[] objs = names.toArray();
 288:     String[] strings = new String[objs.length];
 289:     for (int i = 0; i < objs.length; ++i)
 290:       strings[i] = (String) objs[i];
 291:     return strings;
 292:   }
 293: 
 294:   static String[] getFormatExtensions(boolean writable)
 295:   {
 296:     ArrayList extensions = new ArrayList();
 297:     synchronized (imageFormatSpecs) 
 298:       {
 299:         Iterator i = imageFormatSpecs.iterator();
 300:         while (i.hasNext())
 301:           {
 302:             ImageFormatSpec ifs = (ImageFormatSpec) i.next();
 303:             if (writable && !ifs.writable)
 304:               continue;
 305:             Iterator j = ifs.extensions.iterator();
 306:             while (j.hasNext())
 307:               extensions.add((String) j.next());
 308:           }
 309:       }
 310:     Object[] objs = extensions.toArray();
 311:     String[] strings = new String[objs.length];
 312:     for (int i = 0; i < objs.length; ++i)
 313:       strings[i] = (String) objs[i];
 314:     return strings;
 315:   }
 316: 
 317:   static String[] getFormatMimeTypes(boolean writable)
 318:   {
 319:     ArrayList mimeTypes = new ArrayList();
 320:     synchronized (imageFormatSpecs) 
 321:       {
 322:         Iterator i = imageFormatSpecs.iterator();
 323:         while (i.hasNext())
 324:           {
 325:             ImageFormatSpec ifs = (ImageFormatSpec) i.next();
 326:             if (writable && !ifs.writable)
 327:               continue;
 328:             Iterator j = ifs.mimeTypes.iterator();
 329:             while (j.hasNext())
 330:               mimeTypes.add((String) j.next());
 331:           }
 332:       }
 333:     Object[] objs = mimeTypes.toArray();
 334:     String[] strings = new String[objs.length];
 335:     for (int i = 0; i < objs.length; ++i)
 336:       strings[i] = (String) objs[i];
 337:     return strings;
 338:   }
 339: 
 340:   
 341:   static String findFormatName(Object ext, boolean needWritable)
 342:   {
 343:     if (ext == null)
 344:       return null;
 345: 
 346:     if (!(ext instanceof String))
 347:       throw new IllegalArgumentException("extension is not a string");
 348: 
 349:     String str = (String) ext;
 350: 
 351:     Iterator i = imageFormatSpecs.iterator();
 352:     while (i.hasNext())
 353:       {
 354:         ImageFormatSpec ifs = (ImageFormatSpec) i.next();
 355: 
 356:         if (needWritable && !ifs.writable)
 357:           continue;
 358: 
 359:         if (ifs.name.equals(str))
 360:           return str;
 361: 
 362:         Iterator j = ifs.extensions.iterator(); 
 363:         while (j.hasNext())
 364:           {
 365:             String extension = (String)j.next();
 366:             if (extension.equals(str))
 367:               return ifs.name;
 368:           }
 369: 
 370:         j = ifs.mimeTypes.iterator(); 
 371:         while (j.hasNext())
 372:           {
 373:             String mimeType = (String)j.next();
 374:             if (mimeType.equals(str))
 375:               return ifs.name;
 376:           }
 377:       }      
 378:     throw new IllegalArgumentException("unknown extension '" + str + "'");
 379:   }
 380: 
 381:   private static GdkPixbufReaderSpi readerSpi;
 382:   private static GdkPixbufWriterSpi writerSpi;
 383: 
 384:   public static synchronized GdkPixbufReaderSpi getReaderSpi()
 385:   {
 386:     if (readerSpi == null)
 387:       readerSpi = new GdkPixbufReaderSpi();
 388:     return readerSpi;
 389:   }
 390: 
 391:   public static synchronized GdkPixbufWriterSpi getWriterSpi()
 392:   {
 393:     if (writerSpi == null)
 394:       writerSpi = new GdkPixbufWriterSpi();
 395:     return writerSpi;
 396:   }
 397: 
 398:   public static void registerSpis(IIORegistry reg) 
 399:   {
 400:     reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class);
 401:     reg.registerServiceProvider(getWriterSpi(), ImageWriterSpi.class);
 402:   }
 403: 
 404:   public static class GdkPixbufWriterSpi extends ImageWriterSpi
 405:   {
 406:     public GdkPixbufWriterSpi() 
 407:     {      
 408:       super("GdkPixbuf", "2.x",
 409:             GdkPixbufDecoder.getFormatNames(true), 
 410:             GdkPixbufDecoder.getFormatExtensions(true), 
 411:             GdkPixbufDecoder.getFormatMimeTypes(true),
 412:             "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriter",
 413:             new Class[] { ImageOutputStream.class },
 414:             new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReaderSpi" },
 415:             false, null, null, null, null,
 416:             false, null, null, null, null);
 417:     }
 418: 
 419:     public boolean canEncodeImage(ImageTypeSpecifier ts)
 420:     {
 421:       return true;
 422:     }
 423: 
 424:     public ImageWriter createWriterInstance(Object ext)
 425:     {
 426:       return new GdkPixbufWriter(this, ext);
 427:     }
 428: 
 429:     public String getDescription(java.util.Locale loc)
 430:     {
 431:       return "GdkPixbuf Writer SPI";
 432:     }
 433: 
 434:   }
 435: 
 436:   public static class GdkPixbufReaderSpi extends ImageReaderSpi
 437:   {
 438:     public GdkPixbufReaderSpi() 
 439:     { 
 440:       super("GdkPixbuf", "2.x",
 441:             GdkPixbufDecoder.getFormatNames(false), 
 442:             GdkPixbufDecoder.getFormatExtensions(false), 
 443:             GdkPixbufDecoder.getFormatMimeTypes(false),
 444:             "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReader",
 445:             new Class[] { ImageInputStream.class },
 446:             new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriterSpi" },
 447:             false, null, null, null, null,
 448:             false, null, null, null, null);
 449:     }
 450: 
 451:     public boolean canDecodeInput(Object obj) 
 452:     { 
 453:       return true; 
 454:     }
 455: 
 456:     public ImageReader createReaderInstance(Object ext)
 457:     {
 458:       return new GdkPixbufReader(this, ext);
 459:     }
 460: 
 461:     public String getDescription(Locale loc)
 462:     {
 463:       return "GdkPixbuf Reader SPI";
 464:     }
 465:   }
 466: 
 467:   private static class GdkPixbufWriter
 468:     extends ImageWriter implements Runnable
 469:   {
 470:     String ext;
 471:     public GdkPixbufWriter(GdkPixbufWriterSpi ownerSpi, Object ext)
 472:     {
 473:       super(ownerSpi);
 474:       this.ext = findFormatName(ext, true);
 475:     }
 476: 
 477:     public IIOMetadata convertImageMetadata (IIOMetadata inData,
 478:                                              ImageTypeSpecifier imageType,
 479:                                              ImageWriteParam param)
 480:     {
 481:       return null;
 482:     }
 483: 
 484:     public IIOMetadata convertStreamMetadata (IIOMetadata inData,
 485:                                               ImageWriteParam param)
 486:     {
 487:       return null;
 488:     }
 489: 
 490:     public IIOMetadata getDefaultImageMetadata (ImageTypeSpecifier imageType, 
 491:                                                 ImageWriteParam param)
 492:     {
 493:       return null;
 494:     }
 495: 
 496:     public IIOMetadata getDefaultStreamMetadata (ImageWriteParam param)
 497:     {
 498:       return null;
 499:     }
 500: 
 501:   public void write (IIOMetadata streamMetadata, IIOImage i, ImageWriteParam param)
 502:     throws IOException
 503:     {
 504:       RenderedImage image = i.getRenderedImage();
 505:       Raster ras = image.getData();
 506:       int width = ras.getWidth();
 507:       int height = ras.getHeight();
 508:       ColorModel model = image.getColorModel();
 509:       int[] pixels = CairoGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras);
 510:       
 511:       if (pixels == null)
 512:         {
 513:       BufferedImage img;
 514:       if(model != null && model.hasAlpha())
 515:         img = CairoSurface.getBufferedImage(width, height);
 516:       img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
 517:           int[] pix = new int[4];
 518:           for (int y = 0; y < height; ++y)
 519:             for (int x = 0; x < width; ++x)
 520:               img.setRGB(x, y, model.getRGB(ras.getPixel(x, y, pix)));
 521:           pixels = CairoGraphics2D.findSimpleIntegerArray (img.getColorModel(), 
 522:                                                          img.getRaster());
 523:           model = img.getColorModel();
 524:         }
 525: 
 526:       Thread workerThread = new Thread(this, "GdkPixbufWriter");
 527:       workerThread.start();
 528:       processImageStarted(1);
 529:       synchronized(pixbufLock)
 530:     {
 531:       streamImage(pixels, this.ext, width, height, model.hasAlpha(), 
 532:               this);
 533:     }
 534:       synchronized(data)
 535:         {
 536:           data.add(DATADONE);
 537:           data.notifyAll();
 538:         }
 539: 
 540:       while (workerThread.isAlive())
 541:         {
 542:       try
 543:         {
 544:           workerThread.join();
 545:         }
 546:       catch (InterruptedException ioe)
 547:         {
 548:           // Ignored.
 549:         }
 550:         }
 551: 
 552:       if (exception != null)
 553:     throw exception;
 554: 
 555:       processImageComplete();
 556:     }    
 557: 
 558:     /**
 559:      * Object marking end of data from native streamImage code.
 560:      */
 561:     private static final Object DATADONE = new Object();
 562: 
 563:     /**
 564:      * Holds the data gotten from the native streamImage code.
 565:      * A worker thread will pull data out.
 566:      * Needs to be synchronized for access.
 567:      * The special object DATADONE is added when all data has been delivered.
 568:      */
 569:     private ArrayList data = new ArrayList();
 570: 
 571:     /**
 572:      * Holds any IOException thrown by the run method that needs
 573:      * to be rethrown by the write method.
 574:      */
 575:     private IOException exception;
 576: 
 577:     /** Callback for streamImage native code. **/
 578:     private void write(byte[] bs)
 579:     {
 580:       synchronized(data)
 581:         {
 582:           data.add(bs);
 583:           data.notifyAll();
 584:         }
 585:     }
 586: 
 587:     public void run()
 588:     {
 589:       boolean done = false;
 590:       while (!done)
 591:         {
 592:           synchronized(data)
 593:             {
 594:               while (data.isEmpty())
 595:                 {
 596:                   try
 597:                     {
 598:                       data.wait();
 599:                     }
 600:                   catch (InterruptedException ie)
 601:                     {
 602:                       /* ignore */
 603:                     }
 604:                 }
 605: 
 606:               Object o = data.remove(0);
 607:               if (o == DATADONE)
 608:                 done = true;
 609:               else
 610:                 {
 611:                   DataOutput out = (DataOutput) getOutput();
 612:                   try
 613:                     {
 614:                       out.write((byte[]) o);
 615:                     }
 616:                   catch (IOException ioe)
 617:                     {
 618:                       // We are only interested in the first exception.
 619:                       if (exception == null)
 620:                         exception = ioe;
 621:                     }
 622:                 }
 623:             }
 624:         }
 625:     }
 626:   }
 627: 
 628:   private static class GdkPixbufReader 
 629:     extends ImageReader
 630:     implements ImageConsumer
 631:   {
 632:     // ImageConsumer parts
 633:     GdkPixbufDecoder dec;
 634:     BufferedImage bufferedImage;
 635:     ColorModel defaultModel;
 636:     int width;
 637:     int height;
 638:     String ext;
 639:     
 640:     public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext)
 641:     {
 642:       super(ownerSpi);
 643:       this.ext = findFormatName(ext, false);
 644:     }
 645: 
 646:     public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext, GdkPixbufDecoder d)
 647:     {
 648:       this(ownerSpi, ext);
 649:       dec = d;
 650:     }
 651: 
 652:     public void setDimensions(int w, int h)
 653:     {
 654:       processImageStarted(1);
 655:       width = w;
 656:       height = h;
 657:     }
 658:     
 659:     public void setProperties(Hashtable props) {}
 660: 
 661:     public void setColorModel(ColorModel model) 
 662:     {
 663:       defaultModel = model;
 664:     }
 665: 
 666:     public void setHints(int flags) {}
 667: 
 668:     public void setPixels(int x, int y, int w, int h, 
 669:                           ColorModel model, byte[] pixels, 
 670:                           int offset, int scansize)
 671:     {
 672:     }      
 673: 
 674:     public void setPixels(int x, int y, int w, int h, 
 675:                           ColorModel model, int[] pixels, 
 676:                           int offset, int scansize)
 677:     {
 678:       if (model == null)
 679:         model = defaultModel;
 680:       
 681:       if (bufferedImage == null)
 682:         {
 683:       if(model != null && model.hasAlpha())
 684:         bufferedImage = new BufferedImage (width, height, BufferedImage.TYPE_INT_ARGB);
 685:       else
 686:         bufferedImage = new BufferedImage (width, height, BufferedImage.TYPE_INT_RGB);
 687:         }
 688: 
 689:       int pixels2[];
 690:       if (model != null)
 691:         {
 692:           pixels2 = new int[pixels.length];
 693:           for (int yy = 0; yy < h; yy++)
 694:             for (int xx = 0; xx < w; xx++)
 695:               {
 696:                 int i = yy * scansize + xx;
 697:                 pixels2[i] = model.getRGB (pixels[i]);
 698:               }
 699:         }
 700:       else
 701:         pixels2 = pixels;
 702: 
 703:       bufferedImage.setRGB (x, y, w, h, pixels2, offset, scansize);
 704:       processImageProgress(y / (height == 0 ? 1 : height));
 705:     }
 706: 
 707:     public void imageComplete(int status) 
 708:     {
 709:       processImageComplete();
 710:     }
 711: 
 712:     public BufferedImage getBufferedImage()
 713:     {
 714:       if (bufferedImage == null && dec != null)
 715:         dec.startProduction (this);
 716:       return bufferedImage;
 717:     }
 718: 
 719:     // ImageReader parts
 720: 
 721:     public int getNumImages(boolean allowSearch)
 722:       throws IOException
 723:     {
 724:       return 1;
 725:     }
 726: 
 727:     public IIOMetadata getImageMetadata(int i) 
 728:     {
 729:       return null;
 730:     }
 731: 
 732:     public IIOMetadata getStreamMetadata()
 733:       throws IOException
 734:     {
 735:       return null;
 736:     }
 737: 
 738:     public Iterator getImageTypes(int imageIndex)
 739:       throws IOException
 740:     {
 741:       BufferedImage img = getBufferedImage();
 742:       Vector vec = new Vector();
 743:       vec.add(new ImageTypeSpecifier(img));
 744:       return vec.iterator();
 745:     }
 746:     
 747:     public int getHeight(int imageIndex)
 748:       throws IOException
 749:     {
 750:       return getBufferedImage().getHeight();
 751:     }
 752: 
 753:     public int getWidth(int imageIndex)
 754:       throws IOException
 755:     {
 756:       return getBufferedImage().getWidth();
 757:     }
 758: 
 759:     public void setInput(Object input,
 760:                          boolean seekForwardOnly,
 761:                          boolean ignoreMetadata)
 762:     {
 763:       super.setInput(input, seekForwardOnly, ignoreMetadata);
 764:       Object get = getInput();
 765:       if (get instanceof InputStream)
 766:         dec = new GdkPixbufDecoder((InputStream) get);
 767:       else if (get instanceof DataInput)
 768:         dec = new GdkPixbufDecoder((DataInput) get);
 769:       else
 770:     throw new IllegalArgumentException("input object not supported: "
 771:                        + get);
 772:     }
 773: 
 774:     public BufferedImage read(int imageIndex, ImageReadParam param)
 775:       throws IOException
 776:     {
 777:       return getBufferedImage ();
 778:     }
 779:   }
 780: }