diff options
author | Michael Koch <konqueror@gmx.de> | 2005-01-11 22:07:32 +0000 |
---|---|---|
committer | Michael Koch <konqueror@gmx.de> | 2005-01-11 22:07:32 +0000 |
commit | d57944ad419a596a8346836a5fa85c4524b3b266 (patch) | |
tree | a033392f353aa8121fefeb6491eb188cff36956b /gnu | |
parent | 77acbbe0e2e6eca679d97f1523840e80dd381b16 (diff) | |
download | classpath-d57944ad419a596a8346836a5fa85c4524b3b266.tar.gz |
2005-01-11 Graydon Hoare <graydon@redhat.com>
* gnu/java/awt/ClasspathToolkit.java
(registerImageIOSpis): New method.
* gnu/java/awt/image/ImageDecoder.java
(imageDecoder): New constructor using InputStream
(startProduction): Handle existing InputStream.
* gnu/java/awt/peer/gtk/GdkGraphics2D.java
(findSimpleIntegerArray): Make public and static.
(updateBufferedImage): Set each pixel, in a loop.
* gnu/java/awt/peer/gtk/GdkPixbufDecoder.java:
Implement ImageIO SPI classes.
(createBufferedImage): Rewrite in terms of SPI classes.
* gnu/java/awt/peer/gtk/GtkToolkit.java
(registerImageIOSpis): New method.
* java/lang/reflect/natMethod.cc
(_Jv_CallAnyMethodA): Borrow a patch from aph, applied to trunk,
which lets JNI call interface methods properly.
* javax/imageio/ImageIO.java
(WriterFormatFilter.filter): Fix copy-and-paste typos.
(WriterMIMETypeFilter.filter): Likewise.
(ImageReaderIterator): Pass extension argument through to SPI.
(getReadersByFilter): Likewise.
(getWritersByFilter): Likewise.
(getImageReadersByFormatName): Likewise.
(getImageReadersByMIMEType): Likewise.
(getImageReadersBySuffix): Likewise.
(getImageWritersByFormatName): Likewise.
(getImageWritersByMIMEType): Likewise.
(getImageWritersBySuffix): Likewise.
(read): Implement.
(write): Implement.
* javax/imageio/ImageReader.java
(progressListeners): Initialize.
(setInput): Implement.
* javax/imageio/ImageWriter.java
(progressListeners): Initialize.
(warningListeners): Likewise.
(warningLocales): Likewise.
(setOutput): Test "isInstance" rather than class equality.
* javax/imageio/spi/IIORegistry.java
(static): Add reader and writer SPIs.
(IIORegistry): Call ClasspathToolkit.registerImageIOSpis.
* jni/gtk-peer/gnu_java_awt_peer_gtk_GdkPixbufDecoder.c
(query_formats): New function.
(save_to_stream): Likewise.
(Java_gnu_java_awt_peer_gtk_GdkPixbufDecoder_streamImage): Likewise.
2005-01-11 Michael Koch <konqueror@gmx.de>
* include/gnu_java_awt_peer_gtk_GdkPixbufDecoder.h: Regenerated.
Diffstat (limited to 'gnu')
-rw-r--r-- | gnu/java/awt/ClasspathToolkit.java | 9 | ||||
-rw-r--r-- | gnu/java/awt/image/ImageDecoder.java | 40 | ||||
-rw-r--r-- | gnu/java/awt/peer/gtk/GdkGraphics2D.java | 11 | ||||
-rw-r--r-- | gnu/java/awt/peer/gtk/GdkPixbufDecoder.java | 476 | ||||
-rw-r--r-- | gnu/java/awt/peer/gtk/GtkToolkit.java | 5 |
5 files changed, 496 insertions, 45 deletions
diff --git a/gnu/java/awt/ClasspathToolkit.java b/gnu/java/awt/ClasspathToolkit.java index 1ae54742b..b26a640c2 100644 --- a/gnu/java/awt/ClasspathToolkit.java +++ b/gnu/java/awt/ClasspathToolkit.java @@ -62,6 +62,7 @@ import java.text.AttributedString; import java.util.HashMap; import java.util.Map; import java.awt.peer.RobotPeer; +import javax.imageio.spi.IIORegistry; /** @@ -356,6 +357,14 @@ public abstract class ClasspathToolkit public abstract RobotPeer createRobot (GraphicsDevice screen) throws AWTException; + /** + * Used to register ImageIO SPIs provided by the toolkit. + */ + + public void registerImageIOSpis(IIORegistry reg) + { + } + public abstract boolean nativeQueueEmpty(); public abstract void wakeNativeQueue(); public abstract void iterateNativeQueue(EventQueue locked); diff --git a/gnu/java/awt/image/ImageDecoder.java b/gnu/java/awt/image/ImageDecoder.java index b2e5e96f8..d279d5674 100644 --- a/gnu/java/awt/image/ImageDecoder.java +++ b/gnu/java/awt/image/ImageDecoder.java @@ -74,6 +74,11 @@ public abstract class ImageDecoder implements ImageProducer this.url = url; } + public ImageDecoder (InputStream is) + { + this.input = is; + } + public ImageDecoder (byte[] imagedata, int imageoffset, int imagelength) { data = imagedata; @@ -108,17 +113,30 @@ public abstract class ImageDecoder implements ImageProducer // ImageDecoder constructors so that exceptions cause // imageComplete to be called with an appropriate error // status. - if (url != null) - input = url.openStream(); - else - { - if (filename != null) - input = new FileInputStream (filename); - else - input = new ByteArrayInputStream (data, offset, length); - } - - produce (list, input); + if (input == null) + { + try + { + if (url != null) + input = url.openStream(); + else + { + if (filename != null) + input = new FileInputStream (filename); + else + input = new ByteArrayInputStream (data, offset, length); + } + produce (list, input); + } + finally + { + input = null; + } + } + else + { + produce (list, input); + } } catch (Exception e) { diff --git a/gnu/java/awt/peer/gtk/GdkGraphics2D.java b/gnu/java/awt/peer/gtk/GdkGraphics2D.java index d05a3dfa3..0f0fe9095 100644 --- a/gnu/java/awt/peer/gtk/GdkGraphics2D.java +++ b/gnu/java/awt/peer/gtk/GdkGraphics2D.java @@ -451,7 +451,7 @@ public class GdkGraphics2D extends Graphics2D return defaultHints; } - private final int[] findSimpleIntegerArray(ColorModel cm, Raster raster) + public static final int[] findSimpleIntegerArray (ColorModel cm, Raster raster) { if (cm == null || raster == null) return null; @@ -494,10 +494,11 @@ public class GdkGraphics2D extends Graphics2D { if (bimage != null && pixelConversionRequired) { - bimage.getRaster().setPixels(0, 0, - bimage.getRaster().getWidth (), - bimage.getRaster().getHeight (), - pixelBuffer); + int height = bimage.getHeight(); + int width = bimage.getWidth(); + for (int y = 0; y < height; ++y) + for (int x = 0; x < width; ++x) + bimage.setRGB(x, y, pixelBuffer[y*width+height]); } } diff --git a/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java b/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java index c70c62db1..4bd9e9a43 100644 --- a/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java +++ b/gnu/java/awt/peer/gtk/GdkPixbufDecoder.java @@ -42,17 +42,38 @@ import gnu.classpath.Configuration; import java.awt.image.BufferedImage; import java.awt.image.ColorModel; +import java.awt.image.DataBufferInt; import java.awt.image.DirectColorModel; import java.awt.image.ImageConsumer; import java.awt.image.ImageProducer; +import java.awt.image.Raster; +import java.awt.image.RenderedImage; +import java.awt.image.WritableRaster; +import java.io.DataOutput; import java.io.FileDescriptor; import java.io.FileInputStream; 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.ImageReader; +import javax.imageio.ImageWriter; +import javax.imageio.ImageReadParam; +import javax.imageio.ImageTypeSpecifier; +import javax.imageio.ImageWriteParam; +import javax.imageio.IIOImage; +import javax.imageio.metadata.IIOMetadata; +import javax.imageio.spi.ImageReaderSpi; +import javax.imageio.spi.ImageWriterSpi; +import javax.imageio.spi.IIORegistry; +import javax.imageio.stream.ImageInputStream; +import javax.imageio.stream.ImageOutputStream; + public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder { static @@ -65,20 +86,27 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder } native static void initStaticState (); private final int native_state = GtkGenericPeer.getUniqueInteger (); + private boolean initialized = false; // the current set of ImageConsumers for this decoder Vector curr; // interface to GdkPixbuf native void initState (); - native void pumpBytes (byte bytes[], int len); + native void pumpBytes (byte[] bytes, int len); native void finish (); + static native void streamImage(int[] bytes, String format, int width, int height, boolean hasAlpha, DataOutput sink); // gdk-pixbuf provids data in RGBA format static final ColorModel cm = new DirectColorModel (32, 0xff000000, 0x00ff0000, 0x0000ff00, 0x000000ff); + public GdkPixbufDecoder (InputStream in) + { + super (in); + } + public GdkPixbufDecoder (String filename) { super (filename); @@ -148,27 +176,345 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder } curr = null; + finish(); } - // remaining helper class and static method is a convenience for the Gtk - // peers, for loading a BufferedImage in off a disk file. one would think - // this ought to be fairly straightforward, but it does not appear - // anywhere else I can find. - private static class BufferedImageBuilder implements ImageConsumer + public static class ImageFormatSpec + { + public String name; + public boolean writable = false; + public ArrayList mimeTypes = new ArrayList(); + public ArrayList extensions = new ArrayList(); + + 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 imageFormatSpecs; + + public static ImageFormatSpec registerFormat(String name, boolean writable) + { + ImageFormatSpec ifs = new ImageFormatSpec(name, writable); + synchronized(GdkPixbufDecoder.class) + { + if (imageFormatSpecs == null) + imageFormatSpecs = new ArrayList(); + imageFormatSpecs.add(ifs); + } + return ifs; + } + + static String[] getFormatNames(boolean writable) + { + ArrayList names = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = (ImageFormatSpec) 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 j = ifs.extensions.iterator(); + while (j.hasNext()) + names.add((String) j.next()); + } + } + Object[] objs = names.toArray(); + String[] strings = new String[objs.length]; + for (int i = 0; i < objs.length; ++i) + strings[i] = (String) objs[i]; + return strings; + } + + static String[] getFormatExtensions(boolean writable) + { + ArrayList extensions = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = (ImageFormatSpec) i.next(); + if (writable && !ifs.writable) + continue; + Iterator j = ifs.extensions.iterator(); + while (j.hasNext()) + extensions.add((String) j.next()); + } + } + Object[] objs = extensions.toArray(); + String[] strings = new String[objs.length]; + for (int i = 0; i < objs.length; ++i) + strings[i] = (String) objs[i]; + return strings; + } + + static String[] getFormatMimeTypes(boolean writable) + { + ArrayList mimeTypes = new ArrayList(); + synchronized (imageFormatSpecs) + { + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = (ImageFormatSpec) i.next(); + if (writable && !ifs.writable) + continue; + Iterator j = ifs.mimeTypes.iterator(); + while (j.hasNext()) + mimeTypes.add((String) j.next()); + } + } + Object[] objs = mimeTypes.toArray(); + String[] strings = new String[objs.length]; + for (int i = 0; i < objs.length; ++i) + strings[i] = (String) objs[i]; + return strings; + } + + + static String findFormatName(Object ext, boolean needWritable) + { + if (ext == null) + throw new IllegalArgumentException("extension is null"); + + if (!(ext instanceof String)) + throw new IllegalArgumentException("extension is not a string"); + + String str = (String) ext; + + Iterator i = imageFormatSpecs.iterator(); + while (i.hasNext()) + { + ImageFormatSpec ifs = (ImageFormatSpec) i.next(); + + if (needWritable && !ifs.writable) + continue; + + if (ifs.name.equals(str)) + return str; + + Iterator j = ifs.extensions.iterator(); + while (j.hasNext()) + { + String extension = (String)j.next(); + if (extension.equals(str)) + return ifs.name; + } + + j = ifs.mimeTypes.iterator(); + while (j.hasNext()) + { + String mimeType = (String)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 { + 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 = GdkGraphics2D.findSimpleIntegerArray (image.getColorModel(), ras); + + if (pixels == null) + { + BufferedImage img = new BufferedImage(width, height, + (model != null && model.hasAlpha() ? + BufferedImage.TYPE_INT_ARGB + : 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 = GdkGraphics2D.findSimpleIntegerArray (img.getColorModel(), + img.getRaster()); + model = img.getColorModel(); + } + + processImageStarted(1); + streamImage(pixels, this.ext, width, height, model.hasAlpha(), + (DataOutput) this.getOutput()); + processImageComplete(); + } + } + + 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 BufferedImage getBufferedImage() + public GdkPixbufReader(GdkPixbufReaderSpi ownerSpi, Object ext, GdkPixbufDecoder d) { - return bufferedImage; + this(ownerSpi, ext); + dec = d; } public void setDimensions(int w, int h) { + processImageStarted(1); width = w; height = h; } @@ -196,9 +542,12 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder model = defaultModel; if (bufferedImage == null) - bufferedImage = new BufferedImage (width, height, (model != null && model.hasAlpha() ? - BufferedImage.TYPE_INT_ARGB - : BufferedImage.TYPE_INT_RGB)); + { + bufferedImage = new BufferedImage (width, height, (model != null && model.hasAlpha() ? + BufferedImage.TYPE_INT_ARGB + : BufferedImage.TYPE_INT_RGB)); + } + int pixels2[]; if (model != null) { @@ -214,43 +563,112 @@ public class GdkPixbufDecoder extends gnu.java.awt.image.ImageDecoder 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 void imageComplete(int status) {} + public Iterator getImageTypes(int imageIndex) + throws IOException + { + BufferedImage img = getBufferedImage(); + Vector vec = new Vector(); + 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); + dec = new GdkPixbufDecoder((InputStream) getInput()); + } + + public BufferedImage read(int imageIndex, ImageReadParam param) + throws IOException + { + return getBufferedImage (); + } } + // remaining helper class and static method is a convenience for the Gtk + // peers, for loading a BufferedImage in off a disk file without going + // through the whole imageio system. + public static BufferedImage createBufferedImage (String filename) { - BufferedImageBuilder bb = new BufferedImageBuilder (); - GdkPixbufDecoder dec = new GdkPixbufDecoder (filename); - dec.startProduction (bb); - return bb.getBufferedImage (); + GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), + "png", // reader auto-detects, doesn't matter + new GdkPixbufDecoder (filename)); + return r.getBufferedImage (); } public static BufferedImage createBufferedImage (URL u) { - BufferedImageBuilder bb = new BufferedImageBuilder (); - GdkPixbufDecoder dec = new GdkPixbufDecoder (u); - dec.startProduction (bb); - return bb.getBufferedImage (); + GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), + "png", // reader auto-detects, doesn't matter + new GdkPixbufDecoder (u)); + return r.getBufferedImage (); } public static BufferedImage createBufferedImage (byte[] imagedata, int imageoffset, int imagelength) { - BufferedImageBuilder bb = new BufferedImageBuilder (); - GdkPixbufDecoder dec = new GdkPixbufDecoder (imagedata, imageoffset, imagelength); - dec.startProduction (bb); - return bb.getBufferedImage (); + GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), + "png", // reader auto-detects, doesn't matter + new GdkPixbufDecoder (imagedata, + imageoffset, + imagelength)); + return r.getBufferedImage (); } public static BufferedImage createBufferedImage (ImageProducer producer) { - BufferedImageBuilder bb = new BufferedImageBuilder (); - producer.startProduction(bb); - return bb.getBufferedImage (); + GdkPixbufReader r = new GdkPixbufReader (getReaderSpi(), "png" /* ignored */, null); + producer.startProduction(r); + return r.getBufferedImage (); } - - } diff --git a/gnu/java/awt/peer/gtk/GtkToolkit.java b/gnu/java/awt/peer/gtk/GtkToolkit.java index c7df27ef7..55496496e 100644 --- a/gnu/java/awt/peer/gtk/GtkToolkit.java +++ b/gnu/java/awt/peer/gtk/GtkToolkit.java @@ -649,6 +649,11 @@ public class GtkToolkit extends gnu.java.awt.ClasspathToolkit return new GdkRobotPeer (screen); } + public void registerImageIOSpis(IIORegistry reg) + { + GdkPixbufDecoder.registerSpis(reg); + } + public native boolean nativeQueueEmpty(); public native void wakeNativeQueue(); public native void iterateNativeQueue(EventQueue locked); |