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