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