Dead
[official-gcc.git] / gomp-20050608-branch / libjava / classpath / java / awt / image / BufferedImage.java
blob3cabfbde6926084be0355056cb05e299bb8ed633
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)
9 any later version.
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
19 02110-1301 USA.
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
24 combination.
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;
54 /**
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
60 * out.
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,
68 TYPE_INT_RGB = 1,
69 TYPE_INT_ARGB = 2,
70 TYPE_INT_ARGB_PRE = 3,
71 TYPE_INT_BGR = 4,
72 TYPE_3BYTE_BGR = 5,
73 TYPE_4BYTE_ABGR = 6,
74 TYPE_4BYTE_ABGR_PRE = 7,
75 TYPE_USHORT_565_RGB = 8,
76 TYPE_USHORT_555_RGB = 9,
77 TYPE_BYTE_GRAY = 10,
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,
88 0x0000ff00,
89 0x000000ff,
90 DataBuffer.TYPE_INT };
91 static final int[] masks_565 = { 0xf800,
92 0x07e0,
93 0x001f,
94 DataBuffer.TYPE_USHORT};
95 static final int[] masks_555 = { 0x7c00,
96 0x03e0,
97 0x001f,
98 DataBuffer.TYPE_USHORT};
100 Vector observers;
102 public BufferedImage(int w, int h, int type)
104 ColorModel cm = null;
106 boolean alpha = false;
107 boolean premultiplied = false;
108 switch (type)
110 case TYPE_4BYTE_ABGR_PRE:
111 case TYPE_INT_ARGB_PRE:
112 premultiplied = true;
113 // fall through
114 case TYPE_INT_ARGB:
115 case TYPE_4BYTE_ABGR:
116 alpha = true;
119 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
120 switch (type)
122 case TYPE_INT_RGB:
123 case TYPE_INT_ARGB:
124 case TYPE_INT_ARGB_PRE:
125 case TYPE_USHORT_565_RGB:
126 case TYPE_USHORT_555_RGB:
127 int[] masks = null;
128 switch (type)
130 case TYPE_INT_RGB:
131 case TYPE_INT_ARGB:
132 case TYPE_INT_ARGB_PRE:
133 masks = masks_int;
134 break;
135 case TYPE_USHORT_565_RGB:
136 masks = masks_565;
137 break;
138 case TYPE_USHORT_555_RGB:
139 masks = masks_555;
140 break;
143 cm = new DirectColorModel(cs,
144 32, // 32 bits in an int
145 masks[0], // r
146 masks[1], // g
147 masks[2], // b
148 alpha ? 0xff000000 : 0,
149 premultiplied,
150 masks[3] // data type
152 break;
154 case TYPE_INT_BGR:
155 String msg =
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);
162 case TYPE_3BYTE_BGR:
163 case TYPE_4BYTE_ABGR:
164 case TYPE_4BYTE_ABGR_PRE:
165 case TYPE_BYTE_GRAY:
166 case TYPE_USHORT_GRAY:
167 int[] bits = null;
168 int dataType = DataBuffer.TYPE_BYTE;
169 switch (type) {
170 case TYPE_3BYTE_BGR:
171 bits = bits3;
172 break;
173 case TYPE_4BYTE_ABGR:
174 case TYPE_4BYTE_ABGR_PRE:
175 bits = bits4;
176 break;
177 case TYPE_BYTE_GRAY:
178 bits = bits1byte;
179 break;
180 case TYPE_USHORT_GRAY:
181 bits = bits1ushort;
182 dataType = DataBuffer.TYPE_USHORT;
183 break;
185 cm = new ComponentColorModel(cs, bits, alpha, premultiplied,
186 alpha ?
187 Transparency.TRANSLUCENT:
188 Transparency.OPAQUE,
189 dataType);
190 break;
191 case TYPE_BYTE_BINARY:
192 byte[] vals = { 0, (byte) 0xff };
193 cm = new IndexColorModel(8, 2, vals, vals, vals);
194 break;
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
201 init(cm,
202 cm.createCompatibleWritableRaster(w, h),
203 premultiplied,
204 null, // no properties
205 type
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
219 type);
222 public BufferedImage(ColorModel colormodel,
223 WritableRaster writableraster,
224 boolean premultiplied,
225 Hashtable properties)
227 init(colormodel, writableraster, premultiplied, properties,
228 TYPE_CUSTOM);
229 // TODO: perhaps try to identify type?
232 WritableRaster raster;
233 ColorModel colorModel;
234 Hashtable properties;
235 boolean isPremultiplied;
236 int type;
238 private void init(ColorModel cm,
239 WritableRaster writableraster,
240 boolean premultiplied,
241 Hashtable properties,
242 int type)
244 raster = writableraster;
245 colorModel = cm;
246 this.properties = properties;
247 isPremultiplied = premultiplied;
248 this.type = type;
251 //public void addTileObserver(TileObserver tileobserver) {}
253 public void coerceData(boolean premultiplied)
255 colorModel = colorModel.coerceData(raster, premultiplied);
258 public WritableRaster copyData(WritableRaster dest)
260 if (dest == null)
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...
270 WritableRaster src =
271 raster.createWritableChild(x, y, w, h, x, y,
272 null // same bands
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);
278 else
280 // slower path
281 int samples[] = src.getPixels (x, y, w, h, (int [])null);
282 dest.setPixels (x, y, w, h, samples);
284 return dest;
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()
304 return colorModel;
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)
333 return getHeight();
336 public int getMinTileX()
338 return 0;
341 public int getMinTileY()
343 return 0;
346 public int getMinX()
348 return 0;
351 public int getMinY()
353 return 0;
356 public int getNumXTiles()
358 return 1;
361 public int getNumYTiles()
363 return 1;
366 public Object getProperty(String string)
368 if (properties == null)
369 return null;
370 return properties.get(string);
373 public Object getProperty(String string, ImageObserver imageobserver)
375 return getProperty(string);
379 public String[] getPropertyNames()
381 // FIXME: implement
382 return null;
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,
394 int[] rgbArray,
395 int offset, int scanlineStride)
397 if (rgbArray == null)
400 000000000000000000
401 00000[#######----- [ = start
402 -----########----- ] = end
403 -----#######]00000
404 000000000000000000 */
405 int size = (h-1)*scanlineStride + w;
406 rgbArray = new int[size];
409 int endX = startX + w;
410 int endY = startY + h;
412 /* *TODO*:
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
417 array. */
419 Object rgbElem = null;
420 for (int y=startY; y<endY; y++)
422 int xoffset = offset;
423 for (int x=startX; x<endX; x++)
425 int rgb;
426 rgbElem = raster.getDataElements(x, y, rgbElem);
427 rgb = colorModel.getRGB(rgbElem);
428 rgbArray[xoffset++] = rgb;
430 offset += scanlineStride;
432 return rgbArray;
435 public WritableRaster getRaster()
437 return raster;
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))
454 consumers.add(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)
469 int x = 0;
470 int y = 0;
471 int width = getWidth();
472 int height = getHeight();
473 int stride = width;
474 int offset = 0;
475 int[] pixels = getRGB(x, y,
476 width, height,
477 (int[])null, offset, stride);
478 ColorModel model = getColorModel();
480 consumers.add(ic);
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)
494 startProduction(ic);
500 public Vector getSources()
502 return null;
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(),
511 subRaster,
512 isPremultiplied,
513 properties);
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
541 public int getType()
543 return type;
546 public int getWidth()
548 return raster.getWidth();
551 public int getWidth(ImageObserver imageobserver)
553 return getWidth();
556 public WritableRaster getWritableTile(int tileX, int tileY)
558 isTileWritable(tileX, tileY); // for exception
559 return raster;
562 private static final Point[] tileIndices = { new Point() };
564 public Point[] getWritableTileIndices()
566 return tileIndices;
569 public boolean hasTileWriters()
571 return true;
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)");
583 return true;
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,
603 null // same bands
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);
611 else
613 // slower path
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()
647 StringBuffer buf;
649 buf = new StringBuffer(/* estimated length */ 120);
650 buf.append("BufferedImage@");
651 buf.append(Integer.toHexString(hashCode()));
652 buf.append(": type=");
653 buf.append(type);
654 buf.append(' ');
655 buf.append(colorModel);
656 buf.append(' ');
657 buf.append(raster);
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 ();
674 observers.add (to);
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)
687 return;
689 observers.remove (to);
693 * Return the transparency type.
695 * @return One of {@link #OPAQUE}, {@link #BITMASK}, or {@link #TRANSLUCENT}.
696 * @see Transparency#getTransparency()
697 * @since 1.5
699 public int getTransparency()
701 return colorModel.getTransparency();