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 java.awt.Transparency;
     25 import java.awt.color.ColorSpace;
     26 import java.math.BigInteger;
     27 
     28 import org.apache.harmony.awt.internal.nls.Messages;
     29 
     30 /**
     31  * The Class IndexColorModel represents a color model in which the color values
     32  * of the pixels are read from a palette.
     33  *
     34  * @since Android 1.0
     35  */
     36 public class IndexColorModel extends ColorModel {
     37 
     38     /**
     39      * The color map.
     40      */
     41     private int colorMap[]; // Color Map
     42 
     43     /**
     44      * The map size.
     45      */
     46     private int mapSize; // Color Map size
     47 
     48     /**
     49      * The transparent index.
     50      */
     51     private int transparentIndex; // Index of fully transparent pixel
     52 
     53     /**
     54      * The gray palette.
     55      */
     56     private boolean grayPalette; // Color Model has Color Map with Gray Pallete
     57 
     58     /**
     59      * The valid bits.
     60      */
     61     private BigInteger validBits; // Specify valid Color Map values
     62 
     63     /**
     64      * The Constant CACHESIZE.
     65      */
     66     private static final int CACHESIZE = 20; // Cache size. Cache used for
     67 
     68     // improving performace of selection
     69     // nearest color in Color Map
     70 
     71     /**
     72      * The cachetable.
     73      */
     74     private final int cachetable[] = new int[CACHESIZE * 2]; // Cache table -
     75 
     76     // used for
     77 
     78     // storing RGB values and that appropriate indices
     79     // in the Color Map
     80 
     81     /**
     82      * The next insert idx.
     83      */
     84     private int nextInsertIdx = 0; // Next index for insertion into Cache table
     85 
     86     /**
     87      * The total inserted.
     88      */
     89     private int totalInserted = 0; // Number of inserted values into Cache table
     90 
     91     /**
     92      * Instantiates a new index color model.
     93      *
     94      * @param bits
     95      *            the array of component masks.
     96      * @param size
     97      *            the size of the color map.
     98      * @param cmap
     99      *            the array that gives the color mapping.
    100      * @param start
    101      *            the start index of the color mapping data within the cmap
    102      *            array.
    103      * @param transferType
    104      *            the transfer type (primitive java type to use for the
    105      *            components).
    106      * @param validBits
    107      *            a list of which bits represent valid colormap values, or null
    108      *            if all are valid.
    109      * @throws IllegalArgumentException
    110      *             if the size of the color map is less than one.
    111      */
    112     public IndexColorModel(int bits, int size, int cmap[], int start, int transferType,
    113             BigInteger validBits) {
    114 
    115         super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB),
    116                 true, false, Transparency.OPAQUE, validateTransferType(transferType));
    117 
    118         if (size < 1) {
    119             // awt.264=Size of the color map is less than 1
    120             throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
    121         }
    122 
    123         mapSize = size;
    124         colorMap = new int[mapSize];
    125         transparentIndex = -1;
    126 
    127         if (validBits != null) {
    128             for (int i = 0; i < mapSize; i++) {
    129                 if (!validBits.testBit(i)) {
    130                     this.validBits = validBits;
    131                 }
    132                 break;
    133             }
    134         }
    135 
    136         transparency = Transparency.OPAQUE;
    137         int alphaMask = 0xff000000;
    138         int alpha = 0;
    139 
    140         for (int i = 0; i < mapSize; i++, start++) {
    141             colorMap[i] = cmap[start];
    142             alpha = cmap[start] & alphaMask;
    143 
    144             if (alpha == alphaMask) {
    145                 continue;
    146             }
    147             if (alpha == 0) {
    148                 if (transparentIndex < 0) {
    149                     transparentIndex = i;
    150                 }
    151                 if (transparency == Transparency.OPAQUE) {
    152                     transparency = Transparency.BITMASK;
    153                 }
    154             } else if (alpha != alphaMask && transparency != Transparency.TRANSLUCENT) {
    155                 transparency = Transparency.TRANSLUCENT;
    156             }
    157 
    158         }
    159         checkPalette();
    160 
    161     }
    162 
    163     /**
    164      * Instantiates a new index color model.
    165      *
    166      * @param bits
    167      *            the array of component masks.
    168      * @param size
    169      *            the size of the color map.
    170      * @param cmap
    171      *            the array that gives the color mapping.
    172      * @param start
    173      *            the start index of the color mapping data within the cmap
    174      *            array.
    175      * @param hasalpha
    176      *            whether this color model uses alpha.
    177      * @param trans
    178      *            the transparency supported, @see java.awt.Transparency.
    179      * @param transferType
    180      *            the transfer type (primitive java type to use for the
    181      *            components).
    182      * @throws IllegalArgumentException
    183      *             if the size of the color map is less than one.
    184      */
    185     public IndexColorModel(int bits, int size, int cmap[], int start, boolean hasalpha, int trans,
    186             int transferType) {
    187 
    188         super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace
    189                 .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false,
    190                 Transparency.OPAQUE, validateTransferType(transferType));
    191 
    192         if (size < 1) {
    193             // awt.264=Size of the color map is less than 1
    194             throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
    195         }
    196 
    197         mapSize = size;
    198         colorMap = new int[mapSize];
    199         if (trans >= 0 && trans < mapSize) {
    200             transparentIndex = trans;
    201             transparency = Transparency.BITMASK;
    202         } else {
    203             transparentIndex = -1;
    204             transparency = Transparency.OPAQUE;
    205         }
    206 
    207         int alphaMask = 0xff000000;
    208         int alpha = 0;
    209 
    210         for (int i = 0; i < mapSize; i++, start++) {
    211             if (transparentIndex == i) {
    212                 colorMap[i] = cmap[start] & 0x00ffffff;
    213                 continue;
    214             }
    215             if (hasalpha) {
    216                 alpha = cmap[start] & alphaMask;
    217                 colorMap[i] = cmap[start];
    218 
    219                 if (alpha == alphaMask) {
    220                     continue;
    221                 }
    222                 if (alpha == 0) {
    223                     if (trans < 0) {
    224                         trans = i;
    225                     }
    226                     if (transparency == Transparency.OPAQUE) {
    227                         transparency = Transparency.BITMASK;
    228                     }
    229                 } else if (alpha != 0 && transparency != Transparency.TRANSLUCENT) {
    230                     transparency = Transparency.TRANSLUCENT;
    231                 }
    232             } else {
    233                 colorMap[i] = alphaMask | cmap[start];
    234             }
    235         }
    236         checkPalette();
    237 
    238     }
    239 
    240     /**
    241      * Instantiates a new index color model by building the color map from
    242      * arrays of red, green, blue, and alpha values.
    243      *
    244      * @param bits
    245      *            the array of component masks.
    246      * @param size
    247      *            the size of the color map.
    248      * @param r
    249      *            the array giving the red components of the entries in the
    250      *            color map.
    251      * @param g
    252      *            the array giving the green components of the entries in the
    253      *            color map.
    254      * @param b
    255      *            the array giving the blue components of the entries in the
    256      *            color map.
    257      * @param a
    258      *            the array giving the alpha components of the entries in the
    259      *            color map.
    260      * @throws IllegalArgumentException
    261      *             if the size of the color map is less than one.
    262      * @throws ArrayIndexOutOfBoundsException
    263      *             if the size of one of the component arrays is less than the
    264      *             size of the color map.
    265      */
    266     public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], byte a[]) {
    267 
    268         super(bits, IndexColorModel.createBits(true), ColorSpace.getInstance(ColorSpace.CS_sRGB),
    269                 true, false, Transparency.OPAQUE, validateTransferType(ColorModel
    270                         .getTransferType(bits)));
    271 
    272         createColorMap(size, r, g, b, a, -1);
    273         checkPalette();
    274     }
    275 
    276     /**
    277      * Instantiates a new index color model by building the color map from
    278      * arrays of red, green, and blue values.
    279      *
    280      * @param bits
    281      *            the array of component masks.
    282      * @param size
    283      *            the size of the color map.
    284      * @param r
    285      *            the array giving the red components of the entries in the
    286      *            color map.
    287      * @param g
    288      *            the array giving the green components of the entries in the
    289      *            color map.
    290      * @param b
    291      *            the array giving the blue components of the entries in the
    292      *            color map.
    293      * @param trans
    294      *            the transparency supported, @see java.awt.Transparency.
    295      * @throws IllegalArgumentException
    296      *             if the size of the color map is less than one.
    297      * @throws ArrayIndexOutOfBoundsException
    298      *             if the size of one of the component arrays is less than the
    299      *             size of the color map.
    300      */
    301     public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[], int trans) {
    302 
    303         super(bits, IndexColorModel.createBits((trans >= 0)), ColorSpace
    304                 .getInstance(ColorSpace.CS_sRGB), (trans >= 0), false, Transparency.OPAQUE,
    305                 validateTransferType(ColorModel.getTransferType(bits)));
    306 
    307         createColorMap(size, r, g, b, null, trans);
    308         checkPalette();
    309     }
    310 
    311     /**
    312      * Instantiates a new index color model by building the color map from
    313      * arrays of red, green, and blue values.
    314      *
    315      * @param bits
    316      *            the array of component masks.
    317      * @param size
    318      *            the size of the color map.
    319      * @param r
    320      *            the array giving the red components of the entries in the
    321      *            color map.
    322      * @param g
    323      *            the array giving the green components of the entries in the
    324      *            color map.
    325      * @param b
    326      *            the array giving the blue components of the entries in the
    327      *            color map.
    328      * @throws IllegalArgumentException
    329      *             if the size of the color map is less than one.
    330      * @throws ArrayIndexOutOfBoundsException
    331      *             if the size of one of the component arrays is less than the
    332      *             size of the color map.
    333      */
    334     public IndexColorModel(int bits, int size, byte r[], byte g[], byte b[]) {
    335         super(bits, IndexColorModel.createBits(false), ColorSpace.getInstance(ColorSpace.CS_sRGB),
    336                 false, false, Transparency.OPAQUE, validateTransferType(ColorModel
    337                         .getTransferType(bits)));
    338 
    339         createColorMap(size, r, g, b, null, -1);
    340         checkPalette();
    341     }
    342 
    343     /**
    344      * Instantiates a new index color model.
    345      *
    346      * @param bits
    347      *            the array of component masks.
    348      * @param size
    349      *            the size of the color map.
    350      * @param cmap
    351      *            the array that gives the color mapping.
    352      * @param start
    353      *            the start index of the color mapping data within the cmap
    354      *            array.
    355      * @param hasalpha
    356      *            whether this color model uses alpha.
    357      * @param trans
    358      *            the transparency supported, @see java.awt.Transparency.
    359      * @throws IllegalArgumentException
    360      *             if the size of the color map is less than one.
    361      */
    362     public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha, int trans) {
    363 
    364         super(bits, IndexColorModel.createBits(hasalpha || (trans >= 0)), ColorSpace
    365                 .getInstance(ColorSpace.CS_sRGB), (hasalpha || (trans >= 0)), false,
    366                 Transparency.OPAQUE, validateTransferType(ColorModel.getTransferType(bits)));
    367 
    368         if (size < 1) {
    369             // awt.264=Size of the color map is less than 1
    370             throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
    371         }
    372 
    373         mapSize = size;
    374         colorMap = new int[mapSize];
    375         transparentIndex = -1;
    376 
    377         transparency = Transparency.OPAQUE;
    378         int alpha = 0xff000000;
    379 
    380         for (int i = 0; i < mapSize; i++) {
    381             colorMap[i] = (cmap[start++] & 0xff) << 16 | (cmap[start++] & 0xff) << 8
    382                     | (cmap[start++] & 0xff);
    383             if (trans == i) {
    384                 if (transparency == Transparency.OPAQUE) {
    385                     transparency = Transparency.BITMASK;
    386                 }
    387                 if (hasalpha) {
    388                     start++;
    389                 }
    390                 continue;
    391             }
    392             if (hasalpha) {
    393                 alpha = cmap[start++] & 0xff;
    394                 if (alpha == 0) {
    395                     if (transparency == Transparency.OPAQUE) {
    396                         transparency = Transparency.BITMASK;
    397                         if (trans < 0) {
    398                             trans = i;
    399                         }
    400                     }
    401                 } else {
    402                     if (alpha != 0xff && transparency != Transparency.TRANSLUCENT) {
    403                         transparency = Transparency.TRANSLUCENT;
    404                     }
    405                 }
    406                 alpha <<= 24;
    407             }
    408             colorMap[i] |= alpha;
    409         }
    410 
    411         if (trans >= 0 && trans < mapSize) {
    412             transparentIndex = trans;
    413         }
    414         checkPalette();
    415 
    416     }
    417 
    418     /**
    419      * Instantiates a new index color model.
    420      *
    421      * @param bits
    422      *            the array of component masks.
    423      * @param size
    424      *            the size of the color map.
    425      * @param cmap
    426      *            the array that gives the color mapping.
    427      * @param start
    428      *            the start index of the color mapping data within the cmap
    429      *            array.
    430      * @param hasalpha
    431      *            whether this color model uses alpha.
    432      * @throws IllegalArgumentException
    433      *             if the size of the color map is less than one.
    434      */
    435     public IndexColorModel(int bits, int size, byte cmap[], int start, boolean hasalpha) {
    436 
    437         this(bits, size, cmap, start, hasalpha, -1);
    438     }
    439 
    440     @Override
    441     public Object getDataElements(int[] components, int offset, Object pixel) {
    442         int rgb = (components[offset] << 16) | (components[offset + 1]) << 8
    443                 | components[offset + 2];
    444         if (hasAlpha) {
    445             rgb |= components[offset + 3] << 24;
    446         } else {
    447             rgb |= 0xff000000;
    448         }
    449         return getDataElements(rgb, pixel);
    450     }
    451 
    452     @Override
    453     public synchronized Object getDataElements(int rgb, Object pixel) {
    454         int red = (rgb >> 16) & 0xff;
    455         int green = (rgb >> 8) & 0xff;
    456         int blue = rgb & 0xff;
    457         int alpha = rgb >>> 24;
    458         int pixIdx = 0;
    459 
    460         for (int i = 0; i < totalInserted; i++) {
    461             int idx = i * 2;
    462             if (rgb == cachetable[idx]) {
    463                 return createDataObject(cachetable[idx + 1], pixel);
    464             }
    465         }
    466 
    467         if (!hasAlpha && grayPalette) {
    468             int grey = (red * 77 + green * 150 + blue * 29 + 128) >>> 8;
    469             int minError = 255;
    470             int error = 0;
    471 
    472             for (int i = 0; i < mapSize; i++) {
    473                 error = Math.abs((colorMap[i] & 0xff) - grey);
    474                 if (error < minError) {
    475                     pixIdx = i;
    476                     if (error == 0) {
    477                         break;
    478                     }
    479                     minError = error;
    480                 }
    481             }
    482         } else if (alpha == 0 && transparentIndex > -1) {
    483             pixIdx = transparentIndex;
    484         } else {
    485             int minAlphaError = 255;
    486             int minError = 195075; // 255^2 + 255^2 + 255^2
    487             int alphaError;
    488             int error = 0;
    489 
    490             for (int i = 0; i < mapSize; i++) {
    491                 int pix = colorMap[i];
    492                 if (rgb == pix) {
    493                     pixIdx = i;
    494                     break;
    495                 }
    496                 alphaError = Math.abs(alpha - (pix >>> 24));
    497                 if (alphaError <= minAlphaError) {
    498                     minAlphaError = alphaError;
    499 
    500                     int buf = ((pix >> 16) & 0xff) - red;
    501                     error = buf * buf;
    502 
    503                     if (error < minError) {
    504                         buf = ((pix >> 8) & 0xff) - green;
    505                         error += buf * buf;
    506 
    507                         if (error < minError) {
    508                             buf = (pix & 0xff) - blue;
    509                             error += buf * buf;
    510 
    511                             if (error < minError) {
    512                                 pixIdx = i;
    513                                 minError = error;
    514                             }
    515                         }
    516                     }
    517                 }
    518             }
    519         }
    520 
    521         cachetable[nextInsertIdx] = rgb;
    522         cachetable[nextInsertIdx + 1] = pixIdx;
    523 
    524         nextInsertIdx = (nextInsertIdx + 2) % (CACHESIZE * 2);
    525         if (totalInserted < CACHESIZE) {
    526             totalInserted++;
    527         }
    528 
    529         return createDataObject(pixIdx, pixel);
    530     }
    531 
    532     /**
    533      * Converts an image from indexed to RGB format.
    534      *
    535      * @param raster
    536      *            the raster containing the source image.
    537      * @param forceARGB
    538      *            whether to use the default RGB color model.
    539      * @return the buffered image.
    540      * @throws IllegalArgumentException
    541      *             if the raster is not compatible with this color model.
    542      */
    543     public BufferedImage convertToIntDiscrete(Raster raster, boolean forceARGB) {
    544 
    545         if (!isCompatibleRaster(raster)) {
    546             // awt.265=The raster argument is not compatible with this
    547             // IndexColorModel
    548             throw new IllegalArgumentException(Messages.getString("awt.265")); //$NON-NLS-1$
    549         }
    550 
    551         ColorModel model;
    552         if (forceARGB || transparency == Transparency.TRANSLUCENT) {
    553             model = ColorModel.getRGBdefault();
    554         } else if (transparency == Transparency.BITMASK) {
    555             model = new DirectColorModel(25, 0x00ff0000, 0x0000ff00, 0x000000ff, 0x01000000);
    556         } else {
    557             model = new DirectColorModel(24, 0x00ff0000, 0x0000ff00, 0x000000ff);
    558         }
    559 
    560         int w = raster.getWidth();
    561         int h = raster.getHeight();
    562 
    563         WritableRaster distRaster = model.createCompatibleWritableRaster(w, h);
    564 
    565         int minX = raster.getMinX();
    566         int minY = raster.getMinY();
    567 
    568         Object obj = null;
    569         int pixels[] = null;
    570 
    571         for (int i = 0; i < h; i++, minY++) {
    572             obj = raster.getDataElements(minX, minY, w, 1, obj);
    573             if (obj instanceof byte[]) {
    574                 byte ba[] = (byte[])obj;
    575                 if (pixels == null) {
    576                     pixels = new int[ba.length];
    577                 }
    578                 for (int j = 0; j < ba.length; j++) {
    579                     pixels[j] = colorMap[ba[j] & 0xff];
    580                 }
    581             } else if (obj instanceof short[]) {
    582                 short sa[] = (short[])obj;
    583                 if (pixels == null) {
    584                     pixels = new int[sa.length];
    585                 }
    586                 for (int j = 0; j < sa.length; j++) {
    587                     pixels[j] = colorMap[sa[j] & 0xffff];
    588                 }
    589             }
    590             if (obj instanceof int[]) {
    591                 int ia[] = (int[])obj;
    592                 if (pixels == null) {
    593                     pixels = new int[ia.length];
    594                 }
    595                 for (int j = 0; j < ia.length; j++) {
    596                     pixels[j] = colorMap[ia[j]];
    597                 }
    598             }
    599 
    600             distRaster.setDataElements(0, i, w, 1, pixels);
    601         }
    602 
    603         return new BufferedImage(model, distRaster, false, null);
    604     }
    605 
    606     /**
    607      * Gets the valid pixels.
    608      *
    609      * @return the valid pixels.
    610      */
    611     public BigInteger getValidPixels() {
    612         return validBits;
    613     }
    614 
    615     @Override
    616     public String toString() {
    617         // The output format based on 1.5 release behaviour.
    618         // It could be reveled such way:
    619         // BufferedImage bi = new BufferedImage(1, 1,
    620         // BufferedImage.TYPE_BYTE_INDEXED);
    621         // ColorModel cm = bi.getColorModel();
    622         // System.out.println(cm.toString());
    623         String str = "IndexColorModel: #pixel_bits = " + pixel_bits + //$NON-NLS-1$
    624                 " numComponents = " + numComponents + " color space = " + cs + //$NON-NLS-1$ //$NON-NLS-2$
    625                 " transparency = "; //$NON-NLS-1$
    626 
    627         if (transparency == Transparency.OPAQUE) {
    628             str = str + "Transparency.OPAQUE"; //$NON-NLS-1$
    629         } else if (transparency == Transparency.BITMASK) {
    630             str = str + "Transparency.BITMASK"; //$NON-NLS-1$
    631         } else {
    632             str = str + "Transparency.TRANSLUCENT"; //$NON-NLS-1$
    633         }
    634 
    635         str = str + " transIndex = " + transparentIndex + " has alpha = " + //$NON-NLS-1$ //$NON-NLS-2$
    636                 hasAlpha + " isAlphaPre = " + isAlphaPremultiplied; //$NON-NLS-1$
    637 
    638         return str;
    639     }
    640 
    641     @Override
    642     public int[] getComponents(Object pixel, int components[], int offset) {
    643         int pixIdx = -1;
    644         if (pixel instanceof byte[]) {
    645             byte ba[] = (byte[])pixel;
    646             pixIdx = ba[0] & 0xff;
    647         } else if (pixel instanceof short[]) {
    648             short sa[] = (short[])pixel;
    649             pixIdx = sa[0] & 0xffff;
    650         } else if (pixel instanceof int[]) {
    651             int ia[] = (int[])pixel;
    652             pixIdx = ia[0];
    653         } else {
    654             // awt.219=This transferType is not supported by this color model
    655             throw new UnsupportedOperationException(Messages.getString("awt.219")); //$NON-NLS-1$
    656         }
    657 
    658         return getComponents(pixIdx, components, offset);
    659     }
    660 
    661     @Override
    662     public WritableRaster createCompatibleWritableRaster(int w, int h) {
    663         WritableRaster raster;
    664         if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
    665             raster = Raster.createPackedRaster(DataBuffer.TYPE_BYTE, w, h, 1, pixel_bits, null);
    666         } else if (pixel_bits <= 8) {
    667             raster = Raster.createInterleavedRaster(DataBuffer.TYPE_BYTE, w, h, 1, null);
    668         } else if (pixel_bits <= 16) {
    669             raster = Raster.createInterleavedRaster(DataBuffer.TYPE_USHORT, w, h, 1, null);
    670         } else {
    671             // awt.266=The number of bits in a pixel is greater than 16
    672             throw new UnsupportedOperationException(Messages.getString("awt.266")); //$NON-NLS-1$
    673         }
    674 
    675         return raster;
    676     }
    677 
    678     @Override
    679     public boolean isCompatibleSampleModel(SampleModel sm) {
    680         if (sm == null) {
    681             return false;
    682         }
    683 
    684         if (!(sm instanceof MultiPixelPackedSampleModel) && !(sm instanceof ComponentSampleModel)) {
    685             return false;
    686         }
    687 
    688         if (sm.getTransferType() != transferType) {
    689             return false;
    690         }
    691         if (sm.getNumBands() != 1) {
    692             return false;
    693         }
    694 
    695         return true;
    696     }
    697 
    698     @Override
    699     public SampleModel createCompatibleSampleModel(int w, int h) {
    700         if (pixel_bits == 1 || pixel_bits == 2 || pixel_bits == 4) {
    701             return new MultiPixelPackedSampleModel(DataBuffer.TYPE_BYTE, w, h, pixel_bits);
    702         }
    703         int bandOffsets[] = new int[1];
    704         bandOffsets[0] = 0;
    705         return new ComponentSampleModel(transferType, w, h, 1, w, bandOffsets);
    706 
    707     }
    708 
    709     @Override
    710     public boolean isCompatibleRaster(Raster raster) {
    711         int sampleSize = raster.getSampleModel().getSampleSize(0);
    712         return (raster.getTransferType() == transferType && raster.getNumBands() == 1 && (1 << sampleSize) >= mapSize);
    713     }
    714 
    715     @Override
    716     public int getDataElement(int components[], int offset) {
    717         int rgb = (components[offset] << 16) | (components[offset + 1]) << 8
    718                 | components[offset + 2];
    719 
    720         if (hasAlpha) {
    721             rgb |= components[offset + 3] << 24;
    722         } else {
    723             rgb |= 0xff000000;
    724         }
    725 
    726         int pixel;
    727 
    728         switch (transferType) {
    729             case DataBuffer.TYPE_BYTE:
    730                 byte ba[] = (byte[])getDataElements(rgb, null);
    731                 pixel = ba[0] & 0xff;
    732                 break;
    733             case DataBuffer.TYPE_USHORT:
    734                 short sa[] = (short[])getDataElements(rgb, null);
    735                 pixel = sa[0] & 0xffff;
    736                 break;
    737             default:
    738                 // awt.267=The transferType is invalid
    739                 throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$
    740         }
    741 
    742         return pixel;
    743     }
    744 
    745     /**
    746      * Gets the color map.
    747      *
    748      * @param rgb
    749      *            the destination array where the color map is written.
    750      */
    751     public final void getRGBs(int rgb[]) {
    752         System.arraycopy(colorMap, 0, rgb, 0, mapSize);
    753     }
    754 
    755     /**
    756      * Gets the red component of the color map.
    757      *
    758      * @param r
    759      *            the destination array.
    760      */
    761     public final void getReds(byte r[]) {
    762         for (int i = 0; i < mapSize; i++) {
    763             r[i] = (byte)(colorMap[i] >> 16);
    764         }
    765     }
    766 
    767     /**
    768      * Gets the green component of the color map.
    769      *
    770      * @param g
    771      *            the destination array.
    772      */
    773     public final void getGreens(byte g[]) {
    774         for (int i = 0; i < mapSize; i++) {
    775             g[i] = (byte)(colorMap[i] >> 8);
    776         }
    777     }
    778 
    779     /**
    780      * Gets the blue component of the color map.
    781      *
    782      * @param b
    783      *            the destination array.
    784      */
    785     public final void getBlues(byte b[]) {
    786         for (int i = 0; i < mapSize; i++) {
    787             b[i] = (byte)colorMap[i];
    788         }
    789     }
    790 
    791     /**
    792      * Gets the alpha component of the color map.
    793      *
    794      * @param a
    795      *            the destination array.
    796      */
    797     public final void getAlphas(byte a[]) {
    798         for (int i = 0; i < mapSize; i++) {
    799             a[i] = (byte)(colorMap[i] >> 24);
    800         }
    801     }
    802 
    803     @Override
    804     public int[] getComponents(int pixel, int components[], int offset) {
    805         if (components == null) {
    806             components = new int[offset + numComponents];
    807         }
    808 
    809         components[offset + 0] = getRed(pixel);
    810         components[offset + 1] = getGreen(pixel);
    811         components[offset + 2] = getBlue(pixel);
    812         if (hasAlpha && (components.length - offset) > 3) {
    813             components[offset + 3] = getAlpha(pixel);
    814         }
    815 
    816         return components;
    817     }
    818 
    819     /**
    820      * Checks if the specified pixel is valid for this color model.
    821      *
    822      * @param pixel
    823      *            the pixel.
    824      * @return true, if the pixel is valid.
    825      */
    826     public boolean isValid(int pixel) {
    827         if (validBits == null) {
    828             return (pixel >= 0 && pixel < mapSize);
    829         }
    830         return (pixel < mapSize && validBits.testBit(pixel));
    831     }
    832 
    833     @Override
    834     public final int getRed(int pixel) {
    835         return (colorMap[pixel] >> 16) & 0xff;
    836     }
    837 
    838     @Override
    839     public final int getRGB(int pixel) {
    840         return colorMap[pixel];
    841     }
    842 
    843     @Override
    844     public final int getGreen(int pixel) {
    845         return (colorMap[pixel] >> 8) & 0xff;
    846     }
    847 
    848     @Override
    849     public final int getBlue(int pixel) {
    850         return colorMap[pixel] & 0xff;
    851     }
    852 
    853     @Override
    854     public final int getAlpha(int pixel) {
    855         return (colorMap[pixel] >> 24) & 0xff;
    856     }
    857 
    858     @Override
    859     public int[] getComponentSize() {
    860         return bits.clone();
    861     }
    862 
    863     /**
    864      * Checks if this color model validates pixels.
    865      *
    866      * @return true, if all pixels are valid, otherwise false.
    867      */
    868     public boolean isValid() {
    869         return (validBits == null);
    870     }
    871 
    872     @Override
    873     public void finalize() {
    874         // TODO: implement
    875         return;
    876     }
    877 
    878     /**
    879      * Gets the index that represents the transparent pixel.
    880      *
    881      * @return the index that represents the transparent pixel.
    882      */
    883     public final int getTransparentPixel() {
    884         return transparentIndex;
    885     }
    886 
    887     @Override
    888     public int getTransparency() {
    889         return transparency;
    890     }
    891 
    892     /**
    893      * Gets the size of the color map.
    894      *
    895      * @return the map size.
    896      */
    897     public final int getMapSize() {
    898         return mapSize;
    899     }
    900 
    901     /**
    902      * Creates the color map.
    903      *
    904      * @param size
    905      *            the size.
    906      * @param r
    907      *            the r.
    908      * @param g
    909      *            the g.
    910      * @param b
    911      *            the b.
    912      * @param a
    913      *            the a.
    914      * @param trans
    915      *            the trans.
    916      */
    917     private void createColorMap(int size, byte r[], byte g[], byte b[], byte a[], int trans) {
    918         if (size < 1) {
    919             // awt.264=Size of the color map is less than 1
    920             throw new IllegalArgumentException(Messages.getString("awt.264")); //$NON-NLS-1$
    921         }
    922 
    923         mapSize = size;
    924         colorMap = new int[mapSize];
    925         if (trans >= 0 && trans < mapSize) {
    926             transparency = Transparency.BITMASK;
    927             transparentIndex = trans;
    928         } else {
    929             transparency = Transparency.OPAQUE;
    930             transparentIndex = -1;
    931         }
    932         int alpha = 0;
    933 
    934         for (int i = 0; i < mapSize; i++) {
    935             colorMap[i] = ((r[i] & 0xff) << 16) | ((g[i] & 0xff) << 8) | (b[i] & 0xff);
    936 
    937             if (trans == i) {
    938                 continue;
    939             }
    940 
    941             if (a == null) {
    942                 colorMap[i] |= 0xff000000;
    943             } else {
    944                 alpha = a[i] & 0xff;
    945                 if (alpha == 0xff) {
    946                     colorMap[i] |= 0xff000000;
    947                 } else if (alpha == 0) {
    948                     if (transparency == Transparency.OPAQUE) {
    949                         transparency = Transparency.BITMASK;
    950                     }
    951                     if (transparentIndex < 0) {
    952                         transparentIndex = i;
    953                     }
    954                 } else {
    955                     colorMap[i] |= (a[i] & 0xff) << 24;
    956                     if (transparency != Transparency.TRANSLUCENT) {
    957                         transparency = Transparency.TRANSLUCENT;
    958                     }
    959                 }
    960             }
    961 
    962         }
    963 
    964     }
    965 
    966     /**
    967      * This method checking, if Color Map has Gray palette.
    968      */
    969     private void checkPalette() {
    970         grayPalette = false;
    971         if (transparency > Transparency.OPAQUE) {
    972             return;
    973         }
    974         int rgb = 0;
    975 
    976         for (int i = 0; i < mapSize; i++) {
    977             rgb = colorMap[i];
    978             if (((rgb >> 16) & 0xff) != ((rgb >> 8) & 0xff) || ((rgb >> 8) & 0xff) != (rgb & 0xff)) {
    979                 return;
    980             }
    981         }
    982         grayPalette = true;
    983     }
    984 
    985     /**
    986      * Construction an array pixel representation.
    987      *
    988      * @param colorMapIdx
    989      *            the index into Color Map.
    990      * @param pixel
    991      *            the pixel
    992      * @return the pixel representation array.
    993      */
    994     private Object createDataObject(int colorMapIdx, Object pixel) {
    995         if (pixel == null) {
    996             switch (transferType) {
    997                 case DataBuffer.TYPE_BYTE:
    998                     byte[] ba = new byte[1];
    999                     ba[0] = (byte)colorMapIdx;
   1000                     pixel = ba;
   1001                     break;
   1002                 case DataBuffer.TYPE_USHORT:
   1003                     short[] sa = new short[1];
   1004                     sa[0] = (short)colorMapIdx;
   1005                     pixel = sa;
   1006                     break;
   1007                 default:
   1008                     // awt.267=The transferType is invalid
   1009                     throw new UnsupportedOperationException(Messages.getString("awt.267")); //$NON-NLS-1$
   1010             }
   1011         } else if (pixel instanceof byte[] && transferType == DataBuffer.TYPE_BYTE) {
   1012             byte ba[] = (byte[])pixel;
   1013             ba[0] = (byte)colorMapIdx;
   1014             pixel = ba;
   1015         } else if (pixel instanceof short[] && transferType == DataBuffer.TYPE_USHORT) {
   1016             short[] sa = (short[])pixel;
   1017             sa[0] = (short)colorMapIdx;
   1018             pixel = sa;
   1019         } else if (pixel instanceof int[]) {
   1020             int ia[] = (int[])pixel;
   1021             ia[0] = colorMapIdx;
   1022             pixel = ia;
   1023         } else {
   1024             // awt.268=The pixel is not a primitive array of type transferType
   1025             throw new ClassCastException(Messages.getString("awt.268")); //$NON-NLS-1$
   1026         }
   1027         return pixel;
   1028     }
   1029 
   1030     /**
   1031      * Creates the bits.
   1032      *
   1033      * @param hasAlpha
   1034      *            the has alpha.
   1035      * @return the int[].
   1036      */
   1037     private static int[] createBits(boolean hasAlpha) {
   1038 
   1039         int numChannels;
   1040         if (hasAlpha) {
   1041             numChannels = 4;
   1042         } else {
   1043             numChannels = 3;
   1044         }
   1045 
   1046         int bits[] = new int[numChannels];
   1047         for (int i = 0; i < numChannels; i++) {
   1048             bits[i] = 8;
   1049         }
   1050 
   1051         return bits;
   1052 
   1053     }
   1054 
   1055     /**
   1056      * Validate transfer type.
   1057      *
   1058      * @param transferType
   1059      *            the transfer type.
   1060      * @return the int.
   1061      */
   1062     private static int validateTransferType(int transferType) {
   1063         if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT) {
   1064             // awt.269=The transferType is not one of DataBuffer.TYPE_BYTE or
   1065             // DataBuffer.TYPE_USHORT
   1066             throw new IllegalArgumentException(Messages.getString("awt.269")); //$NON-NLS-1$
   1067         }
   1068         return transferType;
   1069     }
   1070 
   1071     /**
   1072      * Checks if is gray palette.
   1073      *
   1074      * @return true, if is gray palette.
   1075      */
   1076     boolean isGrayPallete() {
   1077         return grayPalette;
   1078     }
   1079 
   1080 }
   1081