1 /* BufferedImage.java --
2 Copyright (C) 2000, 2002, 2003, 2004, 2005 Free Software Foundation
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 java
.awt
.image
;
41 import gnu
.java
.awt
.ComponentDataBlitOp
;
43 import java
.awt
.Graphics
;
44 import java
.awt
.Graphics2D
;
45 import java
.awt
.GraphicsEnvironment
;
46 import java
.awt
.Image
;
47 import java
.awt
.Point
;
48 import java
.awt
.Rectangle
;
49 import java
.awt
.Transparency
;
50 import java
.awt
.color
.ColorSpace
;
51 import java
.util
.Hashtable
;
52 import java
.util
.Vector
;
55 * A buffered image always starts at coordinates (0, 0).
57 * The buffered image is not subdivided into multiple tiles. Instead,
58 * the image consists of one large tile (0,0) with the width and
59 * height of the image. This tile is always considered to be checked
62 * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
64 public class BufferedImage
extends Image
65 implements WritableRenderedImage
, Transparency
67 public static final int TYPE_CUSTOM
= 0,
70 TYPE_INT_ARGB_PRE
= 3,
74 TYPE_4BYTE_ABGR_PRE
= 7,
75 TYPE_USHORT_565_RGB
= 8,
76 TYPE_USHORT_555_RGB
= 9,
78 TYPE_USHORT_GRAY
= 11,
79 TYPE_BYTE_BINARY
= 12,
80 TYPE_BYTE_INDEXED
= 13;
82 static final int[] bits3
= { 8, 8, 8 };
83 static final int[] bits4
= { 8, 8, 8 };
84 static final int[] bits1byte
= { 8 };
85 static final int[] bits1ushort
= { 16 };
87 static final int[] masks_int
= { 0x00ff0000,
90 DataBuffer
.TYPE_INT
};
91 static final int[] masks_565
= { 0xf800,
94 DataBuffer
.TYPE_USHORT
};
95 static final int[] masks_555
= { 0x7c00,
98 DataBuffer
.TYPE_USHORT
};
102 public BufferedImage(int w
, int h
, int type
)
104 ColorModel cm
= null;
106 boolean alpha
= false;
107 boolean premultiplied
= false;
110 case TYPE_4BYTE_ABGR_PRE
:
111 case TYPE_INT_ARGB_PRE
:
112 premultiplied
= true;
115 case TYPE_4BYTE_ABGR
:
119 ColorSpace cs
= ColorSpace
.getInstance(ColorSpace
.CS_sRGB
);
124 case TYPE_INT_ARGB_PRE
:
125 case TYPE_USHORT_565_RGB
:
126 case TYPE_USHORT_555_RGB
:
132 case TYPE_INT_ARGB_PRE
:
135 case TYPE_USHORT_565_RGB
:
138 case TYPE_USHORT_555_RGB
:
143 cm
= new DirectColorModel(cs
,
144 32, // 32 bits in an int
148 alpha ?
0xff000000 : 0,
150 masks
[3] // data type
156 "FIXME: Programmer is confused. Why (and how) does a " +
157 "TYPE_INT_BGR image use ComponentColorModel to store " +
158 "8-bit values? Is data type TYPE_INT or TYPE_BYTE. What " +
159 "is the difference between TYPE_INT_BGR and TYPE_3BYTE_BGR?";
160 throw new UnsupportedOperationException(msg
);
163 case TYPE_4BYTE_ABGR
:
164 case TYPE_4BYTE_ABGR_PRE
:
166 case TYPE_USHORT_GRAY
:
168 int dataType
= DataBuffer
.TYPE_BYTE
;
173 case TYPE_4BYTE_ABGR
:
174 case TYPE_4BYTE_ABGR_PRE
:
180 case TYPE_USHORT_GRAY
:
182 dataType
= DataBuffer
.TYPE_USHORT
;
185 cm
= new ComponentColorModel(cs
, bits
, alpha
, premultiplied
,
187 Transparency
.TRANSLUCENT
:
191 case TYPE_BYTE_BINARY
:
192 byte[] vals
= { 0, (byte) 0xff };
193 cm
= new IndexColorModel(8, 2, vals
, vals
, vals
);
195 case TYPE_BYTE_INDEXED
:
196 String msg2
= "type not implemented yet";
197 throw new UnsupportedOperationException(msg2
);
198 // FIXME: build color-cube and create color model
202 cm
.createCompatibleWritableRaster(w
, h
),
204 null, // no properties
209 public BufferedImage(int w
, int h
, int type
,
210 IndexColorModel indexcolormodel
)
212 if ((type
!= TYPE_BYTE_BINARY
) && (type
!= TYPE_BYTE_INDEXED
))
213 throw new IllegalArgumentException("type must be binary or indexed");
215 init(indexcolormodel
,
216 indexcolormodel
.createCompatibleWritableRaster(w
, h
),
217 false, // not premultiplied (guess)
218 null, // no properties
222 public BufferedImage(ColorModel colormodel
,
223 WritableRaster writableraster
,
224 boolean premultiplied
,
225 Hashtable properties
)
227 init(colormodel
, writableraster
, premultiplied
, properties
,
229 // TODO: perhaps try to identify type?
232 WritableRaster raster
;
233 ColorModel colorModel
;
234 Hashtable properties
;
235 boolean isPremultiplied
;
238 private void init(ColorModel cm
,
239 WritableRaster writableraster
,
240 boolean premultiplied
,
241 Hashtable properties
,
244 raster
= writableraster
;
246 this.properties
= properties
;
247 isPremultiplied
= premultiplied
;
251 //public void addTileObserver(TileObserver tileobserver) {}
253 public void coerceData(boolean premultiplied
)
255 colorModel
= colorModel
.coerceData(raster
, premultiplied
);
258 public WritableRaster
copyData(WritableRaster dest
)
261 dest
= raster
.createCompatibleWritableRaster(getMinX(), getMinY(),
262 getWidth(),getHeight());
264 int x
= dest
.getMinX();
265 int y
= dest
.getMinY();
266 int w
= dest
.getWidth();
267 int h
= dest
.getHeight();
269 // create a src child that has the right bounds...
271 raster
.createWritableChild(x
, y
, w
, h
, x
, y
,
274 if (src
.getSampleModel () instanceof ComponentSampleModel
275 && dest
.getSampleModel () instanceof ComponentSampleModel
)
276 // Refer to ComponentDataBlitOp for optimized data blitting:
277 ComponentDataBlitOp
.INSTANCE
.filter(src
, dest
);
281 int samples
[] = src
.getPixels (x
, y
, w
, h
, (int [])null);
282 dest
.setPixels (x
, y
, w
, h
, samples
);
287 public Graphics2D
createGraphics()
289 GraphicsEnvironment env
;
290 env
= GraphicsEnvironment
.getLocalGraphicsEnvironment ();
291 return env
.createGraphics (this);
294 public void flush() {
297 public WritableRaster
getAlphaRaster()
299 return colorModel
.getAlphaRaster(raster
);
302 public ColorModel
getColorModel()
307 public Raster
getData()
309 return copyData(null);
310 /* TODO: this might be optimized by returning the same
311 raster (not writable) as long as image data doesn't change. */
314 public Raster
getData(Rectangle rectangle
)
316 WritableRaster dest
=
317 raster
.createCompatibleWritableRaster(rectangle
);
318 return copyData(dest
);
321 public Graphics
getGraphics()
323 return createGraphics();
326 public int getHeight()
328 return raster
.getHeight();
331 public int getHeight(ImageObserver imageobserver
)
336 public int getMinTileX()
341 public int getMinTileY()
356 public int getNumXTiles()
361 public int getNumYTiles()
366 public Object
getProperty(String string
)
368 if (properties
== null)
370 return properties
.get(string
);
373 public Object
getProperty(String string
, ImageObserver imageobserver
)
375 return getProperty(string
);
379 public String
[] getPropertyNames()
385 public int getRGB(int x
, int y
)
387 Object rgbElem
= raster
.getDataElements(x
, y
,
388 null // create as needed
390 return colorModel
.getRGB(rgbElem
);
393 public int[] getRGB(int startX
, int startY
, int w
, int h
,
395 int offset
, int scanlineStride
)
397 if (rgbArray
== null)
401 00000[#######----- [ = start
402 -----########----- ] = end
404 000000000000000000 */
405 int size
= (h
-1)*scanlineStride
+ w
;
406 rgbArray
= new int[size
];
409 int endX
= startX
+ w
;
410 int endY
= startY
+ h
;
413 Opportunity for optimization by examining color models...
415 Perhaps wrap the rgbArray up in a WritableRaster with packed
416 sRGB color model and perform optimized rendering into the
419 Object rgbElem
= null;
420 for (int y
=startY
; y
<endY
; y
++)
422 int xoffset
= offset
;
423 for (int x
=startX
; x
<endX
; x
++)
426 rgbElem
= raster
.getDataElements(x
, y
, rgbElem
);
427 rgb
= colorModel
.getRGB(rgbElem
);
428 rgbArray
[xoffset
++] = rgb
;
430 offset
+= scanlineStride
;
435 public WritableRaster
getRaster()
440 public SampleModel
getSampleModel()
442 return raster
.getSampleModel();
445 public ImageProducer
getSource()
447 return new ImageProducer() {
449 Vector consumers
= new Vector();
451 public void addConsumer(ImageConsumer ic
)
453 if(!consumers
.contains(ic
))
457 public boolean isConsumer(ImageConsumer ic
)
459 return consumers
.contains(ic
);
462 public void removeConsumer(ImageConsumer ic
)
464 consumers
.remove(ic
);
467 public void startProduction(ImageConsumer ic
)
471 int width
= getWidth();
472 int height
= getHeight();
475 int[] pixels
= getRGB(x
, y
,
477 (int[])null, offset
, stride
);
478 ColorModel model
= getColorModel();
482 for(int i
=0;i
<consumers
.size();i
++)
484 ImageConsumer c
= (ImageConsumer
) consumers
.elementAt(i
);
485 c
.setHints(ImageConsumer
.SINGLEPASS
);
486 c
.setDimensions(getWidth(), getHeight());
487 c
.setPixels(x
, y
, width
, height
, model
, pixels
, offset
, stride
);
488 c
.imageComplete(ImageConsumer
.STATICIMAGEDONE
);
492 public void requestTopDownLeftRightResend(ImageConsumer ic
)
500 public Vector
getSources()
505 public BufferedImage
getSubimage(int x
, int y
, int w
, int h
)
507 WritableRaster subRaster
=
508 getRaster().createWritableChild(x
, y
, w
, h
, 0, 0, null);
510 return new BufferedImage(getColorModel(),
516 public Raster
getTile(int tileX
, int tileY
)
518 return getWritableTile(tileX
, tileY
);
521 public int getTileGridXOffset()
523 return 0; // according to javadocs
526 public int getTileGridYOffset()
528 return 0; // according to javadocs
531 public int getTileHeight()
533 return getHeight(); // image is one big tile
536 public int getTileWidth()
538 return getWidth(); // image is one big tile
546 public int getWidth()
548 return raster
.getWidth();
551 public int getWidth(ImageObserver imageobserver
)
556 public WritableRaster
getWritableTile(int tileX
, int tileY
)
558 isTileWritable(tileX
, tileY
); // for exception
562 private static final Point
[] tileIndices
= { new Point() };
564 public Point
[] getWritableTileIndices()
569 public boolean hasTileWriters()
574 public boolean isAlphaPremultiplied()
576 return isPremultiplied
;
579 public boolean isTileWritable(int tileX
, int tileY
)
581 if ((tileX
!= 0) || (tileY
!= 0))
582 throw new ArrayIndexOutOfBoundsException("only tile is (0,0)");
586 public void releaseWritableTile(int tileX
, int tileY
)
588 isTileWritable(tileX
, tileY
); // for exception
591 //public void removeTileObserver(TileObserver tileobserver) {}
593 public void setData(Raster src
)
595 int x
= src
.getMinX();
596 int y
= src
.getMinY();
597 int w
= src
.getWidth();
598 int h
= src
.getHeight();
600 // create a dest child that has the right bounds...
601 WritableRaster dest
=
602 raster
.createWritableChild(x
, y
, w
, h
, x
, y
,
606 if (src
.getSampleModel () instanceof ComponentSampleModel
607 && dest
.getSampleModel () instanceof ComponentSampleModel
)
609 // Refer to ComponentDataBlitOp for optimized data blitting:
610 ComponentDataBlitOp
.INSTANCE
.filter(src
, dest
);
614 int samples
[] = src
.getPixels (x
, y
, w
, h
, (int [])null);
615 dest
.setPixels (x
, y
, w
, h
, samples
);
619 public void setRGB(int x
, int y
, int argb
)
621 Object rgbElem
= colorModel
.getDataElements(argb
, null);
622 raster
.setDataElements(x
, y
, rgbElem
);
625 public void setRGB(int startX
, int startY
, int w
, int h
,
626 int[] argbArray
, int offset
, int scanlineStride
)
628 int endX
= startX
+ w
;
629 int endY
= startY
+ h
;
631 Object rgbElem
= null;
632 for (int y
=startY
; y
<endY
; y
++)
634 int xoffset
= offset
;
635 for (int x
=startX
; x
<endX
; x
++)
637 int argb
= argbArray
[xoffset
++];
638 rgbElem
= colorModel
.getDataElements(argb
, rgbElem
);
639 raster
.setDataElements(x
, y
, rgbElem
);
641 offset
+= scanlineStride
;
645 public String
toString()
649 buf
= new StringBuffer(/* estimated length */ 120);
650 buf
.append("BufferedImage@");
651 buf
.append(Integer
.toHexString(hashCode()));
652 buf
.append(": type=");
655 buf
.append(colorModel
);
659 return buf
.toString();
664 * Adds a tile observer. If the observer is already present, it receives
665 * multiple notifications.
667 * @param to The TileObserver to add.
669 public void addTileObserver (TileObserver to
)
671 if (observers
== null)
672 observers
= new Vector ();
678 * Removes a tile observer. If the observer was not registered,
679 * nothing happens. If the observer was registered for multiple
680 * notifications, it is now registered for one fewer notification.
682 * @param to The TileObserver to remove.
684 public void removeTileObserver (TileObserver to
)
686 if (observers
== null)
689 observers
.remove (to
);
693 * Return the transparency type.
695 * @return One of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT}.
696 * @see Transparency#getTransparency()
699 public int getTransparency()
701 return colorModel
.getTransparency();