2 Copyright (C) 2005 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
.Color
;
43 import java
.awt
.Image
;
44 import java
.awt
.image
.ColorModel
;
45 import java
.awt
.image
.DirectColorModel
;
46 import java
.awt
.image
.MemoryImageSource
;
47 import java
.awt
.image
.ImageConsumer
;
48 import java
.awt
.image
.ImageObserver
;
49 import java
.awt
.image
.ImageProducer
;
51 import java
.io
.IOException
;
52 import java
.util
.Hashtable
;
53 import java
.util
.Vector
;
54 import java
.io
.ByteArrayOutputStream
;
55 import java
.io
.BufferedInputStream
;
57 import gnu
.classpath
.Pointer
;
60 * GtkImage - wraps a GdkPixbuf or GdkPixmap.
62 * The constructor GtkImage(int, int) creates an 'off-screen' GdkPixmap,
63 * this can be drawn to (it's a GdkDrawable), and correspondingly, you can
64 * create a GdkGraphics object for it.
66 * This corresponds to the Image implementation returned by
67 * Component.createImage(int, int).
69 * A GdkPixbuf is 'on-screen' and the gdk cannot draw to it,
70 * this is used for the other constructors (and other createImage methods), and
71 * corresponds to the Image implementations returned by the Toolkit.createImage
72 * methods, and is basically immutable.
74 * @author Sven de Marothy
76 public class GtkImage
extends Image
78 int width
= -1, height
= -1;
86 * Loaded or not flag, for asynchronous compatibility.
91 * Pointer to the GdkPixbuf
101 * If offScreen is set, a GdkBitmap is wrapped and not a Pixbuf.
106 * Error flag for loading.
108 boolean errorLoading
;
111 * Original source, if created from an ImageProducer.
113 ImageProducer source
;
116 * The 32-bit AABBGGRR format the GDK uses.
118 static ColorModel nativeModel
= new DirectColorModel(32,
125 * Returns a copy of the pixel data as a java array.
127 private native int[] getPixels();
130 * Sets the pixel data from a java array.
132 private native void setPixels(int[] pixels
);
135 * Loads an image using gdk-pixbuf from a file.
137 private native boolean loadPixbuf(String name
);
140 * Loads an image using gdk-pixbuf from data.
142 private native boolean loadImageFromData(byte[] data
);
145 * Allocates a Gtk Pixbuf or pixmap
147 private native void createPixmap();
152 private native void freePixmap();
155 * Sets the pixmap to scaled copy of src image. hints are rendering hints.
157 private native void createScaledPixmap(GtkImage src
, int hints
);
160 * Draws the image, optionally scaled and composited.
162 private native void drawPixelsScaled (GdkGraphics gc
,
163 int bg_red
, int bg_green
, int bg_blue
,
164 int x
, int y
, int width
, int height
,
168 * Draws the image, optionally scaled flipped and composited.
170 private native void drawPixelsScaledFlipped (GdkGraphics gc
,
171 int bg_red
, int bg_green
,
173 boolean flipX
, boolean flipY
,
175 int srcWidth
, int srcHeight
,
177 int dstWidth
, int dstHeight
,
181 * Constructs a GtkImage from an ImageProducer. Asynchronity is handled in
182 * the following manner:
183 * A GtkImageConsumer gets the image data, and calls setImage() when
184 * completely finished. The GtkImage is not considered loaded until the
185 * GtkImageConsumer is completely finished. We go for all "all or nothing".
187 public GtkImage (ImageProducer producer
)
190 observers
= new Vector();
192 errorLoading
= false;
193 source
.startProduction(new GtkImageConsumer(this, source
));
198 * Constructs a blank GtkImage. This is called when
199 * GtkToolkit.createImage (String) is called with an empty string
200 * argument (""). A blank image is loaded immediately upon
201 * construction and has width -1 and height -1.
208 props
= new Hashtable();
209 errorLoading
= false;
213 * Constructs a GtkImage by loading a given file.
215 * @throws IllegalArgumentException if the image could not be loaded.
217 public GtkImage (String filename
)
219 File f
= new File(filename
);
222 if (loadPixbuf(f
.getCanonicalPath()) != true)
223 throw new IllegalArgumentException("Couldn't load image: "+filename
);
227 throw new IllegalArgumentException("Couldn't load image: "+filename
);
233 props
= new Hashtable();
237 * Constructs a GtkImage from a byte array of an image file.
239 * @throws IllegalArgumentException if the image could not be
242 public GtkImage (byte[] data
)
244 if (loadImageFromData (data
) != true)
245 throw new IllegalArgumentException ("Couldn't load image.");
250 props
= new Hashtable();
251 errorLoading
= false;
255 * Constructs a GtkImage from a URL. May result in an error image.
257 public GtkImage (URL url
)
260 observers
= new Vector();
261 errorLoading
= false;
264 ByteArrayOutputStream baos
= new ByteArrayOutputStream (5000);
267 BufferedInputStream bis
= new BufferedInputStream (url
.openStream());
269 byte[] buf
= new byte[5000];
272 while ((n
= bis
.read(buf
)) != -1)
273 baos
.write(buf
, 0, n
);
278 throw new IllegalArgumentException ("Couldn't load image.");
280 if (loadImageFromData (baos
.toByteArray()) != true)
281 throw new IllegalArgumentException ("Couldn't load image.");
285 props
= new Hashtable();
289 * Constructs an empty GtkImage.
291 public GtkImage (int width
, int height
)
294 this.height
= height
;
295 props
= new Hashtable();
303 * Constructs a scaled version of the src bitmap, using the GDK.
305 private GtkImage (GtkImage src
, int width
, int height
, int hints
)
308 this.height
= height
;
309 props
= new Hashtable();
314 // Use the GDK scaling method.
315 createScaledPixmap(src
, hints
);
319 * Package private constructor to create a GtkImage from a given
322 GtkImage (Pointer pixbuf
)
329 props
= new Hashtable();
333 * Native helper function for constructor that takes a pixbuf Pointer.
335 private native void createFromPixbuf();
338 * Callback from the image consumer.
340 public void setImage(int width
, int height
,
341 int[] pixels
, Hashtable properties
)
344 this.height
= height
;
345 props
= (properties
!= null) ? properties
: new Hashtable();
347 if (width
<= 0 || height
<= 0 || pixels
== null)
359 // java.awt.Image methods ////////////////////////////////////////////////
361 public synchronized int getWidth (ImageObserver observer
)
363 if (addObserver(observer
))
369 public synchronized int getHeight (ImageObserver observer
)
371 if (addObserver(observer
))
377 public synchronized Object
getProperty (String name
, ImageObserver observer
)
379 if (addObserver(observer
))
380 return UndefinedProperty
;
382 Object value
= props
.get (name
);
383 return (value
== null) ? UndefinedProperty
: value
;
387 * Returns the source of this image.
389 public ImageProducer
getSource ()
393 return new MemoryImageSource(width
, height
, nativeModel
, getPixels(),
398 * Creates a GdkGraphics context for this pixmap.
400 public Graphics
getGraphics ()
405 return new GdkGraphics(this);
407 throw new IllegalAccessError("This method only works for off-screen"
412 * Returns a scaled instance of this pixmap.
414 public Image
getScaledInstance(int width
,
418 if (width
<= 0 || height
<= 0)
419 throw new IllegalArgumentException("Width and height of scaled bitmap"+
422 return new GtkImage(this, width
, height
, hints
);
426 * If the image is loaded and comes from an ImageProducer,
427 * regenerate the image from there.
429 * I have no idea if this is ever actually used. Since GtkImage can't be
430 * instantiated directly, how is the user to know if it was created from
431 * an ImageProducer or not?
433 public synchronized void flush ()
435 if (isLoaded
&& source
!= null)
437 observers
= new Vector();
440 source
.startProduction(new GtkImageConsumer(this, source
));
444 public void finalize()
451 * Returns the image status, used by GtkToolkit
453 public int checkImage (ImageObserver observer
)
455 if (addObserver(observer
))
457 if (errorLoading
== true)
458 return ImageObserver
.ERROR
;
463 return ImageObserver
.ALLBITS
| ImageObserver
.WIDTH
| ImageObserver
.HEIGHT
;
466 // Drawing methods ////////////////////////////////////////////////
469 * Draws an image with eventual scaling/transforming.
471 public boolean drawImage (GdkGraphics g
, int dx1
, int dy1
, int dx2
, int dy2
,
472 int sx1
, int sy1
, int sx2
, int sy2
,
473 Color bgcolor
, ImageObserver observer
)
475 if (addObserver(observer
))
478 boolean flipX
= (dx1
> dx2
)^
(sx1
> sx2
);
479 boolean flipY
= (dy1
> dy2
)^
(sy1
> sy2
);
480 int dstWidth
= Math
.abs (dx2
- dx1
);
481 int dstHeight
= Math
.abs (dy2
- dy1
);
482 int srcWidth
= Math
.abs (sx2
- sx1
);
483 int srcHeight
= Math
.abs (sy2
- sy1
);
484 int srcX
= (sx1
< sx2
) ? sx1
: sx2
;
485 int srcY
= (sy1
< sy2
) ? sy1
: sy2
;
486 int dstX
= (dx1
< dx2
) ? dx1
: dx2
;
487 int dstY
= (dy1
< dy2
) ? dy1
: dy2
;
489 // Clipping. This requires the dst to be scaled as well,
490 if (srcWidth
> width
)
492 dstWidth
= (int)((double)dstWidth
*((double)width
/(double)srcWidth
));
493 srcWidth
= width
- srcX
;
496 if (srcHeight
> height
)
498 dstHeight
= (int)((double)dstHeight
*((double)height
/(double)srcHeight
));
499 srcHeight
= height
- srcY
;
502 if (srcWidth
+ srcX
> width
)
504 dstWidth
= (int)((double)dstWidth
* (double)(width
- srcX
)/(double)srcWidth
);
505 srcWidth
= width
- srcX
;
508 if (srcHeight
+ srcY
> height
)
510 dstHeight
= (int)((double)dstHeight
* (double)(width
- srcY
)/(double)srcHeight
);
511 srcHeight
= height
- srcY
;
514 if ( srcWidth
<= 0 || srcHeight
<= 0 || dstWidth
<= 0 || dstHeight
<= 0)
518 drawPixelsScaledFlipped (g
, bgcolor
.getRed (), bgcolor
.getGreen (),
527 drawPixelsScaledFlipped (g
, 0, 0, 0, flipX
, flipY
,
528 srcX
, srcY
, srcWidth
, srcHeight
,
529 dstX
, dstY
, dstWidth
, dstHeight
,
535 * Draws an image to the GdkGraphics context, at (x,y) scaled to
536 * width and height, with optional compositing with a background color.
538 public boolean drawImage (GdkGraphics g
, int x
, int y
, int width
, int height
,
539 Color bgcolor
, ImageObserver observer
)
541 if (addObserver(observer
))
545 drawPixelsScaled(g
, bgcolor
.getRed (), bgcolor
.getGreen (),
546 bgcolor
.getBlue (), x
, y
, width
, height
, true);
548 drawPixelsScaled(g
, 0, 0, 0, x
, y
, width
, height
, false);
553 // Private methods ////////////////////////////////////////////////
556 * Delivers notifications to all queued observers.
558 private void deliver()
560 int flags
= ImageObserver
.HEIGHT
|
561 ImageObserver
.WIDTH
|
562 ImageObserver
.PROPERTIES
|
563 ImageObserver
.ALLBITS
;
565 if (observers
!= null)
566 for(int i
=0; i
< observers
.size(); i
++)
567 ((ImageObserver
)observers
.elementAt(i
)).
568 imageUpdate(this, flags
, 0, 0, width
, height
);
574 * Adds an observer, if we need to.
575 * @return true if an observer was added.
577 private boolean addObserver(ImageObserver observer
)
582 if (!observers
.contains (observer
))
583 observers
.addElement (observer
);