mirror of git://gcc.gnu.org/git/gcc.git
				
				
				
			
		
			
				
	
	
		
			786 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Java
		
	
	
	
			
		
		
	
	
			786 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			Java
		
	
	
	
/* GdkPixbufDecoder.java -- Image data decoding object
 | 
						|
   Copyright (C) 2003, 2004, 2005, 2006  Free Software Foundation, Inc.
 | 
						|
 | 
						|
This file is part of GNU Classpath.
 | 
						|
 | 
						|
GNU Classpath is free software; you can redistribute it and/or modify
 | 
						|
it under the terms of the GNU General Public License as published by
 | 
						|
the Free Software Foundation; either version 2, or (at your option)
 | 
						|
any later version.
 | 
						|
 | 
						|
GNU Classpath is distributed in the hope that it will be useful, but
 | 
						|
WITHOUT ANY WARRANTY; without even the implied warranty of
 | 
						|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 | 
						|
General Public License for more details.
 | 
						|
 | 
						|
You should have received a copy of the GNU General Public License
 | 
						|
along with GNU Classpath; see the file COPYING.  If not, write to the
 | 
						|
Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
 | 
						|
02110-1301 USA.
 | 
						|
 | 
						|
Linking this library statically or dynamically with other modules is
 | 
						|
making a combined work based on this library.  Thus, the terms and
 | 
						|
conditions of the GNU General Public License cover the whole
 | 
						|
combination.
 | 
						|
 | 
						|
As a special exception, the copyright holders of this library give you
 | 
						|
permission to link this library with independent modules to produce an
 | 
						|
executable, regardless of the license terms of these independent
 | 
						|
modules, and to copy and distribute the resulting executable under
 | 
						|
terms of your choice, provided that you also meet, for each linked
 | 
						|
independent module, the terms and conditions of the license of that
 | 
						|
module.  An independent module is a module which is not derived from
 | 
						|
or based on this library.  If you modify this library, you may extend
 | 
						|
this exception to your version of the library, but you are not
 | 
						|
obligated to do so.  If you do not wish to do so, delete this
 | 
						|
exception statement from your version. */
 | 
						|
 | 
						|
 | 
						|
package gnu.java.awt.peer.gtk;
 | 
						|
 | 
						|
import java.awt.image.BufferedImage;
 | 
						|
import java.awt.image.ColorModel;
 | 
						|
import java.awt.image.DirectColorModel;
 | 
						|
import java.awt.image.ImageConsumer;
 | 
						|
import java.awt.image.Raster;
 | 
						|
import java.awt.image.RenderedImage;
 | 
						|
import java.io.DataInput;
 | 
						|
import java.io.DataOutput;
 | 
						|
import java.io.IOException;
 | 
						|
import java.io.InputStream;
 | 
						|
import java.net.URL;
 | 
						|
import java.util.ArrayList;
 | 
						|
import java.util.Hashtable;
 | 
						|
import java.util.Iterator;
 | 
						|
import java.util.Locale;
 | 
						|
import java.util.Vector;
 | 
						|
 | 
						|
import javax.imageio.IIOImage;
 | 
						|
import javax.imageio.ImageReadParam;
 | 
						|
import javax.imageio.ImageReader;
 | 
						|
import javax.imageio.ImageTypeSpecifier;
 | 
						|
import javax.imageio.ImageWriteParam;
 | 
						|
import javax.imageio.ImageWriter;
 | 
						|
import javax.imageio.metadata.IIOMetadata;
 | 
						|
import javax.imageio.spi.IIORegistry;
 | 
						|
import javax.imageio.spi.ImageReaderSpi;
 | 
						|
import javax.imageio.spi.ImageWriterSpi;
 | 
						|
import javax.imageio.stream.ImageInputStream;
 | 
						|
import javax.imageio.stream.ImageOutputStream;
 | 
						|
 | 
						|
import gnu.classpath.Configuration;
 | 
						|
import gnu.classpath.Pointer;
 | 
						|
 | 
						|
