2 Copyright (C) 2005, 2006 Free Software Foundation, Inc.
4 This file is part of GNU Classpath.
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)
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.
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
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
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. */
39 package gnu.java.awt.peer.gtk;
41 import java.awt.Graphics;
42 import java.awt.Image;
43 import java.awt.image.ColorModel;
44 import java.awt.image.DirectColorModel;
45 import java.awt.image.MemoryImageSource;
46 import java.awt.image.ImageObserver;
47 import java.awt.image.ImageProducer;
49 import java.io.IOException;
50 import java.util.Hashtable;
51 import java.util.Vector;
52 import java.io.ByteArrayOutputStream;
53 import java.io.BufferedInputStream;
55 import gnu.classpath.Pointer;
58 * GtkImage - wraps a GdkPixbuf.
60 * A GdkPixbuf is 'on-screen' and the gdk cannot draw to it,
61 * this is used for the other constructors (and other createImage methods), and
62 * corresponds to the Image implementations returned by the Toolkit.createImage
63 * methods, and is basically immutable.
65 * @author Sven de Marothy
67 public class GtkImage extends Image
69 int width = -1, height = -1;
77 * Loaded or not flag, for asynchronous compatibility.
82 * Pointer to the GdkPixbuf -
83 * don't change the name without changing the native code.
90 Vector<ImageObserver> observers;
93 * Error flag for loading.
98 * Original source, if created from an ImageProducer.
100 ImageProducer source;
103 * The 32-bit AABBGGRR format the GDK uses.
105 static ColorModel nativeModel = new DirectColorModel(32,
112 * The singleton GtkImage that is returned on errors by GtkToolkit.
114 private static GtkImage errorImage;
117 * Lock that should be held for all gdkpixbuf operations. We don't use
118 * the global gdk_threads_enter/leave functions in most places since
119 * most gdkpixbuf operations can be done in parallel to drawing and
120 * manipulating gtk widgets.
122 static Object pixbufLock = new Object();
125 * Allocate a PixBuf from a given ARGB32 buffer pointer.
127 private native void initFromBuffer( long bufferPointer );
130 * Returns a copy of the pixel data as a java array.
131 * Should be called with the pixbufLock held.
133 native int[] getPixels();
136 * Sets the pixel data from a java array.
137 * Should be called with the pixbufLock held.
139 private native void setPixels(int[] pixels);
142 * Loads an image using gdk-pixbuf from a file.
143 * Should be called with the pixbufLock held.
145 private native boolean loadPixbuf(String name);
148 * Loads an image using gdk-pixbuf from data.
149 * Should be called with the pixbufLock held.
151 private native boolean loadImageFromData(byte[] data);
154 * Allocates a Gtk Pixbuf
155 * Should be called with the pixbufLock held.
157 private native void createPixbuf();
161 * Should be called with the pixbufLock held.
163 private native void freePixbuf();
166 * Sets the pixbuf to scaled copy of src image. hints are rendering hints.
167 * Should be called with the pixbufLock held.
169 private native void createScaledPixbuf(GtkImage src, int hints);
172 * Constructs a GtkImage from an ImageProducer. Asynchronity is handled in
173 * the following manner:
174 * A GtkImageConsumer gets the image data, and calls setImage() when
175 * completely finished. The GtkImage is not considered loaded until the
176 * GtkImageConsumer is completely finished. We go for all "all or nothing".
178 public GtkImage (ImageProducer producer)
181 observers = new Vector<ImageObserver>();
183 errorLoading = false;
184 source.startProduction(new GtkImageConsumer(this, source));
188 * Constructs a blank GtkImage. This is called when
189 * GtkToolkit.createImage (String) is called with an empty string
190 * argument (""). A blank image is loaded immediately upon
191 * construction and has width -1 and height -1.
197 props = new Hashtable<String,Object>();
198 errorLoading = false;
202 * Constructs a GtkImage by loading a given file.
204 * @throws IllegalArgumentException if the image could not be loaded.
206 public GtkImage (String filename)
208 File f = new File(filename);
211 String path = f.getCanonicalPath();
212 synchronized(pixbufLock)
214 if (loadPixbuf(f.getCanonicalPath()) != true)
215 throw new IllegalArgumentException("Couldn't load image: "
221 IllegalArgumentException iae;
222 iae = new IllegalArgumentException("Couldn't load image: "
230 props = new Hashtable<String,Object>();
234 * Constructs a GtkImage from a byte array of an image file.
236 * @throws IllegalArgumentException if the image could not be
239 public GtkImage (byte[] data)
241 synchronized(pixbufLock)
243 if (loadImageFromData (data) != true)
244 throw new IllegalArgumentException ("Couldn't load image.");
249 props = new Hashtable<String,Object>();
250 errorLoading = false;
254 * Constructs a GtkImage from a URL. May result in an error image.
256 public GtkImage (URL url)
259 observers = new Vector<ImageObserver>();
260 errorLoading = false;
263 ByteArrayOutputStream baos = new ByteArrayOutputStream (5000);
266 BufferedInputStream bis = new BufferedInputStream (url.openStream());
268 byte[] buf = new byte[5000];
271 while ((n = bis.read(buf)) != -1)
272 baos.write(buf, 0, n);
277 throw new IllegalArgumentException ("Couldn't load image.");
279 byte[] array = baos.toByteArray();
280 synchronized(pixbufLock)
282 if (loadImageFromData(array) != true)
283 throw new IllegalArgumentException ("Couldn't load image.");
288 props = new Hashtable<String,Object>();
292 * Constructs a scaled version of the src bitmap, using the GDK.
294 private GtkImage (GtkImage src, int width, int height, int hints)
297 this.height = height;
298 props = new Hashtable<String,Object>();
302 // Use the GDK scaling method.
303 synchronized(pixbufLock)
305 createScaledPixbuf(src, hints);
310 * Package private constructor to create a GtkImage from a given
313 GtkImage (Pointer pixbuf)
315 this.pixbuf = pixbuf;
316 synchronized(pixbufLock)
322 props = new Hashtable<String,Object>();
326 * Wraps a buffer with a GtkImage.
328 * @param bufferPointer a pointer to an ARGB32 buffer
330 GtkImage(int width, int height, long bufferPointer)
333 this.height = height;
334 props = new Hashtable<String,Object>();
337 initFromBuffer( bufferPointer );
341 * Returns an empty GtkImage with the errorLoading flag set.
342 * Called from GtkToolKit when some error occured, but an image needs
343 * to be returned anyway.
345 static synchronized GtkImage getErrorImage()
347 if (errorImage == null)
349 errorImage = new GtkImage();
350 errorImage.errorLoading = true;
356 * Native helper function for constructor that takes a pixbuf Pointer.
357 * Should be called with the pixbufLock held.
359 private native void createFromPixbuf();
362 * Callback from the image consumer.
364 public void setImage(int width, int height,
365 int[] pixels, Hashtable<?,?> properties)
368 this.height = height;
369 props = (properties != null) ? properties : new Hashtable<String,Object>();
371 if (width <= 0 || height <= 0 || pixels == null)
377 synchronized(pixbufLock)
386 // java.awt.Image methods ////////////////////////////////////////////////
388 public synchronized int getWidth (ImageObserver observer)
390 if (addObserver(observer))
396 public synchronized int getHeight (ImageObserver observer)
398 if (addObserver(observer))
404 public synchronized Object getProperty (String name, ImageObserver observer)
406 if (addObserver(observer))
407 return UndefinedProperty;
409 Object value = props.get (name);
410 return (value == null) ? UndefinedProperty : value;
414 * Returns the source of this image.
416 public ImageProducer getSource ()
422 synchronized (pixbufLock)
425 pixels = getPixels();
429 return new MemoryImageSource(width, height, nativeModel, pixels,
434 * Does nothing. Should not be called.
436 public Graphics getGraphics ()
438 throw new IllegalAccessError("This method only works for off-screen"
443 * Returns a scaled instance of this pixbuf.
445 public Image getScaledInstance(int width,
449 if (width <= 0 || height <= 0)
450 throw new IllegalArgumentException("Width and height of scaled bitmap"
453 return new GtkImage(this, width, height, hints);
457 * If the image is loaded and comes from an ImageProducer,
458 * regenerate the image from there.
460 * I have no idea if this is ever actually used. Since GtkImage can't be
461 * instantiated directly, how is the user to know if it was created from
462 * an ImageProducer or not?
464 public synchronized void flush ()
466 if (isLoaded && source != null)
468 observers = new Vector<ImageObserver>();
470 synchronized(pixbufLock)
474 source.startProduction(new GtkImageConsumer(this, source));
478 public void finalize()
482 synchronized(pixbufLock)
490 * Returns the image status, used by GtkToolkit
492 public int checkImage (ImageObserver observer)
494 if (addObserver(observer))
496 if (errorLoading == true)
497 return ImageObserver.ERROR;
502 return ImageObserver.ALLBITS | ImageObserver.WIDTH | ImageObserver.HEIGHT;
506 // Private methods ////////////////////////////////////////////////
509 * Delivers notifications to all queued observers.
511 private void deliver()
513 int flags = ImageObserver.HEIGHT |
514 ImageObserver.WIDTH |
515 ImageObserver.PROPERTIES |
516 ImageObserver.ALLBITS;
518 if (observers != null)
519 for(int i=0; i < observers.size(); i++)
520 ((ImageObserver)observers.elementAt(i)).imageUpdate(this, flags, 0, 0,
527 * Adds an observer, if we need to.
528 * @return true if an observer was added.
530 private boolean addObserver(ImageObserver observer)
535 if (!observers.contains (observer))
536 observers.addElement (observer);