Home | History | Annotate | Download | only in image
      1 /*
      2  *  Licensed to the Apache Software Foundation (ASF) under one or more
      3  *  contributor license agreements.  See the NOTICE file distributed with
      4  *  this work for additional information regarding copyright ownership.
      5  *  The ASF licenses this file to You under the Apache License, Version 2.0
      6  *  (the "License"); you may not use this file except in compliance with
      7  *  the License.  You may obtain a copy of the License at
      8  *
      9  *     http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  *  Unless required by applicable law or agreed to in writing, software
     12  *  distributed under the License is distributed on an "AS IS" BASIS,
     13  *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  *  See the License for the specific language governing permissions and
     15  *  limitations under the License.
     16  */
     17 /**
     18  * @author Igor V. Stolyarov
     19  * @version $Revision$
     20  */
     21 
     22 package java.awt.image;
     23 
     24 import com.android.internal.awt.AndroidGraphics2D;
     25 
     26 import java.awt.Graphics;
     27 import java.awt.Graphics2D;
     28 import java.awt.GraphicsEnvironment;
     29 import java.awt.Image;
     30 import java.awt.Point;
     31 import java.awt.Rectangle;
     32 import java.awt.Transparency;
     33 import java.awt.color.ColorSpace;
     34 import java.util.Enumeration;
     35 import java.util.Hashtable;
     36 import java.util.Vector;
     37 
     38 import org.apache.harmony.awt.gl.ImageSurface;
     39 import org.apache.harmony.awt.gl.Surface;
     40 import org.apache.harmony.awt.gl.image.BufferedImageSource;
     41 import org.apache.harmony.awt.internal.nls.Messages;
     42 
     43 /**
     44  * The BufferedImage class describes an Image which contains a buffer of image
     45  * data and includes a ColorModel and a Raster for this data. This class
     46  * provides methods for obtaining and setting the Raster and for manipulating
     47  * the ColorModel parameters.
     48  *
     49  * @since Android 1.0
     50  */
     51 public class BufferedImage extends Image implements WritableRenderedImage, Transparency {
     52 
     53     /**
     54      * The Constant TYPE_CUSTOM indicates that Image type is unknown.
     55      */
     56     public static final int TYPE_CUSTOM = 0;
     57 
     58     /**
     59      * The Constant TYPE_INT_RGB indicates an image with 8 bit RGB color
     60      * components, it has a DirectColorModel without alpha.
     61      */
     62     public static final int TYPE_INT_RGB = 1;
     63 
     64     /**
     65      * The Constant TYPE_INT_ARGB indicates an image with 8 bit RGBA color
     66      * components, it has a DirectColorModel with alpha.
     67      */
     68     public static final int TYPE_INT_ARGB = 2;
     69 
     70     /**
     71      * The Constant TYPE_INT_ARGB_PRE indicates an image with 8 bit RGBA color
     72      * components, it has a DirectColorModel with alpha, and image data is
     73      * pre-multiplied by alpha.
     74      */
     75     public static final int TYPE_INT_ARGB_PRE = 3;
     76 
     77     /**
     78      * The Constant TYPE_INT_BGR indicates an image with 8 bit RGB color
     79      * components, BGR color model (with the colors Blue, Green, and Red). There
     80      * is no alpha. The image has a DirectColorModel.
     81      */
     82     public static final int TYPE_INT_BGR = 4;
     83 
     84     /**
     85      * The Constant TYPE_3BYTE_BGR indicates an image with 8 bit RGB color
     86      * components, BGR color model (with the colors Blue, Green, and Red stored
     87      * in 3 bytes). There is no alpha. The image has a ComponentColorModel.
     88      */
     89     public static final int TYPE_3BYTE_BGR = 5;
     90 
     91     /**
     92      * The Constant TYPE_4BYTE_ABGR indicates an image with 8 bit RGBA color
     93      * components stored in 3 bytes and 1 byte of alpha. It has a
     94      * ComponentColorModel with alpha.
     95      */
     96     public static final int TYPE_4BYTE_ABGR = 6;
     97 
     98     /**
     99      * The Constant TYPE_4BYTE_ABGR_PRE indicates an image with 8 bit RGBA color
    100      * components stored in 3 bytes and 1 byte for alpha. The image has a
    101      * ComponentColorModel with alpha. The color data is pre-multiplied with
    102      * alpha.
    103      */
    104     public static final int TYPE_4BYTE_ABGR_PRE = 7;
    105 
    106     /**
    107      * The Constant TYPE_USHORT_565_RGB indicates an image with 565 RGB color
    108      * components (5-bits red, 6-bits green, 5-bits blue) with no alpha. This
    109      * image has a DirectColorModel.
    110      */
    111     public static final int TYPE_USHORT_565_RGB = 8;
    112 
    113     /**
    114      * The Constant TYPE_USHORT_555_RGB indicates an image with 555 RGB color
    115      * components (5-bits red, 5-bits green, 5-bits blue) with no alpha. This
    116      * image has a DirectColorModel.
    117      */
    118     public static final int TYPE_USHORT_555_RGB = 9;
    119 
    120     /**
    121      * The Constant TYPE_BYTE_GRAY indicates a unsigned byte image. This image
    122      * has a ComponentColorModel with a CS_GRAY ColorSpace.
    123      */
    124     public static final int TYPE_BYTE_GRAY = 10;
    125 
    126     /**
    127      * The Constant TYPE_USHORT_GRAY indicates an unsigned short image. This
    128      * image has a ComponentColorModel with a CS_GRAY ColorSpace.
    129      */
    130     public static final int TYPE_USHORT_GRAY = 11;
    131 
    132     /**
    133      * The Constant TYPE_BYTE_BINARY indicates an opaque byte-packed 1, 2 or 4
    134      * bit image. The image has an IndexColorModel without alpha.
    135      */
    136     public static final int TYPE_BYTE_BINARY = 12;
    137 
    138     /**
    139      * The Constant TYPE_BYTE_INDEXED indicates an indexed byte image.
    140      */
    141     public static final int TYPE_BYTE_INDEXED = 13;
    142 
    143     /**
    144      * The Constant ALPHA_MASK.
    145      */
    146     private static final int ALPHA_MASK = 0xff000000;
    147 
    148     /**
    149      * The Constant RED_MASK.
    150      */
    151     private static final int RED_MASK = 0x00ff0000;
    152 
    153     /**
    154      * The Constant GREEN_MASK.
    155      */
    156     private static final int GREEN_MASK = 0x0000ff00;
    157 
    158     /**
    159      * The Constant BLUE_MASK.
    160      */
    161     private static final int BLUE_MASK = 0x000000ff;
    162 
    163     /**
    164      * The Constant RED_BGR_MASK.
    165      */
    166     private static final int RED_BGR_MASK = 0x000000ff;
    167 
    168     /**
    169      * The Constant GREEN_BGR_MASK.
    170      */
    171     private static final int GREEN_BGR_MASK = 0x0000ff00;
    172 
    173     /**
    174      * The Constant BLUE_BGR_MASK.
    175      */
    176     private static final int BLUE_BGR_MASK = 0x00ff0000;
    177 
    178     /**
    179      * The Constant RED_565_MASK.
    180      */
    181     private static final int RED_565_MASK = 0xf800;
    182 
    183     /**
    184      * The Constant GREEN_565_MASK.
    185      */
    186     private static final int GREEN_565_MASK = 0x07e0;
    187 
    188     /**
    189      * The Constant BLUE_565_MASK.
    190      */
    191     private static final int BLUE_565_MASK = 0x001f;
    192 
    193     /**
    194      * The Constant RED_555_MASK.
    195      */
    196     private static final int RED_555_MASK = 0x7c00;
    197 
    198     /**
    199      * The Constant GREEN_555_MASK.
    200      */
    201     private static final int GREEN_555_MASK = 0x03e0;
    202 
    203     /**
    204      * The Constant BLUE_555_MASK.
    205      */
    206     private static final int BLUE_555_MASK = 0x001f;
    207 
    208     /**
    209      * The cm.
    210      */
    211     private ColorModel cm;
    212 
    213     /**
    214      * The raster.
    215      */
    216     private final WritableRaster raster;
    217 
    218     /**
    219      * The image type.
    220      */
    221     private final int imageType;
    222 
    223     /**
    224      * The properties.
    225      */
    226     private Hashtable<?, ?> properties;
    227 
    228     // Surface of the Buffered Image - used for blitting one Buffered Image
    229     // on the other one or on the Component
    230     /**
    231      * The image surf.
    232      */
    233     private final ImageSurface imageSurf;
    234 
    235     /**
    236      * Instantiates a new BufferedImage with the specified ColorModel, and
    237      * WritableRaster objects. The Raster data can be be divided or multiplied
    238      * by alpha. It depends on the alphaPremultiplied state in the ColorModel.
    239      *
    240      * @param cm
    241      *            the ColorModel of the new image.
    242      * @param raster
    243      *            the WritableRaster of the new image.
    244      * @param isRasterPremultiplied
    245      *            if true the data of the specified Raster is pre-multiplied by
    246      *            alpha.
    247      * @param properties
    248      *            the properties of new Image.
    249      */
    250     public BufferedImage(ColorModel cm, WritableRaster raster, boolean isRasterPremultiplied,
    251             Hashtable<?, ?> properties) {
    252         if (!cm.isCompatibleRaster(raster)) {
    253             // awt.4D=The raster is incompatible with this ColorModel
    254             throw new IllegalArgumentException(Messages.getString("awt.4D")); //$NON-NLS-1$
    255         }
    256 
    257         if (raster.getMinX() != 0 || raster.getMinY() != 0) {
    258             // awt.228=minX or minY of this raster not equal to zero
    259             throw new IllegalArgumentException(Messages.getString("awt.228")); //$NON-NLS-1$
    260         }
    261 
    262         this.cm = cm;
    263         this.raster = raster;
    264         this.properties = properties;
    265 
    266         coerceData(isRasterPremultiplied);
    267 
    268         imageType = Surface.getType(cm, raster);
    269 
    270         imageSurf = createImageSurface(imageType);
    271     }
    272 
    273     /**
    274      * Instantiates a new BufferedImage with the specified width, height
    275      * predefined image type (TYPE_BYTE_BINARY or TYPE_BYTE_INDEXED) and the
    276      * specified IndexColorModel.
    277      *
    278      * @param width
    279      *            the width of new image.
    280      * @param height
    281      *            the height of new image.
    282      * @param imageType
    283      *            the predefined image type.
    284      * @param cm
    285      *            the specified IndexColorModel.
    286      */
    287     public BufferedImage(int width, int height, int imageType, IndexColorModel cm) {
    288         switch (imageType) {
    289             case TYPE_BYTE_BINARY:
    290                 if (cm.hasAlpha()) {
    291                     // awt.227=This image type can't have alpha
    292                     throw new IllegalArgumentException(Messages.getString("awt.227")); //$NON-NLS-1$
    293                 }
    294                 int pixel_bits = 0;
    295                 int mapSize = cm.getMapSize();
    296                 if (mapSize <= 2) {
    297                     pixel_bits = 1;
    298                 } else if (mapSize <= 4) {
    299                     pixel_bits = 2;
    300                 } else if (mapSize <= 16) {
    301                     pixel_bits = 4;
    302                 } else {
    303                     // awt.221=The imageType is TYPE_BYTE_BINARY and the color
    304                     // map has more than 16 entries
    305                     throw new IllegalArgumentException(Messages.getString("awt.221")); //$NON-NLS-1$
    306                 }
    307 
    308                 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1,
    309                         pixel_bits, null);
    310                 break;
    311 
    312             case TYPE_BYTE_INDEXED:
    313                 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1,
    314                         null);
    315                 break;
    316 
    317             default:
    318                 // awt.222=The imageType is not TYPE_BYTE_BINARY or
    319                 // TYPE_BYTE_INDEXED
    320                 throw new IllegalArgumentException(Messages.getString("awt.222")); //$NON-NLS-1$
    321 
    322         }
    323 
    324         if (!cm.isCompatibleRaster(raster)) {
    325             // awt.223=The imageType is not compatible with ColorModel
    326             throw new IllegalArgumentException(Messages.getString("awt.223")); //$NON-NLS-1$
    327         }
    328 
    329         this.cm = cm;
    330         this.imageType = imageType;
    331         imageSurf = createImageSurface(imageType);
    332 
    333     }
    334 
    335     /**
    336      * Instantiates a new BufferedImage with the specified width, height and
    337      * predefined image type.
    338      *
    339      * @param width
    340      *            the width of new image.
    341      * @param height
    342      *            the height of new image.
    343      * @param imageType
    344      *            the predefined image type.
    345      */
    346     public BufferedImage(int width, int height, int imageType) {
    347 
    348         switch (imageType) {
    349             case TYPE_INT_RGB:
    350                 cm = new DirectColorModel(24, RED_MASK, GREEN_MASK, BLUE_MASK);
    351                 raster = cm.createCompatibleWritableRaster(width, height);
    352                 break;
    353 
    354             case TYPE_INT_ARGB:
    355                 cm = ColorModel.getRGBdefault();
    356                 raster = cm.createCompatibleWritableRaster(width, height);
    357                 break;
    358 
    359             case TYPE_INT_ARGB_PRE:
    360                 cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 32, RED_MASK,
    361                         GREEN_MASK, BLUE_MASK, ALPHA_MASK, true, DataBuffer.TYPE_INT);
    362 
    363                 raster = cm.createCompatibleWritableRaster(width, height);
    364                 break;
    365 
    366             case TYPE_INT_BGR:
    367                 cm = new DirectColorModel(24, RED_BGR_MASK, GREEN_BGR_MASK, BLUE_BGR_MASK);
    368 
    369                 raster = cm.createCompatibleWritableRaster(width, height);
    370                 break;
    371 
    372             case TYPE_3BYTE_BGR: {
    373                 int bits[] = {
    374                         8, 8, 8
    375                 };
    376                 int bandOffsets[] = {
    377                         2, 1, 0
    378                 };
    379                 cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits,
    380                         false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
    381 
    382                 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height,
    383                         width * 3, 3, bandOffsets, null);
    384             }
    385                 break;
    386 
    387             case TYPE_4BYTE_ABGR: {
    388                 int bits[] = {
    389                         8, 8, 8, 8
    390                 };
    391                 int bandOffsets[] = {
    392                         3, 2, 1, 0
    393                 };
    394                 cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits,
    395                         true, false, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
    396 
    397                 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height,
    398                         width * 4, 4, bandOffsets, null);
    399             }
    400                 break;
    401 
    402             case TYPE_4BYTE_ABGR_PRE: {
    403                 int bits[] = {
    404                         8, 8, 8, 8
    405                 };
    406                 int bandOffsets[] = {
    407                         3, 2, 1, 0
    408                 };
    409                 cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), bits,
    410                         true, true, Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);
    411 
    412                 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height,
    413                         width * 4, 4, bandOffsets, null);
    414             }
    415                 break;
    416 
    417             case TYPE_USHORT_565_RGB:
    418                 cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 16,
    419                         RED_565_MASK, GREEN_565_MASK, BLUE_565_MASK, 0, false,
    420                         DataBuffer.TYPE_USHORT);
    421 
    422                 raster = cm.createCompatibleWritableRaster(width, height);
    423                 break;
    424 
    425             case TYPE_USHORT_555_RGB:
    426                 cm = new DirectColorModel(ColorSpace.getInstance(ColorSpace.CS_sRGB), 15,
    427                         RED_555_MASK, GREEN_555_MASK, BLUE_555_MASK, 0, false,
    428                         DataBuffer.TYPE_USHORT);
    429 
    430                 raster = cm.createCompatibleWritableRaster(width, height);
    431                 break;
    432 
    433             case TYPE_BYTE_GRAY: {
    434                 int bits[] = {
    435                     8
    436                 };
    437                 cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits,
    438                         false, false, Transparency.OPAQUE, DataBuffer.TYPE_BYTE);
    439 
    440                 raster = cm.createCompatibleWritableRaster(width, height);
    441             }
    442                 break;
    443 
    444             case TYPE_USHORT_GRAY: {
    445                 int bits[] = {
    446                     16
    447                 };
    448                 cm = new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY), bits,
    449                         false, false, Transparency.OPAQUE, DataBuffer.TYPE_USHORT);
    450                 raster = cm.createCompatibleWritableRaster(width, height);
    451             }
    452                 break;
    453 
    454             case TYPE_BYTE_BINARY: {
    455                 int colorMap[] = {
    456                         0, 0xffffff
    457                 };
    458                 cm = new IndexColorModel(1, 2, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE);
    459 
    460                 raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, width, height, 1, 1, null);
    461             }
    462                 break;
    463 
    464             case TYPE_BYTE_INDEXED: {
    465                 int colorMap[] = new int[256];
    466                 int i = 0;
    467                 for (int r = 0; r < 256; r += 51) {
    468                     for (int g = 0; g < 256; g += 51) {
    469                         for (int b = 0; b < 256; b += 51) {
    470                             colorMap[i] = (r << 16) | (g << 8) | b;
    471                             i++;
    472                         }
    473                     }
    474                 }
    475 
    476                 int gray = 0x12;
    477                 for (; i < 256; i++, gray += 6) {
    478                     colorMap[i] = (gray << 16) | (gray << 8) | gray;
    479                 }
    480                 cm = new IndexColorModel(8, 256, colorMap, 0, false, -1, DataBuffer.TYPE_BYTE);
    481                 raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, width, height, 1,
    482                         null);
    483 
    484             }
    485                 break;
    486             default:
    487                 // awt.224=Unknown image type
    488                 throw new IllegalArgumentException(Messages.getString("awt.224")); //$NON-NLS-1$
    489         }
    490         this.imageType = imageType;
    491         imageSurf = createImageSurface(imageType);
    492     }
    493 
    494     @Override
    495     public Object getProperty(String name, ImageObserver observer) {
    496         return getProperty(name);
    497     }
    498 
    499     public Object getProperty(String name) {
    500         if (name == null) {
    501             // awt.225=Property name is null
    502             throw new NullPointerException(Messages.getString("awt.225")); //$NON-NLS-1$
    503         }
    504         if (properties == null) {
    505             return Image.UndefinedProperty;
    506         }
    507         Object property = properties.get(name);
    508         if (property == null) {
    509             property = Image.UndefinedProperty;
    510         }
    511         return property;
    512     }
    513 
    514     public WritableRaster copyData(WritableRaster outRaster) {
    515         if (outRaster == null) {
    516             outRaster = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster
    517                     .getSampleModelTranslateX(), raster.getSampleModelTranslateY()));
    518         }
    519 
    520         int w = outRaster.getWidth();
    521         int h = outRaster.getHeight();
    522         int minX = outRaster.getMinX();
    523         int minY = outRaster.getMinY();
    524 
    525         Object data = null;
    526 
    527         data = raster.getDataElements(minX, minY, w, h, data);
    528         outRaster.setDataElements(minX, minY, w, h, data);
    529 
    530         return outRaster;
    531     }
    532 
    533     public Raster getData(Rectangle rect) {
    534         int minX = rect.x;
    535         int minY = rect.y;
    536         int w = rect.width;
    537         int h = rect.height;
    538 
    539         SampleModel sm = raster.getSampleModel();
    540         SampleModel nsm = sm.createCompatibleSampleModel(w, h);
    541         WritableRaster outr = Raster.createWritableRaster(nsm, rect.getLocation());
    542         Object data = null;
    543 
    544         data = raster.getDataElements(minX, minY, w, h, data);
    545         outr.setDataElements(minX, minY, w, h, data);
    546         return outr;
    547     }
    548 
    549     public Vector<RenderedImage> getSources() {
    550         return null;
    551     }
    552 
    553     public String[] getPropertyNames() {
    554         if (properties == null) {
    555             return null;
    556         }
    557         Vector<String> v = new Vector<String>();
    558         for (Enumeration<?> e = properties.keys(); e.hasMoreElements();) {
    559             try {
    560                 v.add((String)e.nextElement());
    561             } catch (ClassCastException ex) {
    562             }
    563         }
    564         int size = v.size();
    565         if (size > 0) {
    566             String names[] = new String[size];
    567             for (int i = 0; i < size; i++) {
    568                 names[i] = v.elementAt(i);
    569             }
    570             return names;
    571         }
    572         return null;
    573     }
    574 
    575     /**
    576      * Returns the string representation of this BufferedImage object.
    577      *
    578      * @return the string representation of this BufferedImage object.
    579      */
    580     @Override
    581     public String toString() {
    582         return "BufferedImage@" + Integer.toHexString(hashCode()) + //$NON-NLS-1$
    583                 ": type = " + imageType + " " + cm + " " + raster; //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$
    584     }
    585 
    586     public WritableRaster getWritableTile(int tileX, int tileY) {
    587         return raster;
    588     }
    589 
    590     /**
    591      * Gets the WritableRaster of this BufferedImage.
    592      *
    593      * @return the WritableRaster of this BufferedImage.
    594      */
    595     public WritableRaster getRaster() {
    596         return raster;
    597     }
    598 
    599     /**
    600      * Gets a WritableRaster object which contains the alpha channel of
    601      * BufferedImage object with ColorModel objects that supports a separate
    602      * alpha channel such as ComponentColorModel or DirectColorModel.
    603      *
    604      * @return the WritableRaster object which contains the alpha channel of
    605      *         this BufferedImage.
    606      */
    607     public WritableRaster getAlphaRaster() {
    608         return cm.getAlphaRaster(raster);
    609     }
    610 
    611     public void removeTileObserver(TileObserver to) {
    612     }
    613 
    614     public void addTileObserver(TileObserver to) {
    615     }
    616 
    617     public SampleModel getSampleModel() {
    618         return raster.getSampleModel();
    619     }
    620 
    621     public void setData(Raster r) {
    622 
    623         Rectangle from = r.getBounds();
    624         Rectangle to = raster.getBounds();
    625         Rectangle intersection = to.intersection(from);
    626 
    627         int minX = intersection.x;
    628         int minY = intersection.y;
    629         int w = intersection.width;
    630         int h = intersection.height;
    631 
    632         Object data = null;
    633 
    634         data = r.getDataElements(minX, minY, w, h, data);
    635         raster.setDataElements(minX, minY, w, h, data);
    636     }
    637 
    638     public Raster getTile(int tileX, int tileY) {
    639         if (tileX == 0 && tileY == 0) {
    640             return raster;
    641         }
    642         // awt.226=Both tileX and tileY are not equal to 0
    643         throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$
    644     }
    645 
    646     public Raster getData() {
    647         int w = raster.getWidth();
    648         int h = raster.getHeight();
    649         int minX = raster.getMinX();
    650         int minY = raster.getMinY();
    651 
    652         WritableRaster outr = Raster.createWritableRaster(raster.getSampleModel(), new Point(raster
    653                 .getSampleModelTranslateX(), raster.getSampleModelTranslateY()));
    654 
    655         Object data = null;
    656 
    657         data = raster.getDataElements(minX, minY, w, h, data);
    658         outr.setDataElements(minX, minY, w, h, data);
    659 
    660         return outr;
    661     }
    662 
    663     @Override
    664     public ImageProducer getSource() {
    665         return new BufferedImageSource(this, properties);
    666     }
    667 
    668     @Override
    669     public int getWidth(ImageObserver observer) {
    670         return raster.getWidth();
    671     }
    672 
    673     @Override
    674     public int getHeight(ImageObserver observer) {
    675         return raster.getHeight();
    676     }
    677 
    678     public ColorModel getColorModel() {
    679         return cm;
    680     }
    681 
    682     /**
    683      * Gets the rectangular area of this BufferedImage as a subimage.
    684      *
    685      * @param x
    686      *            the x coordinate.
    687      * @param y
    688      *            the y coordinate.
    689      * @param w
    690      *            the width of the subimage.
    691      * @param h
    692      *            the height of the subimage.
    693      * @return the BufferedImage.
    694      */
    695     public BufferedImage getSubimage(int x, int y, int w, int h) {
    696         WritableRaster wr = raster.createWritableChild(x, y, w, h, 0, 0, null);
    697         return new BufferedImage(cm, wr, cm.isAlphaPremultiplied(), properties);
    698     }
    699 
    700     public Point[] getWritableTileIndices() {
    701         Point points[] = new Point[1];
    702         points[0] = new Point(0, 0);
    703         return points;
    704     }
    705 
    706     /**
    707      * Creates the Graphics2D object which allows to draw into this
    708      * BufferedImage.
    709      *
    710      * @return the graphics2D object.
    711      */
    712     public Graphics2D createGraphics() {
    713         GraphicsEnvironment ge = GraphicsEnvironment.getLocalGraphicsEnvironment();
    714         // return ge.createGraphics(this);
    715         // ???AWT hack, FIXME
    716         // return AndroidGraphics2D.getInstance();
    717         // throw new RuntimeException("Not implemented!");
    718         return null;
    719     }
    720 
    721     @Override
    722     public Graphics getGraphics() {
    723         return createGraphics();
    724     }
    725 
    726     /**
    727      * Coerces the data to achieve the state which is specified by the
    728      * isAlphaPremultiplied variable.
    729      *
    730      * @param isAlphaPremultiplied
    731      *            the is alpha pre-multiplied state.
    732      */
    733     public void coerceData(boolean isAlphaPremultiplied) {
    734         if (cm.hasAlpha() && cm.isAlphaPremultiplied() != isAlphaPremultiplied) {
    735             cm = cm.coerceData(raster, isAlphaPremultiplied);
    736         }
    737     }
    738 
    739     /**
    740      * Gets an array of colors in the TYPE_INT_ARGB color model and default sRGB
    741      * color space of the specified area of this BufferedImage. The result array
    742      * is composed by the following algorithm:
    743      * <p>
    744      * pixel = rgbArray[offset + (y-startY)*scansize + (x-startX)]
    745      * </p>
    746      *
    747      * @param startX
    748      *            the start X area coordinate.
    749      * @param startY
    750      *            the start Y area coordinate.
    751      * @param w
    752      *            the width of the area.
    753      * @param h
    754      *            the height of the area.
    755      * @param rgbArray
    756      *            the result array will be stored to this array.
    757      * @param offset
    758      *            the offset of the rgbArray array.
    759      * @param scansize
    760      *            the scanline stride for the rgbArray.
    761      * @return an array of colors for the specified area.
    762      */
    763     public int[] getRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset,
    764             int scansize) {
    765         if (rgbArray == null) {
    766             rgbArray = new int[offset + h * scansize];
    767         }
    768 
    769         int off = offset;
    770         for (int y = startY; y < startY + h; y++, off += scansize) {
    771             int i = off;
    772             for (int x = startX; x < startX + w; x++, i++) {
    773                 rgbArray[i] = cm.getRGB(raster.getDataElements(x, y, null));
    774             }
    775         }
    776         return rgbArray;
    777     }
    778 
    779     /**
    780      * Sets RGB values from the specified array to the specified BufferedImage
    781      * area. The pixels are in the default RGB color model (TYPE_INT_ARGB) and
    782      * default sRGB color space.
    783      *
    784      * @param startX
    785      *            the start X coordinate.
    786      * @param startY
    787      *            the start Y coordinate.
    788      * @param w
    789      *            the width of the BufferedImage area.
    790      * @param h
    791      *            the height of the BufferedImage area.
    792      * @param rgbArray
    793      *            the array of RGB values.
    794      * @param offset
    795      *            the offset of the rgbArray array.
    796      * @param scansize
    797      *            the scanline stride for the rgbArray.
    798      */
    799     public void setRGB(int startX, int startY, int w, int h, int[] rgbArray, int offset,
    800             int scansize) {
    801         int off = offset;
    802         for (int y = startY; y < startY + h; y++, off += scansize) {
    803             int i = off;
    804             for (int x = startX; x < startX + w; x++, i++) {
    805                 raster.setDataElements(x, y, cm.getDataElements(rgbArray[i], null));
    806             }
    807         }
    808     }
    809 
    810     /**
    811      * Sets a the specified RGB value to the specified pixel of this
    812      * BufferedImage. The pixel should be in the default RGB color model
    813      * (TYPE_INT_ARGB) and default sRGB color space.
    814      *
    815      * @param x
    816      *            the X coordinate of the pixel.
    817      * @param y
    818      *            the Y coordinate of the pixel.
    819      * @param rgb
    820      *            the RGB value to be set.
    821      */
    822     public synchronized void setRGB(int x, int y, int rgb) {
    823         raster.setDataElements(x, y, cm.getDataElements(rgb, null));
    824     }
    825 
    826     public boolean isTileWritable(int tileX, int tileY) {
    827         if (tileX == 0 && tileY == 0) {
    828             return true;
    829         }
    830         // awt.226=Both tileX and tileY are not equal to 0
    831         throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.226")); //$NON-NLS-1$
    832     }
    833 
    834     public void releaseWritableTile(int tileX, int tileY) {
    835     }
    836 
    837     /**
    838      * Gets a color in the TYPE_INT_ARGB color model and default sRGB color
    839      * space of the specified pixel.
    840      *
    841      * @param x
    842      *            the X coordinate of the pixel.
    843      * @param y
    844      *            the Y coordinate of the pixel.
    845      * @return the color of the specified pixel in the TYPE_INT_ARGB color model
    846      *         and default sRGB color space.
    847      */
    848     public int getRGB(int x, int y) {
    849         return cm.getRGB(raster.getDataElements(x, y, null));
    850     }
    851 
    852     /**
    853      * Returns true if alpha is pre-multiplied, false if alpha is not
    854      * pre-multiplied or there is no alpha.
    855      *
    856      * @return true if alpha is pre-multiplied, false if alpha is not
    857      *         pre-multiplied or there is no alpha.
    858      */
    859     public boolean isAlphaPremultiplied() {
    860         return cm.isAlphaPremultiplied();
    861     }
    862 
    863     public boolean hasTileWriters() {
    864         return true;
    865     }
    866 
    867     @Override
    868     public void flush() {
    869         imageSurf.dispose();
    870     }
    871 
    872     public int getWidth() {
    873         return raster.getWidth();
    874     }
    875 
    876     /**
    877      * Gets the image type.
    878      *
    879      * @return the image type.
    880      */
    881     public int getType() {
    882         return imageType;
    883     }
    884 
    885     public int getTileWidth() {
    886         return raster.getWidth();
    887     }
    888 
    889     public int getTileHeight() {
    890         return raster.getHeight();
    891     }
    892 
    893     public int getTileGridYOffset() {
    894         return raster.getSampleModelTranslateY();
    895     }
    896 
    897     public int getTileGridXOffset() {
    898         return raster.getSampleModelTranslateX();
    899     }
    900 
    901     public int getNumYTiles() {
    902         return 1;
    903     }
    904 
    905     public int getNumXTiles() {
    906         return 1;
    907     }
    908 
    909     public int getMinY() {
    910         return raster.getMinY();
    911     }
    912 
    913     public int getMinX() {
    914         return raster.getMinX();
    915     }
    916 
    917     public int getMinTileY() {
    918         return 0;
    919     }
    920 
    921     public int getMinTileX() {
    922         return 0;
    923     }
    924 
    925     public int getHeight() {
    926         return raster.getHeight();
    927     }
    928 
    929     /**
    930      * Creates the image surface.
    931      *
    932      * @param type
    933      *            the type.
    934      * @return the image surface.
    935      */
    936     private ImageSurface createImageSurface(int type) {
    937         return new ImageSurface(getColorModel(), getRaster(), type);
    938     }
    939 
    940     /**
    941      * Gets the image surface.
    942      *
    943      * @return the image surface.
    944      */
    945     ImageSurface getImageSurface() {
    946         return imageSurf;
    947     }
    948 
    949     public int getTransparency() {
    950         return cm.getTransparency();
    951     }
    952 }
    953