public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder
 | 
						|
{
 | 
						|
  static
 | 
						|
  {
 | 
						|
    if (true) // GCJ LOCAL
 | 
						|
      {
 | 
						|
        System.loadLibrary("gtkpeer");
 | 
						|
      }
 | 
						|
 | 
						|
    initStaticState ();
 | 
						|
  }
 | 
						|
 | 
						|
  /**
 | 
						|
   * Lock that should be held for all gdkpixbuf operations. We don't use
 | 
						|
   * the global gdk_threads_enter/leave functions since gdkpixbuf
 | 
						|
   * operations can be done in parallel to drawing and manipulating gtk
 | 
						|
   * widgets.
 | 
						|
   */
 | 
						|
  static Object pixbufLock = new Object();
 | 
						|
 | 
						|
  static native void initStaticState();
 | 
						|
  private final int native_state = GtkGenericPeer.getUniqueInteger ();
 | 
						|
 | 
						|
  // initState() has been called, but pumpDone() has not yet been called.
 | 
						|
  private boolean needsClose = false;
 | 
						|
 | 
						|
  // the current set of ImageConsumers for this decoder
 | 
						|
  Vector curr;
 | 
						|
 | 
						|
  /**
 | 
						|
   * The pointer to the native pixbuf loader.
 | 
						|
   *
 | 
						|
   * This field is manipulated by native code. Don't change or remove
 | 
						|
   * without adjusting the native code.
 | 
						|
   */
 | 
						|
  private Pointer nativeDecoder;
 | 
						|
 | 
						|
  // interface to GdkPixbuf
 | 
						|
  // These native functions should be called with the pixbufLock held.
 | 
						|
  native void initState ();
 | 
						|
  native void pumpBytes (byte[] bytes, int len) throws IOException;
 | 
						|
  native void pumpDone () throws IOException;
 | 
						|
  native void finish (boolean needsClose);
 | 
						|
 | 
						|
  /**
 | 
						|
   * Converts given image to bytes.
 | 
						|
   * Will call the GdkPixbufWriter for each chunk.
 | 
						|
   */
 | 
						|
  static native void streamImage(int[] bytes, String format,
 | 
						|
                                 int width, int height,
 | 
						|
                                 boolean hasAlpha, GdkPixbufWriter writer);
 | 
						|
 | 
						|
  // gdk-pixbuf provids data in RGBA format
 | 
						|
  static final ColorModel cm = new DirectColorModel (32, 0xff000000,
 | 
						|
                                                     0x00ff0000,
 | 
						|
                                                     0x0000ff00,
 | 
						|
                                                     0x000000ff);
 | 
						|
  public GdkPixbufDecoder (DataInput datainput)
 | 
						|
  {
 | 
						|
    super (datainput);
 | 
						|
  }
 | 
						|
 | 
						|
  public GdkPixbufDecoder (InputStream in)
 | 
						|
  {
 | 
						|
    super (in);
 | 
						|
  }
 | 
						|
 | 
						|
  public GdkPixbufDecoder (String filename)
 | 
						|
  {
 | 
						|
    super (filename);
 | 
						|
  }
 | 
						|
 | 
						|
  public GdkPixbufDecoder (URL url)
 | 
						|
  {
 | 
						|
    super (url);
 | 
						|
  }
 | 
						|
 | 
						|
  public GdkPixbufDecoder (byte[] imagedata, int imageoffset, int imagelength)
 | 
						|
  {
 | 
						|
    super (imagedata, imageoffset, imagelength);
 | 
						|
  }
 | 
						|
 | 
						|
  // called back by native side: area_prepared_cb
 | 
						|
  void areaPrepared (int width, int height)
 | 
						|
  {
 | 
						|
 | 
						|
    if (curr == null)
 | 
						|
      return;
 | 
						|
 | 
						|
    for (int i = 0; i < curr.size (); i++)
 | 
						|
      {
 | 
						|
        ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
 | 
						|
        ic.setDimensions (width, height);
 | 
						|
        ic.setColorModel (cm);
 | 
						|
        ic.setHints (ImageConsumer.RANDOMPIXELORDER);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // called back by native side: area_updated_cb
 | 
						|
  void areaUpdated (int x, int y, int width, int height,
 | 
						|
                    int pixels[], int scansize)
 | 
						|
  {
 | 
						|
    if (curr == null)
 | 
						|
      return;
 | 
						|
 | 
						|
    for (int i = 0; i < curr.size (); i++)
 | 
						|
      {
 | 
						|
        ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
 | 
						|
        ic.setPixels (x, y, width, height, cm, pixels, 0, scansize);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
  // called from an async image loader of one sort or another, this method
 | 
						|
  // repeatedly reads bytes from the input stream and passes them through a
 | 
						|
  // GdkPixbufLoader using the native method pumpBytes. pumpBytes in turn
 | 
						|
  // decodes the image data and calls back areaPrepared and areaUpdated on
 | 
						|
  // this object, feeding back decoded pixel blocks, which we pass to each
 | 
						|
  // of the ImageConsumers in the provided Vector.
 | 
						|
 | 
						|
  public void produce (Vector v, InputStream is) throws IOException
 | 
						|
  {
 | 
						|
    curr = v;
 | 
						|
 | 
						|
    byte bytes[] = new byte[4096];
 | 
						|
    int len = 0;
 | 
						|
    synchronized(pixbufLock)
 | 
						|
      {
 | 
						|
        initState();
 | 
						|
      }
 | 
						|
    needsClose = true;
 | 
						|
 | 
						|
    // Note: We don't want the pixbufLock while reading from the InputStream.
 | 
						|
    while ((len = is.read (bytes)) != -1)
 | 
						|
      {
 | 
						|
        synchronized(pixbufLock)
 | 
						|
          {
 | 
						|
            pumpBytes (bytes, len);
 | 
						|
          }
 | 
						|
      }
 | 
						|
 | 
						|
    synchronized(pixbufLock)
 | 
						|
      {
 | 
						|
        pumpDone();
 | 
						|
      }
 | 
						|
 | 
						|
    needsClose = false;
 | 
						|
 | 
						|
    for (int i = 0; i < curr.size (); i++)
 | 
						|
      {
 | 
						|
        ImageConsumer ic = (ImageConsumer) curr.elementAt (i);
 | 
						|
        ic.imageComplete (ImageConsumer.STATICIMAGEDONE);
 | 
						|
      }
 | 
						|
 | 
						|
    curr = null;
 | 
						|
  }
 | 
						|
 | 
						|
  public void finalize()
 | 
						|
  {
 | 
						|
    synchronized(pixbufLock)
 | 
						|
      {
 | 
						|
        finish(needsClose);
 | 
						|
      }
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  public static class ImageFormatSpec
 | 
						|
  {
 | 
						|
    public String name;
 | 
						|
    public boolean writable = false;
 | 
						|
    public ArrayList<String> mimeTypes = new ArrayList<String>();
 | 
						|
    public ArrayList<String> extensions = new ArrayList<String>();
 | 
						|
 | 
						|
    public ImageFormatSpec(String name, boolean writable)
 | 
						|
    {
 | 
						|
      this.name = name;
 | 
						|
      this.writable = writable;
 | 
						|
    }
 | 
						|
 | 
						|
    public synchronized void addMimeType(String m)
 | 
						|
    {
 | 
						|
      mimeTypes.add(m);
 | 
						|
    }
 | 
						|
 | 
						|
    public synchronized void addExtension(String e)
 | 
						|
    {
 | 
						|
      extensions.add(e);
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  static ArrayList<ImageFormatSpec> imageFormatSpecs;
 | 
						|
 | 
						|
  public static ImageFormatSpec registerFormat(String name, boolean writable)
 | 
						|
  {
 | 
						|
    ImageFormatSpec ifs = new ImageFormatSpec(name, writable);
 | 
						|
    synchronized(GdkPixbufDecoder.class)
 | 
						|
      {
 | 
						|
        if (imageFormatSpecs == null)
 | 
						|
          imageFormatSpecs = new ArrayList<ImageFormatSpec>();
 | 
						|
        imageFormatSpecs.add(ifs);
 | 
						|
      }
 | 
						|
    return ifs;
 | 
						|
  }
 | 
						|
 | 
						|
  static String[] getFormatNames(boolean writable)
 | 
						|
  {
 | 
						|
    ArrayList<String> names = new ArrayList<String>();
 | 
						|
    synchronized (imageFormatSpecs)
 | 
						|
      {
 | 
						|
        Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator();
 | 
						|
        while (i.hasNext())
 | 
						|
          {
 | 
						|
            ImageFormatSpec ifs = i.next();
 | 
						|
            if (writable && !ifs.writable)
 | 
						|
              continue;
 | 
						|
            names.add(ifs.name);
 | 
						|
 | 
						|
            /*
 | 
						|
             * In order to make the filtering code work, we need to register
 | 
						|
             * this type under every "format name" likely to be used as a synonym.
 | 
						|
             * This generally means "all the extensions people might use".
 | 
						|
             */
 | 
						|
 | 
						|
            Iterator<String> j = ifs.extensions.iterator();
 | 
						|
            while (j.hasNext())
 | 
						|
              names.add(j.next());
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return names.toArray(new String[names.size()]);
 | 
						|
  }
 | 
						|
 | 
						|
  static String[] getFormatExtensions(boolean writable)
 | 
						|
  {
 | 
						|
    ArrayList<String> extensions = new ArrayList<String>();
 | 
						|
    synchronized (imageFormatSpecs)
 | 
						|
      {
 | 
						|
        Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator();
 | 
						|
        while (i.hasNext())
 | 
						|
          {
 | 
						|
            ImageFormatSpec ifs = i.next();
 | 
						|
            if (writable && !ifs.writable)
 | 
						|
              continue;
 | 
						|
            Iterator<String> j = ifs.extensions.iterator();
 | 
						|
            while (j.hasNext())
 | 
						|
              extensions.add(j.next());
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return extensions.toArray(new String[extensions.size()]);
 | 
						|
  }
 | 
						|
 | 
						|
  static String[] getFormatMimeTypes(boolean writable)
 | 
						|
  {
 | 
						|
    ArrayList<String> mimeTypes = new ArrayList<String>();
 | 
						|
    synchronized (imageFormatSpecs)
 | 
						|
      {
 | 
						|
        Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator();
 | 
						|
        while (i.hasNext())
 | 
						|
          {
 | 
						|
            ImageFormatSpec ifs = i.next();
 | 
						|
            if (writable && !ifs.writable)
 | 
						|
              continue;
 | 
						|
            Iterator<String> j = ifs.mimeTypes.iterator();
 | 
						|
            while (j.hasNext())
 | 
						|
              mimeTypes.add(j.next());
 | 
						|
          }
 | 
						|
      }
 | 
						|
    return mimeTypes.toArray(new String[mimeTypes.size()]);
 | 
						|
  }
 | 
						|
 | 
						|
 | 
						|
  static String findFormatName(Object ext, boolean needWritable)
 | 
						|
  {
 | 
						|
    if (ext == null)
 | 
						|
      return null;
 | 
						|
 | 
						|
    if (!(ext instanceof String))
 | 
						|
      throw new IllegalArgumentException("extension is not a string");
 | 
						|
 | 
						|
    String str = (String) ext;
 | 
						|
 | 
						|
    Iterator<ImageFormatSpec> i = imageFormatSpecs.iterator();
 | 
						|
    while (i.hasNext())
 | 
						|
      {
 | 
						|
        ImageFormatSpec ifs = i.next();
 | 
						|
 | 
						|
        if (needWritable && !ifs.writable)
 | 
						|
          continue;
 | 
						|
 | 
						|
        if (ifs.name.equals(str))
 | 
						|
          return str;
 | 
						|
 | 
						|
        Iterator<String> j = ifs.extensions.iterator();
 | 
						|
        while (j.hasNext())
 | 
						|
          {
 | 
						|
            String extension = j.next();
 | 
						|
            if (extension.equals(str))
 | 
						|
              return ifs.name;
 | 
						|
          }
 | 
						|
 | 
						|
        j = ifs.mimeTypes.iterator();
 | 
						|
        while (j.hasNext())
 | 
						|
          {
 | 
						|
            String mimeType = j.next();
 | 
						|
            if (mimeType.equals(str))
 | 
						|
              return ifs.name;
 | 
						|
          }
 | 
						|
      }
 | 
						|
    throw new IllegalArgumentException("unknown extension '" + str + "'");
 | 
						|
  }
 | 
						|
 | 
						|
  private static GdkPixbufReaderSpi readerSpi;
 | 
						|
  private static GdkPixbufWriterSpi writerSpi;
 | 
						|
 | 
						|
  public static synchronized GdkPixbufReaderSpi getReaderSpi()
 | 
						|
  {
 | 
						|
    if (readerSpi == null)
 | 
						|
      readerSpi = new GdkPixbufReaderSpi();
 | 
						|
    return readerSpi;
 | 
						|
  }
 | 
						|
 | 
						|
  public static synchronized GdkPixbufWriterSpi getWriterSpi()
 | 
						|
  {
 | 
						|
    if (writerSpi == null)
 | 
						|
      writerSpi = new GdkPixbufWriterSpi();
 | 
						|
    return writerSpi;
 | 
						|
  }
 | 
						|
 | 
						|
  public static void registerSpis(IIORegistry reg)
 | 
						|
  {
 | 
						|
    reg.registerServiceProvider(getReaderSpi(), ImageReaderSpi.class);
 | 
						|
    reg.registerServiceProvider(getWriterSpi(), ImageWriterSpi.class);
 | 
						|
  }
 | 
						|
 | 
						|
  public static class GdkPixbufWriterSpi extends ImageWriterSpi
 | 
						|
  {
 | 
						|
    public GdkPixbufWriterSpi()
 | 
						|
    {
 | 
						|
      super("GdkPixbuf", "2.x",
 | 
						|
            GdkPixbufDecoder.getFormatNames(true),
 | 
						|
            GdkPixbufDecoder.getFormatExtensions(true),
 | 
						|
            GdkPixbufDecoder.getFormatMimeTypes(true),
 | 
						|
            "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriter",
 | 
						|
            new Class[] { ImageOutputStream.class },
 | 
						|
            new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReaderSpi" },
 | 
						|
            false, null, null, null, null,
 | 
						|
            false, null, null, null, null);
 | 
						|
    }
 | 
						|
 | 
						|
    public boolean canEncodeImage(ImageTypeSpecifier ts)
 | 
						|
    {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    public ImageWriter createWriterInstance(Object ext)
 | 
						|
    {
 | 
						|
      return new GdkPixbufWriter(this, ext);
 | 
						|
    }
 | 
						|
 | 
						|
    public String getDescription(java.util.Locale loc)
 | 
						|
    {
 | 
						|
      return "GdkPixbuf Writer SPI";
 | 
						|
    }
 | 
						|
 | 
						|
  }
 | 
						|
 | 
						|
  public static class GdkPixbufReaderSpi extends ImageReaderSpi
 | 
						|
  {
 | 
						|
    public GdkPixbufReaderSpi()
 | 
						|
    {
 | 
						|
      super("GdkPixbuf", "2.x",
 | 
						|
            GdkPixbufDecoder.getFormatNames(false),
 | 
						|
            GdkPixbufDecoder.getFormatExtensions(false),
 | 
						|
            GdkPixbufDecoder.getFormatMimeTypes(false),
 | 
						|
            "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufReader",
 | 
						|
            new Class[] { ImageInputStream.class },
 | 
						|
            new String[] { "gnu.java.awt.peer.gtk.GdkPixbufDecoder$GdkPixbufWriterSpi" },
 | 
						|
            false, null, null, null, null,
 | 
						|
            false, null, null, null, null);
 | 
						|
    }
 | 
						|
 | 
						|
    public boolean canDecodeInput(Object obj)
 | 
						|
    {
 | 
						|
      return true;
 | 
						|
    }
 | 
						|
 | 
						|
    public ImageReader createReaderInstance(Object ext)
 | 
						|
    {
 | 
						|
      return new GdkPixbufReader(this, ext);
 | 
						|
    }
 | 
						|
 | 
						|
    public String getDescription(Locale loc)
 | 
						|
    {
 | 
						|
      return "GdkPixbuf Reader SPI";
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  private static class GdkPixbufWriter
 | 
						|
    extends ImageWriter implements Runnable
 | 
						|
  {
 | 
						|
    String ext;
 | 
						|
    public GdkPixbufWriter(GdkPixbufWriterSpi ownerSpi, Object ext)
 | 
						|
    {
 | 
						|
      super(ownerSpi);
 | 
						|
      this.ext = findFormatName(ext, true);
 | 
						|
    }
 | 
						|
 | 
						|
    public IIOMetadata convertImageMetadata (IIOMetadata inData,
 | 
						|
                                             ImageTypeSpecifier imageType,
 | 
						|
                                             ImageWriteParam param)
 | 
						|
    {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    public IIOMetadata convertStreamMetadata (IIOMetadata inData,
 | 
						|
                                              ImageWriteParam param)
 | 
						|
    {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    public IIOMetadata getDefaultImageMetadata (ImageTypeSpecifier imageType,
 | 
						|
                                                ImageWriteParam param)
 | 
						|
    {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    public IIOMetadata getDefaultStreamMetadata (ImageWriteParam param)
 | 
						|
    {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
  public void write (IIOMetadata streamMetadata, IIOImage i, ImageWriteParam param)
 | 
						|
    throws IOException
 | 
						|
    {
 | 
						|
      RenderedImage image = i.getRenderedImage();
 | 
						|
      Raster ras = image.getData();
 | 
						|
      int width = ras.getWidth();
 | 
						|
      int height = ras.getHeight();
 | 
						|
      ColorModel model = image.getColorModel();
 | 
						|
      int[] pixels = CairoGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras);
 | 
						|
 | 
						|
      if (pixels == null)
 | 
						|
        {
 | 
						|
          BufferedImage img;
 | 
						|
          if(model != null && model.hasAlpha())
 | 
						|
            img = CairoSurface.getBufferedImage(width, height);
 | 
						|
          img = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
 | 
						|
          int[] pix = new int[4];
 | 
						|
          for (int y = 0; y < height; ++y)
 | 
						|
            for (int x = 0; x < width; ++x)
 | 
						|
              img.setRGB(x, y, model.getRGB(ras.getPixel(x, y, pix)));
 | 
						|
          pixels = CairoGraphics2D.findSimpleIntegerArray (img.getColorModel(),
 | 
						|
                                                         img.getRaster());
 | 
						|
          model = img.getColorModel();
 | 
						|
        }
 | 
						|
 | 
						|
      Thread workerThread = new Thread(this, "GdkPixbufWriter");
 | 
						|
      workerThread.start();
 | 
						|
      processImageStarted(1);
 | 
						|
      synchronized(pixbufLock)
 | 
						|
        {
 | 
						|
          streamImage(pixels, this.ext, width, height, model.hasAlpha(),
 | 
						|
                      this);
 | 
						|
        }
 | 
						|
      synchronized(data)
 | 
						|
        {
 | 
						|
          data.add(DATADONE);
 | 
						|
          data.notifyAll();
 | 
						|
        }
 | 
						|
 | 
						|
      while (workerThread.isAlive())
 | 
						|
        {
 | 
						|
          try
 | 
						|
            {
 | 
						|
              workerThread.join();
 | 
						|
            }
 | 
						|
          catch (InterruptedException ioe)
 | 
						|
            {
 | 
						|
              // Ignored.
 | 
						|
            }
 | 
						|
        }
 | 
						|
 | 
						|
      if (exception != null)
 | 
						|
        throw exception;
 | 
						|
 | 
						|
      processImageComplete();
 | 
						|
    }
 | 
						|
 | 
						|
    /**
 | 
						|
     * Object marking end of data from native streamImage code.
 | 
						|
     */
 | 
						|
    private static final Object DATADONE = new Object();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Holds the data gotten from the native streamImage code.
 | 
						|
     * A worker thread will pull data out.
 | 
						|
     * Needs to be synchronized for access.
 | 
						|
     * The special object DATADONE is added when all data has been delivered.
 | 
						|
     */
 | 
						|
    private ArrayList<Object> data = new ArrayList<Object>();
 | 
						|
 | 
						|
    /**
 | 
						|
     * Holds any IOException thrown by the run method that needs
 | 
						|
     * to be rethrown by the write method.
 | 
						|
     */
 | 
						|
    private IOException exception;
 | 
						|
 | 
						|
    /** Callback for streamImage native code. **/
 | 
						|
    private void write(byte[] bs)
 | 
						|
    {
 | 
						|
      synchronized(data)
 | 
						|
        {
 | 
						|
          data.add(bs);
 | 
						|
          data.notifyAll();
 | 
						|
        }
 | 
						|
    }
 | 
						|
 | 
						|
    public void run()
 | 
						|
    {
 | 
						|
      boolean done = false;
 | 
						|
      while (!done)
 | 
						|
        {
 | 
						|
          synchronized(data)
 | 
						|
            {
 | 
						|
              while (data.isEmpty())
 | 
						|
                {
 | 
						|
                  try
 | 
						|
                    {
 | 
						|
                      data.wait();
 | 
						|
                    }
 | 
						|
                  catch (InterruptedException ie)
 | 
						|
                    {
 | 
						|
                      /* ignore */
 | 
						|
                    }
 | 
						|
                }
 | 
						|
 | 
						|
              Object o = data.remove(0);
 | 
						|
              if (o == DATADONE)
 | 
						|
                done = true;
 | 
						|
              else
 | 
						|
                {
 | 
						|
                  DataOutput out = (DataOutput) getOutput();
 | 
						|
                  try
 | 
						|
                    {
 | 
						|
                      out.write((byte[]) o);
 | 
						|
                    }
 | 
						|
                  catch (IOException ioe)
 | 
						|
                    {
 | 
						|
                      // We are only interested in the first exception.
 | 
						|
                      if (exception == null)
 | 
						|
                        exception = ioe;
 | 
						|
                    }
 | 
						|
                }
 | 
						|
            }
 | 
						|
        }
 | 
						|
    }
 | 
						|
  }
 | 
						|
 | 
						|
  private static class GdkPixbufReader
 | 
						|
    extends ImageReader
 | 
						|
    implements ImageConsumer
 | 
						|
  {
 | 
						|
    // ImageConsumer parts
 | 
						|
    GdkPixbufDecoder dec;
 | 
						|
    BufferedImage bufferedImage;
 | 
						|
    ColorModel defaultModel;
 | 
						|
    int width;
 | 
						|
    int height;
 | 
						|
    String ext;
 | 
						|
 | 
						|
    public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext)
 | 
						|
    {
 | 
						|
      super(ownerSpi);
 | 
						|
      this.ext = findFormatName(ext, false);
 | 
						|
    }
 | 
						|
 | 
						|
    public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext,
 | 
						|
                           GdkPixbufDecoder d)
 | 
						|
    {
 | 
						|
      this(ownerSpi, ext);
 | 
						|
      dec = d;
 | 
						|
    }
 | 
						|
 | 
						|
    public void setDimensions(int w, int h)
 | 
						|
    {
 | 
						|
      processImageStarted(1);
 | 
						|
      width = w;
 | 
						|
      height = h;
 | 
						|
    }
 | 
						|
 | 
						|
    public void setProperties(Hashtable props) {}
 | 
						|
 | 
						|
    public void setColorModel(ColorModel model)
 | 
						|
    {
 | 
						|
      defaultModel = model;
 | 
						|
    }
 | 
						|
 | 
						|
    public void setHints(int flags) {}
 | 
						|
 | 
						|
    public void setPixels(int x, int y, int w, int h,
 | 
						|
                          ColorModel model, byte[] pixels,
 | 
						|
                          int offset, int scansize)
 | 
						|
    {
 | 
						|
    }
 | 
						|
 | 
						|
    public void setPixels(int x, int y, int w, int h,
 | 
						|
                          ColorModel model, int[] pixels,
 | 
						|
                          int offset, int scansize)
 | 
						|
    {
 | 
						|
      if (model == null)
 | 
						|
        model = defaultModel;
 | 
						|
 | 
						|
      if (bufferedImage == null)
 | 
						|
        {
 | 
						|
          if(model != null && model.hasAlpha())
 | 
						|
            bufferedImage = new BufferedImage (width, height,
 | 
						|
                                               BufferedImage.TYPE_INT_ARGB);
 | 
						|
          else
 | 
						|
            bufferedImage = new BufferedImage (width, height,
 | 
						|
                                               BufferedImage.TYPE_INT_RGB);
 | 
						|
        }
 | 
						|
 | 
						|
      int pixels2[];
 | 
						|
      if (model != null)
 | 
						|
        {
 | 
						|
          pixels2 = new int[pixels.length];
 | 
						|
          for (int yy = 0; yy < h; yy++)
 | 
						|
            for (int xx = 0; xx < w; xx++)
 | 
						|
              {
 | 
						|
                int i = yy * scansize + xx;
 | 
						|
                pixels2[i] = model.getRGB (pixels[i]);
 | 
						|
              }
 | 
						|
        }
 | 
						|
      else
 | 
						|
        pixels2 = pixels;
 | 
						|
 | 
						|
      bufferedImage.setRGB (x, y, w, h, pixels2, offset, scansize);
 | 
						|
      processImageProgress(y / (height == 0 ? 1 : height));
 | 
						|
    }
 | 
						|
 | 
						|
    public void imageComplete(int status)
 | 
						|
    {
 | 
						|
      processImageComplete();
 | 
						|
    }
 | 
						|
 | 
						|
    public BufferedImage getBufferedImage()
 | 
						|
    {
 | 
						|
      if (bufferedImage == null && dec != null)
 | 
						|
        dec.startProduction (this);
 | 
						|
      return bufferedImage;
 | 
						|
    }
 | 
						|
 | 
						|
    // ImageReader parts
 | 
						|
 | 
						|
    public int getNumImages(boolean allowSearch)
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      return 1;
 | 
						|
    }
 | 
						|
 | 
						|
    public IIOMetadata getImageMetadata(int i)
 | 
						|
    {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    public IIOMetadata getStreamMetadata()
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      return null;
 | 
						|
    }
 | 
						|
 | 
						|
    public Iterator<ImageTypeSpecifier> getImageTypes(int imageIndex)
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      BufferedImage img = getBufferedImage();
 | 
						|
      Vector<ImageTypeSpecifier> vec = new Vector<ImageTypeSpecifier>();
 | 
						|
      vec.add(new ImageTypeSpecifier(img));
 | 
						|
      return vec.iterator();
 | 
						|
    }
 | 
						|
 | 
						|
    public int getHeight(int imageIndex)
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      return getBufferedImage().getHeight();
 | 
						|
    }
 | 
						|
 | 
						|
    public int getWidth(int imageIndex)
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      return getBufferedImage().getWidth();
 | 
						|
    }
 | 
						|
 | 
						|
    public void setInput(Object input,
 | 
						|
                         boolean seekForwardOnly,
 | 
						|
                         boolean ignoreMetadata)
 | 
						|
    {
 | 
						|
      super.setInput(input, seekForwardOnly, ignoreMetadata);
 | 
						|
      Object get = getInput();
 | 
						|
      if (get instanceof InputStream)
 | 
						|
        dec = new GdkPixbufDecoder((InputStream) get);
 | 
						|
      else if (get instanceof DataInput)
 | 
						|
        dec = new GdkPixbufDecoder((DataInput) get);
 | 
						|
      else
 | 
						|
        throw new IllegalArgumentException("input object not supported: "
 | 
						|
                                           + get);
 | 
						|
    }
 | 
						|
 | 
						|
    public BufferedImage read(int imageIndex, ImageReadParam param)
 | 
						|
      throws IOException
 | 
						|
    {
 | 
						|
      return getBufferedImage ();
 | 
						|
    }
 | 
						|
  }
 | 
						|
}
 |