2003-12-26 Guilhem Lavaux <guilhem@kaffe.org>
[official-gcc.git] / libjava / java / awt / image / BufferedImage.java
blob52006c099c14ccb698ded1bccab7414be17620aa
1 /* Copyright (C) 2000, 2002, 2003 Free Software Foundation
3 This file is part of GNU Classpath.
5 GNU Classpath is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
8 any later version.
10 GNU Classpath is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNU Classpath; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 USA.
20 Linking this library statically or dynamically with other modules is
21 making a combined work based on this library. Thus, the terms and
22 conditions of the GNU General Public License cover the whole
23 combination.
25 As a special exception, the copyright holders of this library give you
26 permission to link this library with independent modules to produce an
27 executable, regardless of the license terms of these independent
28 modules, and to copy and distribute the resulting executable under
29 terms of your choice, provided that you also meet, for each linked
30 independent module, the terms and conditions of the license of that
31 module. An independent module is a module which is not derived from
32 or based on this library. If you modify this library, you may extend
33 this exception to your version of the library, but you are not
34 obligated to do so. If you do not wish to do so, delete this
35 exception statement from your version. */
38 package java.awt.image;
40 import java.awt.Graphics;
41 import java.awt.Graphics2D;
42 import java.awt.Image;
43 import java.awt.Point;
44 import java.awt.Rectangle;
45 import java.awt.Transparency;
46 import java.awt.color.ColorSpace;
47 import java.util.Hashtable;
48 import java.util.Vector;
49 import gnu.java.awt.ComponentDataBlitOp;
51 /**
52 * A buffered image always starts at coordinates (0, 0).
54 * The buffered image is not subdivided into multiple tiles. Instead,
55 * the image consists of one large tile (0,0) with the width and
56 * height of the image. This tile is always considered to be checked
57 * out.
59 * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
61 public class BufferedImage extends Image
62 implements WritableRenderedImage
64 public static final int TYPE_CUSTOM = 0,
65 TYPE_INT_RGB = 1,
66 TYPE_INT_ARGB = 2,
67 TYPE_INT_ARGB_PRE = 3,
68 TYPE_INT_BGR = 4,
69 TYPE_3BYTE_BGR = 5,
70 TYPE_4BYTE_ABGR = 6,
71 TYPE_4BYTE_ABGR_PRE = 7,
72 TYPE_USHORT_565_RGB = 8,
73 TYPE_USHORT_555_RGB = 9,
74 TYPE_BYTE_GRAY = 10,
75 TYPE_USHORT_GRAY = 11,
76 TYPE_BYTE_BINARY = 12,
77 TYPE_BYTE_INDEXED = 13;
79 final static int[] bits3 = { 8, 8, 8 };
80 final static int[] bits4 = { 8, 8, 8 };
81 final static int[] bits1byte = { 8 };
82 final static int[] bits1ushort = { 16 };
84 final static int[] masks_int = { 0x00ff0000,
85 0x0000ff00,
86 0x000000ff,
87 DataBuffer.TYPE_INT };
88 final static int[] masks_565 = { 0xf800,
89 0x07e0,
90 0x001f,
91 DataBuffer.TYPE_USHORT};
92 final static int[] masks_555 = { 0x7c00,
93 0x03e0,
94 0x001f,
95 DataBuffer.TYPE_USHORT};
97 Vector observers;
99 public BufferedImage(int w, int h, int type)
101 ColorModel cm = null;
103 boolean alpha = false;
104 boolean premultiplied = false;
105 switch (type)
107 case TYPE_4BYTE_ABGR_PRE:
108 case TYPE_INT_ARGB_PRE:
109 premultiplied = true;
110 // fall through
111 case TYPE_INT_ARGB:
112 case TYPE_4BYTE_ABGR:
113 alpha = true;
116 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
117 switch (type)
119 case TYPE_INT_RGB:
120 case TYPE_INT_ARGB:
121 case TYPE_INT_ARGB_PRE:
122 case TYPE_USHORT_565_RGB:
123 case TYPE_USHORT_555_RGB:
124 int[] masks = null;
125 switch (type)
127 case TYPE_INT_RGB:
128 case TYPE_INT_ARGB:
129 case TYPE_INT_ARGB_PRE:
130 masks = masks_int;
131 break;
132 case TYPE_USHORT_565_RGB:
133 masks = masks_565;
134 break;
135 case TYPE_USHORT_555_RGB:
136 masks = masks_555;
137 break;
140 cm = new DirectColorModel(cs,
141 32, // 32 bits in an int
142 masks[0], // r
143 masks[1], // g
144 masks[2], // b
145 alpha ? 0xff000000 : 0,
146 premultiplied,
147 masks[3] // data type
149 break;
151 case TYPE_INT_BGR:
152 String msg =
153 "FIXME: Programmer is confused. Why (and how) does a " +
154 "TYPE_INT_BGR image use ComponentColorModel to store " +
155 "8-bit values? Is data type TYPE_INT or TYPE_BYTE. What " +
156 "is the difference between TYPE_INT_BGR and TYPE_3BYTE_BGR?";
157 throw new UnsupportedOperationException(msg);
159 case TYPE_3BYTE_BGR:
160 case TYPE_4BYTE_ABGR:
161 case TYPE_4BYTE_ABGR_PRE:
162 case TYPE_BYTE_GRAY:
163 case TYPE_USHORT_GRAY:
164 int[] bits = null;
165 int dataType = DataBuffer.TYPE_BYTE;
166 switch (type) {
167 case TYPE_3BYTE_BGR:
168 bits = bits3;
169 break;
170 case TYPE_4BYTE_ABGR:
171 case TYPE_4BYTE_ABGR_PRE:
172 bits = bits4;
173 break;
174 case TYPE_BYTE_GRAY:
175 bits = bits1byte;
176 break;
177 case TYPE_USHORT_GRAY:
178 bits = bits1ushort;
179 dataType = DataBuffer.TYPE_USHORT;
180 break;
182 cm = new ComponentColorModel(cs, bits, alpha, premultiplied,
183 alpha ?
184 Transparency.TRANSLUCENT:
185 Transparency.OPAQUE,
186 dataType);
187 break;
188 case TYPE_BYTE_BINARY:
189 byte[] vals = { 0, (byte) 0xff };
190 cm = new IndexColorModel(8, 2, vals, vals, vals);
191 break;
192 case TYPE_BYTE_INDEXED:
193 String msg2 = "type not implemented yet";
194 throw new UnsupportedOperationException(msg2);
195 // FIXME: build color-cube and create color model
198 init(cm,
199 cm.createCompatibleWritableRaster(w, h),
200 premultiplied,
201 null, // no properties
202 type
206 public BufferedImage(int w, int h, int type,
207 IndexColorModel indexcolormodel)
209 if ((type != TYPE_BYTE_BINARY) && (type != TYPE_BYTE_INDEXED))
210 throw new IllegalArgumentException("type must be binary or indexed");
212 init(indexcolormodel,
213 indexcolormodel.createCompatibleWritableRaster(w, h),
214 false, // not premultiplied (guess)
215 null, // no properties
216 type);
219 public BufferedImage(ColorModel colormodel,
220 WritableRaster writableraster,
221 boolean premultiplied,
222 Hashtable properties)
224 init(colormodel, writableraster, premultiplied, properties,
225 TYPE_CUSTOM);
226 // TODO: perhaps try to identify type?
229 WritableRaster raster;
230 ColorModel colorModel;
231 Hashtable properties;
232 boolean isPremultiplied;
233 int type;
235 private void init(ColorModel cm,
236 WritableRaster writableraster,
237 boolean premultiplied,
238 Hashtable properties,
239 int type)
241 raster = writableraster;
242 colorModel = cm;
243 this.properties = properties;
244 isPremultiplied = premultiplied;
245 this.type = type;
248 //public void addTileObserver(TileObserver tileobserver) {}
250 public void coerceData(boolean premultiplied)
252 colorModel = colorModel.coerceData(raster, premultiplied);
255 public WritableRaster copyData(WritableRaster dest)
257 if (dest == null)
258 dest = raster.createCompatibleWritableRaster();
260 int x = dest.getMinX();
261 int y = dest.getMinY();
262 int w = dest.getWidth();
263 int h = dest.getHeight();
265 // create a src child that has the right bounds...
266 WritableRaster src =
267 raster.createWritableChild(x, y, w, h, x, y,
268 null // same bands
270 if (src.getSampleModel () instanceof ComponentSampleModel
271 && dest.getSampleModel () instanceof ComponentSampleModel)
272 // Refer to ComponentDataBlitOp for optimized data blitting:
273 ComponentDataBlitOp.INSTANCE.filter(src, dest);
274 else
276 // slower path
277 int samples[] = src.getPixels (x, y, w, h, (int [])null);
278 dest.setPixels (x, y, w, h, samples);
280 return dest;
283 public Graphics2D createGraphics()
285 throw new UnsupportedOperationException("not implemented");
286 // will require a lot of effort to implement
289 public void flush() {
292 public WritableRaster getAlphaRaster()
294 return colorModel.getAlphaRaster(raster);
297 public ColorModel getColorModel()
299 return colorModel;
302 public Raster getData()
304 return copyData(null);
305 /* TODO: this might be optimized by returning the same
306 raster (not writable) as long as image data doesn't change. */
309 public Raster getData(Rectangle rectangle)
311 WritableRaster dest =
312 raster.createCompatibleWritableRaster(rectangle);
313 return copyData(dest);
316 public Graphics getGraphics()
318 return createGraphics();
321 public int getHeight()
323 return raster.getHeight();
326 public int getHeight(ImageObserver imageobserver)
328 return getHeight();
331 public int getMinTileX()
333 return 0;
336 public int getMinTileY()
338 return 0;
341 public int getMinX()
343 return 0;
346 public int getMinY()
348 return 0;
351 public int getNumXTiles()
353 return 1;
356 public int getNumYTiles()
358 return 1;
361 public Object getProperty(String string)
363 if (properties == null)
364 return null;
365 return properties.get(string);
368 public Object getProperty(String string, ImageObserver imageobserver)
370 return getProperty(string);
374 public String[] getPropertyNames()
376 // FIXME: implement
377 return null;
380 public int getRGB(int x, int y)
382 Object rgbElem = raster.getDataElements(x, y,
383 null // create as needed
385 return colorModel.getRGB(rgbElem);
388 public int[] getRGB(int startX, int startY, int w, int h,
389 int[] rgbArray,
390 int offset, int scanlineStride)
392 if (rgbArray == null)
395 000000000000000000
396 00000[#######----- [ = start
397 -----########----- ] = end
398 -----#######]00000
399 000000000000000000 */
400 int size = (h-1)*scanlineStride + w;
401 rgbArray = new int[size];
404 int endX = startX + w;
405 int endY = startY + h;
407 /* *TODO*:
408 Opportunity for optimization by examining color models...
410 Perhaps wrap the rgbArray up in a WritableRaster with packed
411 sRGB color model and perform optimized rendering into the
412 array. */
414 Object rgbElem = null;
415 for (int y=startY; y<endY; y++)
417 int xoffset = offset;
418 for (int x=startX; x<endX; x++)
420 int rgb;
421 rgbElem = raster.getDataElements(x, y, rgbElem);
422 rgb = colorModel.getRGB(rgbElem);
423 rgbArray[xoffset++] = rgb;
425 offset += scanlineStride;
427 return rgbArray;
430 public WritableRaster getRaster()
432 return raster;
435 public SampleModel getSampleModel()
437 return raster.getSampleModel();
440 public ImageProducer getSource()
442 throw new UnsupportedOperationException("not implemented");
445 public Vector getSources()
447 return null;
450 public BufferedImage getSubimage(int x, int y, int w, int h)
452 WritableRaster subRaster =
453 getRaster().createWritableChild(x, y, w, h, 0, 0, null);
455 return new BufferedImage(getColorModel(),
456 subRaster,
457 isPremultiplied,
458 properties);
461 public Raster getTile(int tileX, int tileY)
463 return getWritableTile(tileX, tileY);
466 public int getTileGridXOffset()
468 return 0; // according to javadocs
471 public int getTileGridYOffset()
473 return 0; // according to javadocs
476 public int getTileHeight()
478 return getHeight(); // image is one big tile
481 public int getTileWidth()
483 return getWidth(); // image is one big tile
486 public int getType()
488 return type;
491 public int getWidth()
493 return raster.getWidth();
496 public int getWidth(ImageObserver imageobserver)
498 return getWidth();
501 public WritableRaster getWritableTile(int tileX, int tileY)
503 isTileWritable(tileX, tileY); // for exception
504 return raster;
507 private static final Point[] tileIndices = { new Point() };
509 public Point[] getWritableTileIndices()
511 return tileIndices;
514 public boolean hasTileWriters()
516 return true;
519 public boolean isAlphaPremultiplied()
521 return isPremultiplied;
524 public boolean isTileWritable(int tileX, int tileY)
526 if ((tileX != 0) || (tileY != 0))
527 throw new ArrayIndexOutOfBoundsException("only tile is (0,0)");
528 return true;
531 public void releaseWritableTile(int tileX, int tileY)
533 isTileWritable(tileX, tileY); // for exception
536 //public void removeTileObserver(TileObserver tileobserver) {}
538 public void setData(Raster src)
540 int x = src.getMinX();
541 int y = src.getMinY();
542 int w = src.getWidth();
543 int h = src.getHeight();
545 // create a dest child that has the right bounds...
546 WritableRaster dest =
547 raster.createWritableChild(x, y, w, h, x, y,
548 null // same bands
551 if (src.getSampleModel () instanceof ComponentSampleModel
552 && dest.getSampleModel () instanceof ComponentSampleModel)
554 // Refer to ComponentDataBlitOp for optimized data blitting:
555 ComponentDataBlitOp.INSTANCE.filter(src, dest);
556 else
558 // slower path
559 int samples[] = src.getPixels (x, y, w, h, (int [])null);
560 dest.setPixels (x, y, w, h, samples);
564 public void setRGB(int x, int y, int argb)
566 Object rgbElem = colorModel.getDataElements(argb, null);
567 raster.setDataElements(x, y, rgbElem);
570 public void setRGB(int startX, int startY, int w, int h,
571 int[] argbArray, int offset, int scanlineStride)
573 int endX = startX + w;
574 int endY = startY + h;
576 Object rgbElem = null;
577 for (int y=startY; y<endY; y++)
579 int xoffset = offset;
580 for (int x=startX; x<endX; x++)
582 int argb = argbArray[xoffset++];
583 rgbElem = colorModel.getDataElements(argb, rgbElem);
584 raster.setDataElements(x, y, rgbElem);
586 offset += scanlineStride;
590 public String toString()
592 StringBuffer buf;
594 buf = new StringBuffer(/* estimated length */ 120);
595 buf.append("BufferedImage@");
596 buf.append(Integer.toHexString(hashCode()));
597 buf.append(": type=");
598 buf.append(type);
599 buf.append(' ');
600 buf.append(colorModel);
601 buf.append(' ');
602 buf.append(raster);
604 return buf.toString();
609 * Adds a tile observer. If the observer is already present, it receives
610 * multiple notifications.
612 * @param to The TileObserver to add.
614 public void addTileObserver (TileObserver to)
616 if (observers == null)
617 observers = new Vector ();
619 observers.add (to);
623 * Removes a tile observer. If the observer was not registered,
624 * nothing happens. If the observer was registered for multiple
625 * notifications, it is now registered for one fewer notification.
627 * @param to The TileObserver to remove.
629 public void removeTileObserver (TileObserver to)
631 if (observers == null)
632 return;
634 observers.remove (to);