blob: 763fc31df69d3362ad9d9710c0cc60eeed29dc71 [file] [log] [blame]
J. Duke319a3b92007-12-01 00:00:00 +00001/*
2 * Copyright 1997-2006 Sun Microsystems, Inc. All Rights Reserved.
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * This code is free software; you can redistribute it and/or modify it
6 * under the terms of the GNU General Public License version 2 only, as
7 * published by the Free Software Foundation. Sun designates this
8 * particular file as subject to the "Classpath" exception as provided
9 * by Sun in the LICENSE file that accompanied this code.
10 *
11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * version 2 for more details (a copy is included in the LICENSE file that
15 * accompanied this code).
16 *
17 * You should have received a copy of the GNU General Public License version
18 * 2 along with this work; if not, write to the Free Software Foundation,
19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 *
21 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
22 * CA 95054 USA or visit www.sun.com if you need additional information or
23 * have any questions.
24 */
25
26package java.awt.image;
27
28import java.awt.Transparency;
29import java.awt.color.ColorSpace;
30import java.awt.Graphics2D;
31import java.awt.GraphicsConfiguration;
32import java.awt.GraphicsEnvironment;
33import java.awt.ImageCapabilities;
34import java.awt.geom.Rectangle2D;
35import java.awt.geom.Point2D;
36import java.awt.Point;
37import java.awt.Rectangle;
38import java.util.Hashtable;
39import java.util.Vector;
40
41import sun.awt.image.BytePackedRaster;
42import sun.awt.image.ShortComponentRaster;
43import sun.awt.image.ByteComponentRaster;
44import sun.awt.image.IntegerComponentRaster;
45import sun.awt.image.OffScreenImageSource;
46
47/**
48 *
49 * The <code>BufferedImage</code> subclass describes an {@link
50 * java.awt.Image Image} with an accessible buffer of image data.
51 * A <code>BufferedImage</code> is comprised of a {@link ColorModel} and a
52 * {@link Raster} of image data.
53 * The number and types of bands in the {@link SampleModel} of the
54 * <code>Raster</code> must match the number and types required by the
55 * <code>ColorModel</code> to represent its color and alpha components.
56 * All <code>BufferedImage</code> objects have an upper left corner
57 * coordinate of (0,&nbsp;0). Any <code>Raster</code> used to construct a
58 * <code>BufferedImage</code> must therefore have minX=0 and minY=0.
59 *
60 * <p>
61 * This class relies on the data fetching and setting methods
62 * of <code>Raster</code>,
63 * and on the color characterization methods of <code>ColorModel</code>.
64 *
65 * @see ColorModel
66 * @see Raster
67 * @see WritableRaster
68 */
69
70public class BufferedImage extends java.awt.Image
71 implements WritableRenderedImage, Transparency
72{
73 int imageType = TYPE_CUSTOM;
74 ColorModel colorModel;
75 WritableRaster raster;
76 OffScreenImageSource osis;
77 Hashtable properties;
78
79 boolean isAlphaPremultiplied;// If true, alpha has been premultiplied in
80 // color channels
81
82 /**
83 * Image Type Constants
84 */
85
86 /**
87 * Image type is not recognized so it must be a customized
88 * image. This type is only used as a return value for the getType()
89 * method.
90 */
91 public static final int TYPE_CUSTOM = 0;
92
93 /**
94 * Represents an image with 8-bit RGB color components packed into
95 * integer pixels. The image has a {@link DirectColorModel} without
96 * alpha.
97 * When data with non-opaque alpha is stored
98 * in an image of this type,
99 * the color data must be adjusted to a non-premultiplied form
100 * and the alpha discarded,
101 * as described in the
102 * {@link java.awt.AlphaComposite} documentation.
103 */
104 public static final int TYPE_INT_RGB = 1;
105
106 /**
107 * Represents an image with 8-bit RGBA color components packed into
108 * integer pixels. The image has a <code>DirectColorModel</code>
109 * with alpha. The color data in this image is considered not to be
110 * premultiplied with alpha. When this type is used as the
111 * <code>imageType</code> argument to a <code>BufferedImage</code>
112 * constructor, the created image is consistent with images
113 * created in the JDK1.1 and earlier releases.
114 */
115 public static final int TYPE_INT_ARGB = 2;
116
117 /**
118 * Represents an image with 8-bit RGBA color components packed into
119 * integer pixels. The image has a <code>DirectColorModel</code>
120 * with alpha. The color data in this image is considered to be
121 * premultiplied with alpha.
122 */
123 public static final int TYPE_INT_ARGB_PRE = 3;
124
125 /**
126 * Represents an image with 8-bit RGB color components, corresponding
127 * to a Windows- or Solaris- style BGR color model, with the colors
128 * Blue, Green, and Red packed into integer pixels. There is no alpha.
129 * The image has a {@link DirectColorModel}.
130 * When data with non-opaque alpha is stored
131 * in an image of this type,
132 * the color data must be adjusted to a non-premultiplied form
133 * and the alpha discarded,
134 * as described in the
135 * {@link java.awt.AlphaComposite} documentation.
136 */
137 public static final int TYPE_INT_BGR = 4;
138
139 /**
140 * Represents an image with 8-bit RGB color components, corresponding
141 * to a Windows-style BGR color model) with the colors Blue, Green,
142 * and Red stored in 3 bytes. There is no alpha. The image has a
143 * <code>ComponentColorModel</code>.
144 * When data with non-opaque alpha is stored
145 * in an image of this type,
146 * the color data must be adjusted to a non-premultiplied form
147 * and the alpha discarded,
148 * as described in the
149 * {@link java.awt.AlphaComposite} documentation.
150 */
151 public static final int TYPE_3BYTE_BGR = 5;
152
153 /**
154 * Represents an image with 8-bit RGBA color components with the colors
155 * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The
156 * image has a <code>ComponentColorModel</code> with alpha. The
157 * color data in this image is considered not to be premultiplied with
158 * alpha. The byte data is interleaved in a single
159 * byte array in the order A, B, G, R
160 * from lower to higher byte addresses within each pixel.
161 */
162 public static final int TYPE_4BYTE_ABGR = 6;
163
164 /**
165 * Represents an image with 8-bit RGBA color components with the colors
166 * Blue, Green, and Red stored in 3 bytes and 1 byte of alpha. The
167 * image has a <code>ComponentColorModel</code> with alpha. The color
168 * data in this image is considered to be premultiplied with alpha.
169 * The byte data is interleaved in a single byte array in the order
170 * A, B, G, R from lower to higher byte addresses within each pixel.
171 */
172 public static final int TYPE_4BYTE_ABGR_PRE = 7;
173
174 /**
175 * Represents an image with 5-6-5 RGB color components (5-bits red,
176 * 6-bits green, 5-bits blue) with no alpha. This image has
177 * a <code>DirectColorModel</code>.
178 * When data with non-opaque alpha is stored
179 * in an image of this type,
180 * the color data must be adjusted to a non-premultiplied form
181 * and the alpha discarded,
182 * as described in the
183 * {@link java.awt.AlphaComposite} documentation.
184 */
185 public static final int TYPE_USHORT_565_RGB = 8;
186
187 /**
188 * Represents an image with 5-5-5 RGB color components (5-bits red,
189 * 5-bits green, 5-bits blue) with no alpha. This image has
190 * a <code>DirectColorModel</code>.
191 * When data with non-opaque alpha is stored
192 * in an image of this type,
193 * the color data must be adjusted to a non-premultiplied form
194 * and the alpha discarded,
195 * as described in the
196 * {@link java.awt.AlphaComposite} documentation.
197 */
198 public static final int TYPE_USHORT_555_RGB = 9;
199
200 /**
201 * Represents a unsigned byte grayscale image, non-indexed. This
202 * image has a <code>ComponentColorModel</code> with a CS_GRAY
203 * {@link ColorSpace}.
204 * When data with non-opaque alpha is stored
205 * in an image of this type,
206 * the color data must be adjusted to a non-premultiplied form
207 * and the alpha discarded,
208 * as described in the
209 * {@link java.awt.AlphaComposite} documentation.
210 */
211 public static final int TYPE_BYTE_GRAY = 10;
212
213 /**
214 * Represents an unsigned short grayscale image, non-indexed). This
215 * image has a <code>ComponentColorModel</code> with a CS_GRAY
216 * <code>ColorSpace</code>.
217 * When data with non-opaque alpha is stored
218 * in an image of this type,
219 * the color data must be adjusted to a non-premultiplied form
220 * and the alpha discarded,
221 * as described in the
222 * {@link java.awt.AlphaComposite} documentation.
223 */
224 public static final int TYPE_USHORT_GRAY = 11;
225
226 /**
227 * Represents an opaque byte-packed 1, 2, or 4 bit image. The
228 * image has an {@link IndexColorModel} without alpha. When this
229 * type is used as the <code>imageType</code> argument to the
230 * <code>BufferedImage</code> constructor that takes an
231 * <code>imageType</code> argument but no <code>ColorModel</code>
232 * argument, a 1-bit image is created with an
233 * <code>IndexColorModel</code> with two colors in the default
234 * sRGB <code>ColorSpace</code>: {0,&nbsp;0,&nbsp;0} and
235 * {255,&nbsp;255,&nbsp;255}.
236 *
237 * <p> Images with 2 or 4 bits per pixel may be constructed via
238 * the <code>BufferedImage</code> constructor that takes a
239 * <code>ColorModel</code> argument by supplying a
240 * <code>ColorModel</code> with an appropriate map size.
241 *
242 * <p> Images with 8 bits per pixel should use the image types
243 * <code>TYPE_BYTE_INDEXED</code> or <code>TYPE_BYTE_GRAY</code>
244 * depending on their <code>ColorModel</code>.
245
246 * <p> When color data is stored in an image of this type,
247 * the closest color in the colormap is determined
248 * by the <code>IndexColorModel</code> and the resulting index is stored.
249 * Approximation and loss of alpha or color components
250 * can result, depending on the colors in the
251 * <code>IndexColorModel</code> colormap.
252 */
253 public static final int TYPE_BYTE_BINARY = 12;
254
255 /**
256 * Represents an indexed byte image. When this type is used as the
257 * <code>imageType</code> argument to the <code>BufferedImage</code>
258 * constructor that takes an <code>imageType</code> argument
259 * but no <code>ColorModel</code> argument, an
260 * <code>IndexColorModel</code> is created with
261 * a 256-color 6/6/6 color cube palette with the rest of the colors
262 * from 216-255 populated by grayscale values in the
263 * default sRGB ColorSpace.
264 *
265 * <p> When color data is stored in an image of this type,
266 * the closest color in the colormap is determined
267 * by the <code>IndexColorModel</code> and the resulting index is stored.
268 * Approximation and loss of alpha or color components
269 * can result, depending on the colors in the
270 * <code>IndexColorModel</code> colormap.
271 */
272 public static final int TYPE_BYTE_INDEXED = 13;
273
274 private static final int DCM_RED_MASK = 0x00ff0000;
275 private static final int DCM_GREEN_MASK = 0x0000ff00;
276 private static final int DCM_BLUE_MASK = 0x000000ff;
277 private static final int DCM_ALPHA_MASK = 0xff000000;
278 private static final int DCM_565_RED_MASK = 0xf800;
279 private static final int DCM_565_GRN_MASK = 0x07E0;
280 private static final int DCM_565_BLU_MASK = 0x001F;
281 private static final int DCM_555_RED_MASK = 0x7C00;
282 private static final int DCM_555_GRN_MASK = 0x03E0;
283 private static final int DCM_555_BLU_MASK = 0x001F;
284 private static final int DCM_BGR_RED_MASK = 0x0000ff;
285 private static final int DCM_BGR_GRN_MASK = 0x00ff00;
286 private static final int DCM_BGR_BLU_MASK = 0xff0000;
287
288
289 static private native void initIDs();
290 static {
291 ColorModel.loadLibraries();
292 initIDs();
293 }
294
295 /**
296 * Constructs a <code>BufferedImage</code> of one of the predefined
297 * image types. The <code>ColorSpace</code> for the image is the
298 * default sRGB space.
299 * @param width width of the created image
300 * @param height height of the created image
301 * @param imageType type of the created image
302 * @see ColorSpace
303 * @see #TYPE_INT_RGB
304 * @see #TYPE_INT_ARGB
305 * @see #TYPE_INT_ARGB_PRE
306 * @see #TYPE_INT_BGR
307 * @see #TYPE_3BYTE_BGR
308 * @see #TYPE_4BYTE_ABGR
309 * @see #TYPE_4BYTE_ABGR_PRE
310 * @see #TYPE_BYTE_GRAY
311 * @see #TYPE_USHORT_GRAY
312 * @see #TYPE_BYTE_BINARY
313 * @see #TYPE_BYTE_INDEXED
314 * @see #TYPE_USHORT_565_RGB
315 * @see #TYPE_USHORT_555_RGB
316 */
317 public BufferedImage(int width,
318 int height,
319 int imageType) {
320 switch (imageType) {
321 case TYPE_INT_RGB:
322 {
323 colorModel = new DirectColorModel(24,
324 0x00ff0000, // Red
325 0x0000ff00, // Green
326 0x000000ff, // Blue
327 0x0 // Alpha
328 );
329 raster = colorModel.createCompatibleWritableRaster(width,
330 height);
331 }
332 break;
333
334 case TYPE_INT_ARGB:
335 {
336 colorModel = ColorModel.getRGBdefault();
337
338 raster = colorModel.createCompatibleWritableRaster(width,
339 height);
340 }
341 break;
342
343 case TYPE_INT_ARGB_PRE:
344 {
345 colorModel = new
346 DirectColorModel(
347 ColorSpace.getInstance(ColorSpace.CS_sRGB),
348 32,
349 0x00ff0000,// Red
350 0x0000ff00,// Green
351 0x000000ff,// Blue
352 0xff000000,// Alpha
353 true, // Alpha Premultiplied
354 DataBuffer.TYPE_INT
355 );
356
357 raster = colorModel.createCompatibleWritableRaster(width,
358 height);
359 }
360 break;
361
362 case TYPE_INT_BGR:
363 {
364 colorModel = new DirectColorModel(24,
365 0x000000ff, // Red
366 0x0000ff00, // Green
367 0x00ff0000 // Blue
368 );
369 raster = colorModel.createCompatibleWritableRaster(width,
370 height);
371 }
372 break;
373
374 case TYPE_3BYTE_BGR:
375 {
376 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
377 int[] nBits = {8, 8, 8};
378 int[] bOffs = {2, 1, 0};
379 colorModel = new ComponentColorModel(cs, nBits, false, false,
380 Transparency.OPAQUE,
381 DataBuffer.TYPE_BYTE);
382 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
383 width, height,
384 width*3, 3,
385 bOffs, null);
386 }
387 break;
388
389 case TYPE_4BYTE_ABGR:
390 {
391 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
392 int[] nBits = {8, 8, 8, 8};
393 int[] bOffs = {3, 2, 1, 0};
394 colorModel = new ComponentColorModel(cs, nBits, true, false,
395 Transparency.TRANSLUCENT,
396 DataBuffer.TYPE_BYTE);
397 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
398 width, height,
399 width*4, 4,
400 bOffs, null);
401 }
402 break;
403
404 case TYPE_4BYTE_ABGR_PRE:
405 {
406 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_sRGB);
407 int[] nBits = {8, 8, 8, 8};
408 int[] bOffs = {3, 2, 1, 0};
409 colorModel = new ComponentColorModel(cs, nBits, true, true,
410 Transparency.TRANSLUCENT,
411 DataBuffer.TYPE_BYTE);
412 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
413 width, height,
414 width*4, 4,
415 bOffs, null);
416 }
417 break;
418
419 case TYPE_BYTE_GRAY:
420 {
421 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
422 int[] nBits = {8};
423 colorModel = new ComponentColorModel(cs, nBits, false, true,
424 Transparency.OPAQUE,
425 DataBuffer.TYPE_BYTE);
426 raster = colorModel.createCompatibleWritableRaster(width,
427 height);
428 }
429 break;
430
431 case TYPE_USHORT_GRAY:
432 {
433 ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
434 int[] nBits = {16};
435 colorModel = new ComponentColorModel(cs, nBits, false, true,
436 Transparency.OPAQUE,
437 DataBuffer.TYPE_USHORT);
438 raster = colorModel.createCompatibleWritableRaster(width,
439 height);
440 }
441 break;
442
443 case TYPE_BYTE_BINARY:
444 {
445 byte[] arr = {(byte)0, (byte)0xff};
446
447 colorModel = new IndexColorModel(1, 2, arr, arr, arr);
448 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
449 width, height, 1, 1, null);
450 }
451 break;
452
453 case TYPE_BYTE_INDEXED:
454 {
455 // Create a 6x6x6 color cube
456 int[] cmap = new int[256];
457 int i=0;
458 for (int r=0; r < 256; r += 51) {
459 for (int g=0; g < 256; g += 51) {
460 for (int b=0; b < 256; b += 51) {
461 cmap[i++] = (r<<16)|(g<<8)|b;
462 }
463 }
464 }
465 // And populate the rest of the cmap with gray values
466 int grayIncr = 256/(256-i);
467
468 // The gray ramp will be between 18 and 252
469 int gray = grayIncr*3;
470 for (; i < 256; i++) {
471 cmap[i] = (gray<<16)|(gray<<8)|gray;
472 gray += grayIncr;
473 }
474
475 colorModel = new IndexColorModel(8, 256, cmap, 0, false, -1,
476 DataBuffer.TYPE_BYTE);
477 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
478 width, height, 1, null);
479 }
480 break;
481
482 case TYPE_USHORT_565_RGB:
483 {
484 colorModel = new DirectColorModel(16,
485 DCM_565_RED_MASK,
486 DCM_565_GRN_MASK,
487 DCM_565_BLU_MASK
488 );
489 raster = colorModel.createCompatibleWritableRaster(width,
490 height);
491 }
492 break;
493
494 case TYPE_USHORT_555_RGB:
495 {
496 colorModel = new DirectColorModel(15,
497 DCM_555_RED_MASK,
498 DCM_555_GRN_MASK,
499 DCM_555_BLU_MASK
500 );
501 raster = colorModel.createCompatibleWritableRaster(width,
502 height);
503 }
504 break;
505
506 default:
507 throw new IllegalArgumentException ("Unknown image type " +
508 imageType);
509 }
510
511 this.imageType = imageType;
512 }
513
514 /**
515 * Constructs a <code>BufferedImage</code> of one of the predefined
516 * image types:
517 * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED.
518 *
519 * <p> If the image type is TYPE_BYTE_BINARY, the number of
520 * entries in the color model is used to determine whether the
521 * image should have 1, 2, or 4 bits per pixel. If the color model
522 * has 1 or 2 entries, the image will have 1 bit per pixel. If it
523 * has 3 or 4 entries, the image with have 2 bits per pixel. If
524 * it has between 5 and 16 entries, the image will have 4 bits per
525 * pixel. Otherwise, an IllegalArgumentException will be thrown.
526 *
527 * @param width width of the created image
528 * @param height height of the created image
529 * @param imageType type of the created image
530 * @param cm <code>IndexColorModel</code> of the created image
531 * @throws IllegalArgumentException if the imageType is not
532 * TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED or if the imageType is
533 * TYPE_BYTE_BINARY and the color map has more than 16 entries.
534 * @see #TYPE_BYTE_BINARY
535 * @see #TYPE_BYTE_INDEXED
536 */
537 public BufferedImage (int width,
538 int height,
539 int imageType,
540 IndexColorModel cm) {
541 if (cm.hasAlpha() && cm.isAlphaPremultiplied()) {
542 throw new IllegalArgumentException("This image types do not have "+
543 "premultiplied alpha.");
544 }
545
546 switch(imageType) {
547 case TYPE_BYTE_BINARY:
548 int bits; // Will be set below
549 int mapSize = cm.getMapSize();
550 if (mapSize <= 2) {
551 bits = 1;
552 } else if (mapSize <= 4) {
553 bits = 2;
554 } else if (mapSize <= 16) {
555 bits = 4;
556 } else {
557 throw new IllegalArgumentException
558 ("Color map for TYPE_BYTE_BINARY " +
559 "must have no more than 16 entries");
560 }
561 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE,
562 width, height, 1, bits, null);
563 break;
564
565 case TYPE_BYTE_INDEXED:
566 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE,
567 width, height, 1, null);
568 break;
569 default:
570 throw new IllegalArgumentException("Invalid image type (" +
571 imageType+"). Image type must"+
572 " be either TYPE_BYTE_BINARY or "+
573 " TYPE_BYTE_INDEXED");
574 }
575
576 if (!cm.isCompatibleRaster(raster)) {
577 throw new IllegalArgumentException("Incompatible image type and IndexColorModel");
578 }
579
580 colorModel = cm;
581 this.imageType = imageType;
582 }
583
584 /**
585 * Constructs a new <code>BufferedImage</code> with a specified
586 * <code>ColorModel</code> and <code>Raster</code>. If the number and
587 * types of bands in the <code>SampleModel</code> of the
588 * <code>Raster</code> do not match the number and types required by
589 * the <code>ColorModel</code> to represent its color and alpha
590 * components, a {@link RasterFormatException} is thrown. This
591 * method can multiply or divide the color <code>Raster</code> data by
592 * alpha to match the <code>alphaPremultiplied</code> state
593 * in the <code>ColorModel</code>. Properties for this
594 * <code>BufferedImage</code> can be established by passing
595 * in a {@link Hashtable} of <code>String</code>/<code>Object</code>
596 * pairs.
597 * @param cm <code>ColorModel</code> for the new image
598 * @param raster <code>Raster</code> for the image data
599 * @param isRasterPremultiplied if <code>true</code>, the data in
600 * the raster has been premultiplied with alpha.
601 * @param properties <code>Hashtable</code> of
602 * <code>String</code>/<code>Object</code> pairs.
603 * @exception <code>RasterFormatException</code> if the number and
604 * types of bands in the <code>SampleModel</code> of the
605 * <code>Raster</code> do not match the number and types required by
606 * the <code>ColorModel</code> to represent its color and alpha
607 * components.
608 * @exception <code>IllegalArgumentException</code> if
609 * <code>raster</code> is incompatible with <code>cm</code>
610 * @see ColorModel
611 * @see Raster
612 * @see WritableRaster
613 */
614
615
616/*
617 *
618 * FOR NOW THE CODE WHICH DEFINES THE RASTER TYPE IS DUPLICATED BY DVF
619 * SEE THE METHOD DEFINERASTERTYPE @ RASTEROUTPUTMANAGER
620 *
621 */
622 public BufferedImage (ColorModel cm,
623 WritableRaster raster,
624 boolean isRasterPremultiplied,
625 Hashtable<?,?> properties) {
626
627 if (!cm.isCompatibleRaster(raster)) {
628 throw new
629 IllegalArgumentException("Raster "+raster+
630 " is incompatible with ColorModel "+
631 cm);
632 }
633
634 if ((raster.minX != 0) || (raster.minY != 0)) {
635 throw new
636 IllegalArgumentException("Raster "+raster+
637 " has minX or minY not equal to zero: "
638 + raster.minX + " " + raster.minY);
639 }
640
641 colorModel = cm;
642 this.raster = raster;
643 this.properties = properties;
644 int numBands = raster.getNumBands();
645 boolean isAlphaPre = cm.isAlphaPremultiplied();
646 ColorSpace cs;
647
648 // Force the raster data alpha state to match the premultiplied
649 // state in the color model
650 coerceData(isRasterPremultiplied);
651
652 SampleModel sm = raster.getSampleModel();
653 cs = cm.getColorSpace();
654 int csType = cs.getType();
655 if (csType != ColorSpace.TYPE_RGB) {
656 if (csType == ColorSpace.TYPE_GRAY
657 && cm instanceof ComponentColorModel) {
658 // Check if this might be a child raster (fix for bug 4240596)
659 if (sm instanceof ComponentSampleModel &&
660 ((ComponentSampleModel)sm).getPixelStride() != numBands) {
661 imageType = TYPE_CUSTOM;
662 } else if (raster instanceof ByteComponentRaster &&
663 raster.getNumBands() == 1 &&
664 cm.getComponentSize(0) == 8 &&
665 ((ByteComponentRaster)raster).getPixelStride() == 1) {
666 imageType = TYPE_BYTE_GRAY;
667 } else if (raster instanceof ShortComponentRaster &&
668 raster.getNumBands() == 1 &&
669 cm.getComponentSize(0) == 16 &&
670 ((ShortComponentRaster)raster).getPixelStride() == 1) {
671 imageType = TYPE_USHORT_GRAY;
672 }
673 } else {
674 imageType = TYPE_CUSTOM;
675 }
676 return;
677 }
678
679 if ((raster instanceof IntegerComponentRaster) &&
680 (numBands == 3 || numBands == 4)) {
681 IntegerComponentRaster iraster =
682 (IntegerComponentRaster) raster;
683 // Check if the raster params and the color model
684 // are correct
685 int pixSize = cm.getPixelSize();
686 if (iraster.getPixelStride() == 1 &&
687 cm instanceof DirectColorModel &&
688 (pixSize == 32 || pixSize == 24))
689 {
690 // Now check on the DirectColorModel params
691 DirectColorModel dcm = (DirectColorModel) cm;
692 int rmask = dcm.getRedMask();
693 int gmask = dcm.getGreenMask();
694 int bmask = dcm.getBlueMask();
695 if (rmask == DCM_RED_MASK && gmask == DCM_GREEN_MASK &&
696 bmask == DCM_BLUE_MASK)
697 {
698 if (dcm.getAlphaMask() == DCM_ALPHA_MASK) {
699 imageType = (isAlphaPre
700 ? TYPE_INT_ARGB_PRE
701 : TYPE_INT_ARGB);
702 }
703 else {
704 // No Alpha
705 if (!dcm.hasAlpha()) {
706 imageType = TYPE_INT_RGB;
707 }
708 }
709 } // if (dcm.getRedMask() == DCM_RED_MASK &&
710 else if (rmask == DCM_BGR_RED_MASK && gmask == DCM_BGR_GRN_MASK
711 && bmask == DCM_BGR_BLU_MASK) {
712 if (!dcm.hasAlpha()) {
713 imageType = TYPE_INT_BGR;
714 }
715 } // if (rmask == DCM_BGR_RED_MASK &&
716 } // if (iraster.getPixelStride() == 1
717 } // ((raster instanceof IntegerComponentRaster) &&
718 else if ((cm instanceof IndexColorModel) && (numBands == 1) &&
719 (!cm.hasAlpha() || !isAlphaPre))
720 {
721 IndexColorModel icm = (IndexColorModel) cm;
722 int pixSize = icm.getPixelSize();
723
724 if (raster instanceof BytePackedRaster) {
725 imageType = TYPE_BYTE_BINARY;
726 } // if (raster instanceof BytePackedRaster)
727 else if (raster instanceof ByteComponentRaster) {
728 ByteComponentRaster braster = (ByteComponentRaster) raster;
729 if (braster.getPixelStride() == 1 && pixSize <= 8) {
730 imageType = TYPE_BYTE_INDEXED;
731 }
732 }
733 } // else if (cm instanceof IndexColorModel) && (numBands == 1))
734 else if ((raster instanceof ShortComponentRaster)
735 && (cm instanceof DirectColorModel)
736 && (numBands == 3)
737 && !cm.hasAlpha())
738 {
739 DirectColorModel dcm = (DirectColorModel) cm;
740 if (dcm.getRedMask() == DCM_565_RED_MASK) {
741 if (dcm.getGreenMask() == DCM_565_GRN_MASK &&
742 dcm.getBlueMask() == DCM_565_BLU_MASK) {
743 imageType = TYPE_USHORT_565_RGB;
744 }
745 }
746 else if (dcm.getRedMask() == DCM_555_RED_MASK) {
747 if (dcm.getGreenMask() == DCM_555_GRN_MASK &&
748 dcm.getBlueMask() == DCM_555_BLU_MASK) {
749 imageType = TYPE_USHORT_555_RGB;
750 }
751 }
752 } // else if ((cm instanceof IndexColorModel) && (numBands == 1))
753 else if ((raster instanceof ByteComponentRaster)
754 && (cm instanceof ComponentColorModel)
755 && (raster.getSampleModel() instanceof PixelInterleavedSampleModel)
756 && (numBands == 3 || numBands == 4))
757 {
758 ComponentColorModel ccm = (ComponentColorModel) cm;
759 PixelInterleavedSampleModel csm =
760 (PixelInterleavedSampleModel)raster.getSampleModel();
761 ByteComponentRaster braster = (ByteComponentRaster) raster;
762 int[] offs = csm.getBandOffsets();
763 if (ccm.getNumComponents() != numBands) {
764 throw new RasterFormatException("Number of components in "+
765 "ColorModel ("+
766 ccm.getNumComponents()+
767 ") does not match # in "+
768 " Raster ("+numBands+")");
769 }
770 int[] nBits = ccm.getComponentSize();
771 boolean is8bit = true;
772 for (int i=0; i < numBands; i++) {
773 if (nBits[i] != 8) {
774 is8bit = false;
775 break;
776 }
777 }
778 if (is8bit &&
779 offs[0] == numBands-1 &&
780 offs[1] == numBands-2 &&
781 offs[2] == numBands-3)
782 {
783 if (numBands == 3) {
784 imageType = TYPE_3BYTE_BGR;
785 }
786 else if (offs[3] == 0) {
787 imageType = (isAlphaPre
788 ? TYPE_4BYTE_ABGR_PRE
789 : TYPE_4BYTE_ABGR);
790 }
791 }
792 } // else if ((raster instanceof ByteComponentRaster) &&
793 }
794
795 /**
796 * Returns the image type. If it is not one of the known types,
797 * TYPE_CUSTOM is returned.
798 * @return the image type of this <code>BufferedImage</code>.
799 * @see #TYPE_INT_RGB
800 * @see #TYPE_INT_ARGB
801 * @see #TYPE_INT_ARGB_PRE
802 * @see #TYPE_INT_BGR
803 * @see #TYPE_3BYTE_BGR
804 * @see #TYPE_4BYTE_ABGR
805 * @see #TYPE_4BYTE_ABGR_PRE
806 * @see #TYPE_BYTE_GRAY
807 * @see #TYPE_BYTE_BINARY
808 * @see #TYPE_BYTE_INDEXED
809 * @see #TYPE_USHORT_GRAY
810 * @see #TYPE_USHORT_565_RGB
811 * @see #TYPE_USHORT_555_RGB
812 * @see #TYPE_CUSTOM
813 */
814 public int getType() {
815 return imageType;
816 }
817
818 /**
819 * Returns the <code>ColorModel</code>.
820 * @return the <code>ColorModel</code> of this
821 * <code>BufferedImage</code>.
822 */
823 public ColorModel getColorModel() {
824 return colorModel;
825 }
826
827 /**
828 * Returns the {@link WritableRaster}.
829 * @return the <code>WriteableRaster</code> of this
830 * <code>BufferedImage</code>.
831 */
832 public WritableRaster getRaster() {
833 return raster;
834 }
835
836
837 /**
838 * Returns a <code>WritableRaster</code> representing the alpha
839 * channel for <code>BufferedImage</code> objects
840 * with <code>ColorModel</code> objects that support a separate
841 * spatial alpha channel, such as <code>ComponentColorModel</code> and
842 * <code>DirectColorModel</code>. Returns <code>null</code> if there
843 * is no alpha channel associated with the <code>ColorModel</code> in
844 * this image. This method assumes that for all
845 * <code>ColorModel</code> objects other than
846 * <code>IndexColorModel</code>, if the <code>ColorModel</code>
847 * supports alpha, there is a separate alpha channel
848 * which is stored as the last band of image data.
849 * If the image uses an <code>IndexColorModel</code> that
850 * has alpha in the lookup table, this method returns
851 * <code>null</code> since there is no spatially discrete alpha
852 * channel. This method creates a new
853 * <code>WritableRaster</code>, but shares the data array.
854 * @return a <code>WritableRaster</code> or <code>null</code> if this
855 * <code>BufferedImage</code> has no alpha channel associated
856 * with its <code>ColorModel</code>.
857 */
858 public WritableRaster getAlphaRaster() {
859 return colorModel.getAlphaRaster(raster);
860 }
861
862 /**
863 * Returns an integer pixel in the default RGB color model
864 * (TYPE_INT_ARGB) and default sRGB colorspace. Color
865 * conversion takes place if this default model does not match
866 * the image <code>ColorModel</code>. There are only 8-bits of
867 * precision for each color component in the returned data when using
868 * this method.
869 *
870 * <p>
871 *
872 * An <code>ArrayOutOfBoundsException</code> may be thrown
873 * if the coordinates are not in bounds.
874 * However, explicit bounds checking is not guaranteed.
875 *
876 * @param x the X coordinate of the pixel from which to get
877 * the pixel in the default RGB color model and sRGB
878 * color space
879 * @param y the Y coordinate of the pixel from which to get
880 * the pixel in the default RGB color model and sRGB
881 * color space
882 * @return an integer pixel in the default RGB color model and
883 * default sRGB colorspace.
884 * @see #setRGB(int, int, int)
885 * @see #setRGB(int, int, int, int, int[], int, int)
886 */
887 public int getRGB(int x, int y) {
888 return colorModel.getRGB(raster.getDataElements(x, y, null));
889 }
890
891 /**
892 * Returns an array of integer pixels in the default RGB color model
893 * (TYPE_INT_ARGB) and default sRGB color space,
894 * from a portion of the image data. Color conversion takes
895 * place if the default model does not match the image
896 * <code>ColorModel</code>. There are only 8-bits of precision for
897 * each color component in the returned data when
898 * using this method. With a specified coordinate (x,&nbsp;y) in the
899 * image, the ARGB pixel can be accessed in this way:
900 * </p>
901 *
902 * <pre>
903 * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]; </pre>
904 *
905 * <p>
906 *
907 * An <code>ArrayOutOfBoundsException</code> may be thrown
908 * if the region is not in bounds.
909 * However, explicit bounds checking is not guaranteed.
910 *
911 * @param startX the starting X coordinate
912 * @param startY the starting Y coordinate
913 * @param w width of region
914 * @param h height of region
915 * @param rgbArray if not <code>null</code>, the rgb pixels are
916 * written here
917 * @param offset offset into the <code>rgbArray</code>
918 * @param scansize scanline stride for the <code>rgbArray</code>
919 * @return array of RGB pixels.
920 * @see #setRGB(int, int, int)
921 * @see #setRGB(int, int, int, int, int[], int, int)
922 */
923 public int[] getRGB(int startX, int startY, int w, int h,
924 int[] rgbArray, int offset, int scansize) {
925 int yoff = offset;
926 int off;
927 Object data;
928 int nbands = raster.getNumBands();
929 int dataType = raster.getDataBuffer().getDataType();
930 switch (dataType) {
931 case DataBuffer.TYPE_BYTE:
932 data = new byte[nbands];
933 break;
934 case DataBuffer.TYPE_USHORT:
935 data = new short[nbands];
936 break;
937 case DataBuffer.TYPE_INT:
938 data = new int[nbands];
939 break;
940 case DataBuffer.TYPE_FLOAT:
941 data = new float[nbands];
942 break;
943 case DataBuffer.TYPE_DOUBLE:
944 data = new double[nbands];
945 break;
946 default:
947 throw new IllegalArgumentException("Unknown data buffer type: "+
948 dataType);
949 }
950
951 if (rgbArray == null) {
952 rgbArray = new int[offset+h*scansize];
953 }
954
955 for (int y = startY; y < startY+h; y++, yoff+=scansize) {
956 off = yoff;
957 for (int x = startX; x < startX+w; x++) {
958 rgbArray[off++] = colorModel.getRGB(raster.getDataElements(x,
959 y,
960 data));
961 }
962 }
963
964 return rgbArray;
965 }
966
967
968 /**
969 * Sets a pixel in this <code>BufferedImage</code> to the specified
970 * RGB value. The pixel is assumed to be in the default RGB color
971 * model, TYPE_INT_ARGB, and default sRGB color space. For images
972 * with an <code>IndexColorModel</code>, the index with the nearest
973 * color is chosen.
974 *
975 * <p>
976 *
977 * An <code>ArrayOutOfBoundsException</code> may be thrown
978 * if the coordinates are not in bounds.
979 * However, explicit bounds checking is not guaranteed.
980 *
981 * @param x the X coordinate of the pixel to set
982 * @param y the Y coordinate of the pixel to set
983 * @param rgb the RGB value
984 * @see #getRGB(int, int)
985 * @see #getRGB(int, int, int, int, int[], int, int)
986 */
987 public synchronized void setRGB(int x, int y, int rgb) {
988 raster.setDataElements(x, y, colorModel.getDataElements(rgb, null));
989 }
990
991 /**
992 * Sets an array of integer pixels in the default RGB color model
993 * (TYPE_INT_ARGB) and default sRGB color space,
994 * into a portion of the image data. Color conversion takes place
995 * if the default model does not match the image
996 * <code>ColorModel</code>. There are only 8-bits of precision for
997 * each color component in the returned data when
998 * using this method. With a specified coordinate (x,&nbsp;y) in the
999 * this image, the ARGB pixel can be accessed in this way:
1000 * <pre>
1001 * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)];
1002 * </pre>
1003 * WARNING: No dithering takes place.
1004 *
1005 * <p>
1006 *
1007 * An <code>ArrayOutOfBoundsException</code> may be thrown
1008 * if the region is not in bounds.
1009 * However, explicit bounds checking is not guaranteed.
1010 *
1011 * @param startX the starting X coordinate
1012 * @param startY the starting Y coordinate
1013 * @param w width of the region
1014 * @param h height of the region
1015 * @param rgbArray the rgb pixels
1016 * @param offset offset into the <code>rgbArray</code>
1017 * @param scansize scanline stride for the <code>rgbArray</code>
1018 * @see #getRGB(int, int)
1019 * @see #getRGB(int, int, int, int, int[], int, int)
1020 */
1021 public void setRGB(int startX, int startY, int w, int h,
1022 int[] rgbArray, int offset, int scansize) {
1023 int yoff = offset;
1024 int off;
1025 Object pixel = null;
1026
1027 for (int y = startY; y < startY+h; y++, yoff+=scansize) {
1028 off = yoff;
1029 for (int x = startX; x < startX+w; x++) {
1030 pixel = colorModel.getDataElements(rgbArray[off++], pixel);
1031 raster.setDataElements(x, y, pixel);
1032 }
1033 }
1034 }
1035
1036
1037 /**
1038 * Returns the width of the <code>BufferedImage</code>.
1039 * @return the width of this <code>BufferedImage</code>
1040 */
1041 public int getWidth() {
1042 return raster.getWidth();
1043 }
1044
1045 /**
1046 * Returns the height of the <code>BufferedImage</code>.
1047 * @return the height of this <code>BufferedImage</code>
1048 */
1049 public int getHeight() {
1050 return raster.getHeight();
1051 }
1052
1053 /**
1054 * Returns the width of the <code>BufferedImage</code>.
1055 * @param observer ignored
1056 * @return the width of this <code>BufferedImage</code>
1057 */
1058 public int getWidth(ImageObserver observer) {
1059 return raster.getWidth();
1060 }
1061
1062 /**
1063 * Returns the height of the <code>BufferedImage</code>.
1064 * @param observer ignored
1065 * @return the height of this <code>BufferedImage</code>
1066 */
1067 public int getHeight(ImageObserver observer) {
1068 return raster.getHeight();
1069 }
1070
1071 /**
1072 * Returns the object that produces the pixels for the image.
1073 * @return the {@link ImageProducer} that is used to produce the
1074 * pixels for this image.
1075 * @see ImageProducer
1076 */
1077 public ImageProducer getSource() {
1078 if (osis == null) {
1079 if (properties == null) {
1080 properties = new Hashtable();
1081 }
1082 osis = new OffScreenImageSource(this, properties);
1083 }
1084 return osis;
1085 }
1086
1087
1088 /**
1089 * Returns a property of the image by name. Individual property names
1090 * are defined by the various image formats. If a property is not
1091 * defined for a particular image, this method returns the
1092 * <code>UndefinedProperty</code> field. If the properties
1093 * for this image are not yet known, then this method returns
1094 * <code>null</code> and the <code>ImageObserver</code> object is
1095 * notified later. The property name "comment" should be used to
1096 * store an optional comment that can be presented to the user as a
1097 * description of the image, its source, or its author.
1098 * @param name the property name
1099 * @param observer the <code>ImageObserver</code> that receives
1100 * notification regarding image information
1101 * @return an {@link Object} that is the property referred to by the
1102 * specified <code>name</code> or <code>null</code> if the
1103 * properties of this image are not yet known.
1104 * @throws <code>NullPointerException</code> if the property name is null.
1105 * @see ImageObserver
1106 * @see java.awt.Image#UndefinedProperty
1107 */
1108 public Object getProperty(String name, ImageObserver observer) {
1109 return getProperty(name);
1110 }
1111
1112 /**
1113 * Returns a property of the image by name.
1114 * @param name the property name
1115 * @return an <code>Object</code> that is the property referred to by
1116 * the specified <code>name</code>.
1117 * @throws <code>NullPointerException</code> if the property name is null.
1118 */
1119 public Object getProperty(String name) {
1120 if (name == null) {
1121 throw new NullPointerException("null property name is not allowed");
1122 }
1123 if (properties == null) {
1124 return java.awt.Image.UndefinedProperty;
1125 }
1126 Object o = properties.get(name);
1127 if (o == null) {
1128 o = java.awt.Image.UndefinedProperty;
1129 }
1130 return o;
1131 }
1132
1133 /**
1134 * This method returns a {@link Graphics2D}, but is here
1135 * for backwards compatibility. {@link #createGraphics() createGraphics} is more
1136 * convenient, since it is declared to return a
1137 * <code>Graphics2D</code>.
1138 * @return a <code>Graphics2D</code>, which can be used to draw into
1139 * this image.
1140 */
1141 public java.awt.Graphics getGraphics() {
1142 return createGraphics();
1143 }
1144
1145 /**
1146 * Creates a <code>Graphics2D</code>, which can be used to draw into
1147 * this <code>BufferedImage</code>.
1148 * @return a <code>Graphics2D</code>, used for drawing into this
1149 * image.
1150 */
1151 public Graphics2D createGraphics() {
1152 GraphicsEnvironment env =
1153 GraphicsEnvironment.getLocalGraphicsEnvironment();
1154 return env.createGraphics(this);
1155 }
1156
1157 /**
1158 * Returns a subimage defined by a specified rectangular region.
1159 * The returned <code>BufferedImage</code> shares the same
1160 * data array as the original image.
1161 * @param x the X coordinate of the upper-left corner of the
1162 * specified rectangular region
1163 * @param y the Y coordinate of the upper-left corner of the
1164 * specified rectangular region
1165 * @param w the width of the specified rectangular region
1166 * @param h the height of the specified rectangular region
1167 * @return a <code>BufferedImage</code> that is the subimage of this
1168 * <code>BufferedImage</code>.
1169 * @exception <code>RasterFormatException</code> if the specified
1170 * area is not contained within this <code>BufferedImage</code>.
1171 */
1172 public BufferedImage getSubimage (int x, int y, int w, int h) {
1173 return new BufferedImage (colorModel,
1174 raster.createWritableChild(x, y, w, h,
1175 0, 0, null),
1176 colorModel.isAlphaPremultiplied(),
1177 properties);
1178 }
1179
1180 /**
1181 * Returns whether or not the alpha has been premultiplied. It
1182 * returns <code>false</code> if there is no alpha.
1183 * @return <code>true</code> if the alpha has been premultiplied;
1184 * <code>false</code> otherwise.
1185 */
1186 public boolean isAlphaPremultiplied() {
1187 return colorModel.isAlphaPremultiplied();
1188 }
1189
1190 /**
1191 * Forces the data to match the state specified in the
1192 * <code>isAlphaPremultiplied</code> variable. It may multiply or
1193 * divide the color raster data by alpha, or do nothing if the data is
1194 * in the correct state.
1195 * @param isAlphaPremultiplied <code>true</code> if the alpha has been
1196 * premultiplied; <code>false</code> otherwise.
1197 */
1198 public void coerceData (boolean isAlphaPremultiplied) {
1199 if (colorModel.hasAlpha() &&
1200 colorModel.isAlphaPremultiplied() != isAlphaPremultiplied) {
1201 // Make the color model do the conversion
1202 colorModel = colorModel.coerceData (raster, isAlphaPremultiplied);
1203 }
1204 }
1205
1206 /**
1207 * Returns a <code>String</code> representation of this
1208 * <code>BufferedImage</code> object and its values.
1209 * @return a <code>String</code> representing this
1210 * <code>BufferedImage</code>.
1211 */
1212 public String toString() {
1213 return new String("BufferedImage@"+Integer.toHexString(hashCode())
1214 +": type = "+imageType
1215 +" "+colorModel+" "+raster);
1216 }
1217
1218 /**
1219 * Returns a {@link Vector} of {@link RenderedImage} objects that are
1220 * the immediate sources, not the sources of these immediate sources,
1221 * of image data for this <code>BufferedImage</code>. This
1222 * method returns <code>null</code> if the <code>BufferedImage</code>
1223 * has no information about its immediate sources. It returns an
1224 * empty <code>Vector</code> if the <code>BufferedImage</code> has no
1225 * immediate sources.
1226 * @return a <code>Vector</code> containing immediate sources of
1227 * this <code>BufferedImage</code> object's image date, or
1228 * <code>null</code> if this <code>BufferedImage</code> has
1229 * no information about its immediate sources, or an empty
1230 * <code>Vector</code> if this <code>BufferedImage</code>
1231 * has no immediate sources.
1232 */
1233 public Vector<RenderedImage> getSources() {
1234 return null;
1235 }
1236
1237 /**
1238 * Returns an array of names recognized by
1239 * {@link #getProperty(String) getProperty(String)}
1240 * or <code>null</code>, if no property names are recognized.
1241 * @return a <code>String</code> array containing all of the property
1242 * names that <code>getProperty(String)</code> recognizes;
1243 * or <code>null</code> if no property names are recognized.
1244 */
1245 public String[] getPropertyNames() {
1246 return null;
1247 }
1248
1249 /**
1250 * Returns the minimum x coordinate of this
1251 * <code>BufferedImage</code>. This is always zero.
1252 * @return the minimum x coordinate of this
1253 * <code>BufferedImage</code>.
1254 */
1255 public int getMinX() {
1256 return raster.getMinX();
1257 }
1258
1259 /**
1260 * Returns the minimum y coordinate of this
1261 * <code>BufferedImage</code>. This is always zero.
1262 * @return the minimum y coordinate of this
1263 * <code>BufferedImage</code>.
1264 */
1265 public int getMinY() {
1266 return raster.getMinY();
1267 }
1268
1269 /**
1270 * Returns the <code>SampleModel</code> associated with this
1271 * <code>BufferedImage</code>.
1272 * @return the <code>SampleModel</code> of this
1273 * <code>BufferedImage</code>.
1274 */
1275 public SampleModel getSampleModel() {
1276 return raster.getSampleModel();
1277 }
1278
1279 /**
1280 * Returns the number of tiles in the x direction.
1281 * This is always one.
1282 * @return the number of tiles in the x direction.
1283 */
1284 public int getNumXTiles() {
1285 return 1;
1286 }
1287
1288 /**
1289 * Returns the number of tiles in the y direction.
1290 * This is always one.
1291 * @return the number of tiles in the y direction.
1292 */
1293 public int getNumYTiles() {
1294 return 1;
1295 }
1296
1297 /**
1298 * Returns the minimum tile index in the x direction.
1299 * This is always zero.
1300 * @return the minimum tile index in the x direction.
1301 */
1302 public int getMinTileX() {
1303 return 0;
1304 }
1305
1306 /**
1307 * Returns the minimum tile index in the y direction.
1308 * This is always zero.
1309 * @return the mininum tile index in the y direction.
1310 */
1311 public int getMinTileY() {
1312 return 0;
1313 }
1314
1315 /**
1316 * Returns the tile width in pixels.
1317 * @return the tile width in pixels.
1318 */
1319 public int getTileWidth() {
1320 return raster.getWidth();
1321 }
1322
1323 /**
1324 * Returns the tile height in pixels.
1325 * @return the tile height in pixels.
1326 */
1327 public int getTileHeight() {
1328 return raster.getHeight();
1329 }
1330
1331 /**
1332 * Returns the x offset of the tile grid relative to the origin,
1333 * For example, the x coordinate of the location of tile
1334 * (0,&nbsp;0). This is always zero.
1335 * @return the x offset of the tile grid.
1336 */
1337 public int getTileGridXOffset() {
1338 return raster.getSampleModelTranslateX();
1339 }
1340
1341 /**
1342 * Returns the y offset of the tile grid relative to the origin,
1343 * For example, the y coordinate of the location of tile
1344 * (0,&nbsp;0). This is always zero.
1345 * @return the y offset of the tile grid.
1346 */
1347 public int getTileGridYOffset() {
1348 return raster.getSampleModelTranslateY();
1349 }
1350
1351 /**
1352 * Returns tile (<code>tileX</code>,&nbsp;<code>tileY</code>). Note
1353 * that <code>tileX</code> and <code>tileY</code> are indices
1354 * into the tile array, not pixel locations. The <code>Raster</code>
1355 * that is returned is live, which means that it is updated if the
1356 * image is changed.
1357 * @param tileX the x index of the requested tile in the tile array
1358 * @param tileY the y index of the requested tile in the tile array
1359 * @return a <code>Raster</code> that is the tile defined by the
1360 * arguments <code>tileX</code> and <code>tileY</code>.
1361 * @exception <code>ArrayIndexOutOfBoundsException</code> if both
1362 * <code>tileX</code> and <code>tileY</code> are not
1363 * equal to 0
1364 */
1365 public Raster getTile(int tileX, int tileY) {
1366 if (tileX == 0 && tileY == 0) {
1367 return raster;
1368 }
1369 throw new ArrayIndexOutOfBoundsException("BufferedImages only have"+
1370 " one tile with index 0,0");
1371 }
1372
1373 /**
1374 * Returns the image as one large tile. The <code>Raster</code>
1375 * returned is a copy of the image data is not updated if the
1376 * image is changed.
1377 * @return a <code>Raster</code> that is a copy of the image data.
1378 * @see #setData(Raster)
1379 */
1380 public Raster getData() {
1381
1382 // REMIND : this allocates a whole new tile if raster is a
1383 // subtile. (It only copies in the requested area)
1384 // We should do something smarter.
1385 int width = raster.getWidth();
1386 int height = raster.getHeight();
1387 int startX = raster.getMinX();
1388 int startY = raster.getMinY();
1389 WritableRaster wr =
1390 Raster.createWritableRaster(raster.getSampleModel(),
1391 new Point(raster.getSampleModelTranslateX(),
1392 raster.getSampleModelTranslateY()));
1393
1394 Object tdata = null;
1395
1396 for (int i = startY; i < startY+height; i++) {
1397 tdata = raster.getDataElements(startX,i,width,1,tdata);
1398 wr.setDataElements(startX,i,width,1, tdata);
1399 }
1400 return wr;
1401 }
1402
1403 /**
1404 * Computes and returns an arbitrary region of the
1405 * <code>BufferedImage</code>. The <code>Raster</code> returned is a
1406 * copy of the image data and is not updated if the image is
1407 * changed.
1408 * @param rect the region of the <code>BufferedImage</code> to be
1409 * returned.
1410 * @return a <code>Raster</code> that is a copy of the image data of
1411 * the specified region of the <code>BufferedImage</code>
1412 * @see #setData(Raster)
1413 */
1414 public Raster getData(Rectangle rect) {
1415 SampleModel sm = raster.getSampleModel();
1416 SampleModel nsm = sm.createCompatibleSampleModel(rect.width,
1417 rect.height);
1418 WritableRaster wr = Raster.createWritableRaster(nsm,
1419 rect.getLocation());
1420 int width = rect.width;
1421 int height = rect.height;
1422 int startX = rect.x;
1423 int startY = rect.y;
1424
1425 Object tdata = null;
1426
1427 for (int i = startY; i < startY+height; i++) {
1428 tdata = raster.getDataElements(startX,i,width,1,tdata);
1429 wr.setDataElements(startX,i,width,1, tdata);
1430 }
1431 return wr;
1432 }
1433
1434 /**
1435 * Computes an arbitrary rectangular region of the
1436 * <code>BufferedImage</code> and copies it into a specified
1437 * <code>WritableRaster</code>. The region to be computed is
1438 * determined from the bounds of the specified
1439 * <code>WritableRaster</code>. The specified
1440 * <code>WritableRaster</code> must have a
1441 * <code>SampleModel</code> that is compatible with this image. If
1442 * <code>outRaster</code> is <code>null</code>,
1443 * an appropriate <code>WritableRaster</code> is created.
1444 * @param outRaster a <code>WritableRaster</code> to hold the returned
1445 * part of the image, or <code>null</code>
1446 * @return a reference to the supplied or created
1447 * <code>WritableRaster</code>.
1448 */
1449 public WritableRaster copyData(WritableRaster outRaster) {
1450 if (outRaster == null) {
1451 return (WritableRaster) getData();
1452 }
1453 int width = outRaster.getWidth();
1454 int height = outRaster.getHeight();
1455 int startX = outRaster.getMinX();
1456 int startY = outRaster.getMinY();
1457
1458 Object tdata = null;
1459
1460 for (int i = startY; i < startY+height; i++) {
1461 tdata = raster.getDataElements(startX,i,width,1,tdata);
1462 outRaster.setDataElements(startX,i,width,1, tdata);
1463 }
1464
1465 return outRaster;
1466 }
1467
1468 /**
1469 * Sets a rectangular region of the image to the contents of the
1470 * specified <code>Raster</code> <code>r</code>, which is
1471 * assumed to be in the same coordinate space as the
1472 * <code>BufferedImage</code>. The operation is clipped to the bounds
1473 * of the <code>BufferedImage</code>.
1474 * @param r the specified <code>Raster</code>
1475 * @see #getData
1476 * @see #getData(Rectangle)
1477 */
1478 public void setData(Raster r) {
1479 int width = r.getWidth();
1480 int height = r.getHeight();
1481 int startX = r.getMinX();
1482 int startY = r.getMinY();
1483
1484 int[] tdata = null;
1485
1486 // Clip to the current Raster
1487 Rectangle rclip = new Rectangle(startX, startY, width, height);
1488 Rectangle bclip = new Rectangle(0, 0, raster.width, raster.height);
1489 Rectangle intersect = rclip.intersection(bclip);
1490 if (intersect.isEmpty()) {
1491 return;
1492 }
1493 width = intersect.width;
1494 height = intersect.height;
1495 startX = intersect.x;
1496 startY = intersect.y;
1497
1498 // remind use get/setDataElements for speed if Rasters are
1499 // compatible
1500 for (int i = startY; i < startY+height; i++) {
1501 tdata = r.getPixels(startX,i,width,1,tdata);
1502 raster.setPixels(startX,i,width,1, tdata);
1503 }
1504 }
1505
1506
1507 /**
1508 * Adds a tile observer. If the observer is already present,
1509 * it receives multiple notifications.
1510 * @param to the specified {@link TileObserver}
1511 */
1512 public void addTileObserver (TileObserver to) {
1513 }
1514
1515 /**
1516 * Removes a tile observer. If the observer was not registered,
1517 * nothing happens. If the observer was registered for multiple
1518 * notifications, it is now registered for one fewer notification.
1519 * @param to the specified <code>TileObserver</code>.
1520 */
1521 public void removeTileObserver (TileObserver to) {
1522 }
1523
1524 /**
1525 * Returns whether or not a tile is currently checked out for writing.
1526 * @param tileX the x index of the tile.
1527 * @param tileY the y index of the tile.
1528 * @return <code>true</code> if the tile specified by the specified
1529 * indices is checked out for writing; <code>false</code>
1530 * otherwise.
1531 * @exception <code>ArrayIndexOutOfBoundsException</code> if both
1532 * <code>tileX</code> and <code>tileY</code> are not equal
1533 * to 0
1534 */
1535 public boolean isTileWritable (int tileX, int tileY) {
1536 if (tileX == 0 && tileY == 0) {
1537 return true;
1538 }
1539 throw new IllegalArgumentException("Only 1 tile in image");
1540 }
1541
1542 /**
1543 * Returns an array of {@link Point} objects indicating which tiles
1544 * are checked out for writing. Returns <code>null</code> if none are
1545 * checked out.
1546 * @return a <code>Point</code> array that indicates the tiles that
1547 * are checked out for writing, or <code>null</code> if no
1548 * tiles are checked out for writing.
1549 */
1550 public Point[] getWritableTileIndices() {
1551 Point[] p = new Point[1];
1552 p[0] = new Point(0, 0);
1553
1554 return p;
1555 }
1556
1557 /**
1558 * Returns whether or not any tile is checked out for writing.
1559 * Semantically equivalent to
1560 * <pre>
1561 * (getWritableTileIndices() != null).
1562 * </pre>
1563 * @return <code>true</code> if any tile is checked out for writing;
1564 * <code>false</code> otherwise.
1565 */
1566 public boolean hasTileWriters () {
1567 return true;
1568 }
1569
1570 /**
1571 * Checks out a tile for writing. All registered
1572 * <code>TileObservers</code> are notified when a tile goes from having
1573 * no writers to having one writer.
1574 * @param tileX the x index of the tile
1575 * @param tileY the y index of the tile
1576 * @return a <code>WritableRaster</code> that is the tile, indicated by
1577 * the specified indices, to be checked out for writing.
1578 */
1579 public WritableRaster getWritableTile (int tileX, int tileY) {
1580 return raster;
1581 }
1582
1583 /**
1584 * Relinquishes permission to write to a tile. If the caller
1585 * continues to write to the tile, the results are undefined.
1586 * Calls to this method should only appear in matching pairs
1587 * with calls to {@link #getWritableTile(int, int) getWritableTile(int, int)}. Any other leads
1588 * to undefined results. All registered <code>TileObservers</code>
1589 * are notified when a tile goes from having one writer to having no
1590 * writers.
1591 * @param tileX the x index of the tile
1592 * @param tileY the y index of the tile
1593 */
1594 public void releaseWritableTile (int tileX, int tileY) {
1595 }
1596
1597 /**
1598 * Returns the transparency. Returns either OPAQUE, BITMASK,
1599 * or TRANSLUCENT.
1600 * @return the transparency of this <code>BufferedImage</code>.
1601 * @see Transparency#OPAQUE
1602 * @see Transparency#BITMASK
1603 * @see Transparency#TRANSLUCENT
1604 * @since 1.5
1605 */
1606 public int getTransparency() {
1607 return colorModel.getTransparency();
1608 }
1609}