jdk/src/java.desktop/share/classes/java/awt/image/PackedColorModel.java
changeset 25859 3317bb8137f4
parent 22584 eed64ee05369
child 32865 f9cb6e427f9e
equal deleted inserted replaced
25858:836adbf7a2cd 25859:3317bb8137f4
       
     1 /*
       
     2  * Copyright (c) 1997, 2014, 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 
       
    31 /**
       
    32  * The <code>PackedColorModel</code> class is an abstract
       
    33  * {@link ColorModel} class that works with pixel values which represent
       
    34  * color and alpha information as separate samples and which pack all
       
    35  * samples for a single pixel into a single int, short, or byte quantity.
       
    36  * This class can be used with an arbitrary {@link ColorSpace}.  The number of
       
    37  * color samples in the pixel values must be the same as the number of color
       
    38  * components in the <code>ColorSpace</code>.  There can be a single alpha
       
    39  * sample.  The array length is always 1 for those methods that use a
       
    40  * primitive array pixel representation of type <code>transferType</code>.
       
    41  * The transfer types supported are DataBuffer.TYPE_BYTE,
       
    42  * DataBuffer.TYPE_USHORT, and DataBuffer.TYPE_INT.
       
    43  * Color and alpha samples are stored in the single element of the array
       
    44  * in bits indicated by bit masks.  Each bit mask must be contiguous and
       
    45  * masks must not overlap.  The same masks apply to the single int
       
    46  * pixel representation used by other methods.  The correspondence of
       
    47  * masks and color/alpha samples is as follows:
       
    48  * <ul>
       
    49  * <li> Masks are identified by indices running from 0 through
       
    50  * {@link ColorModel#getNumComponents() getNumComponents}&nbsp;-&nbsp;1.
       
    51  * <li> The first
       
    52  * {@link ColorModel#getNumColorComponents() getNumColorComponents}
       
    53  * indices refer to color samples.
       
    54  * <li> If an alpha sample is present, it corresponds the last index.
       
    55  * <li> The order of the color indices is specified
       
    56  * by the <code>ColorSpace</code>.  Typically, this reflects the name of
       
    57  * the color space type (for example, TYPE_RGB), index 0
       
    58  * corresponds to red, index 1 to green, and index 2 to blue.
       
    59  * </ul>
       
    60  * <p>
       
    61  * The translation from pixel values to color/alpha components for
       
    62  * display or processing purposes is a one-to-one correspondence of
       
    63  * samples to components.
       
    64  * A <code>PackedColorModel</code> is typically used with image data
       
    65  * that uses masks to define packed samples.  For example, a
       
    66  * <code>PackedColorModel</code> can be used in conjunction with a
       
    67  * {@link SinglePixelPackedSampleModel} to construct a
       
    68  * {@link BufferedImage}.  Normally the masks used by the
       
    69  * {@link SampleModel} and the <code>ColorModel</code> would be the same.
       
    70  * However, if they are different, the color interpretation of pixel data is
       
    71  * done according to the masks of the <code>ColorModel</code>.
       
    72  * <p>
       
    73  * A single <code>int</code> pixel representation is valid for all objects
       
    74  * of this class since it is always possible to represent pixel values
       
    75  * used with this class in a single <code>int</code>.  Therefore, methods
       
    76  * that use this representation do not throw an
       
    77  * <code>IllegalArgumentException</code> due to an invalid pixel value.
       
    78  * <p>
       
    79  * A subclass of <code>PackedColorModel</code> is {@link DirectColorModel},
       
    80  * which is similar to an X11 TrueColor visual.
       
    81  *
       
    82  * @see DirectColorModel
       
    83  * @see SinglePixelPackedSampleModel
       
    84  * @see BufferedImage
       
    85  */
       
    86 
       
    87 public abstract class PackedColorModel extends ColorModel {
       
    88     int[] maskArray;
       
    89     int[] maskOffsets;
       
    90     float[] scaleFactors;
       
    91 
       
    92     /**
       
    93      * Constructs a <code>PackedColorModel</code> from a color mask array,
       
    94      * which specifies which bits in an <code>int</code> pixel representation
       
    95      * contain each of the color samples, and an alpha mask.  Color
       
    96      * components are in the specified <code>ColorSpace</code>.  The length of
       
    97      * <code>colorMaskArray</code> should be the number of components in
       
    98      * the <code>ColorSpace</code>.  All of the bits in each mask
       
    99      * must be contiguous and fit in the specified number of least significant
       
   100      * bits of an <code>int</code> pixel representation.  If the
       
   101      * <code>alphaMask</code> is 0, there is no alpha.  If there is alpha,
       
   102      * the <code>boolean</code> <code>isAlphaPremultiplied</code> specifies
       
   103      * how to interpret color and alpha samples in pixel values.  If the
       
   104      * <code>boolean</code> is <code>true</code>, color samples are assumed
       
   105      * to have been multiplied by the alpha sample.  The transparency,
       
   106      * <code>trans</code>, specifies what alpha values can be represented
       
   107      * by this color model.  The transfer type is the type of primitive
       
   108      * array used to represent pixel values.
       
   109      * @param space the specified <code>ColorSpace</code>
       
   110      * @param bits the number of bits in the pixel values
       
   111      * @param colorMaskArray array that specifies the masks representing
       
   112      *         the bits of the pixel values that represent the color
       
   113      *         components
       
   114      * @param alphaMask specifies the mask representing
       
   115      *         the bits of the pixel values that represent the alpha
       
   116      *         component
       
   117      * @param isAlphaPremultiplied <code>true</code> if color samples are
       
   118      *        premultiplied by the alpha sample; <code>false</code> otherwise
       
   119      * @param trans specifies the alpha value that can be represented by
       
   120      *        this color model
       
   121      * @param transferType the type of array used to represent pixel values
       
   122      * @throws IllegalArgumentException if <code>bits</code> is less than
       
   123      *         1 or greater than 32
       
   124      */
       
   125     public PackedColorModel (ColorSpace space, int bits,
       
   126                              int[] colorMaskArray, int alphaMask,
       
   127                              boolean isAlphaPremultiplied,
       
   128                              int trans, int transferType) {
       
   129         super(bits, PackedColorModel.createBitsArray(colorMaskArray,
       
   130                                                      alphaMask),
       
   131               space, (alphaMask == 0 ? false : true),
       
   132               isAlphaPremultiplied, trans, transferType);
       
   133         if (bits < 1 || bits > 32) {
       
   134             throw new IllegalArgumentException("Number of bits must be between"
       
   135                                                +" 1 and 32.");
       
   136         }
       
   137         maskArray   = new int[numComponents];
       
   138         maskOffsets = new int[numComponents];
       
   139         scaleFactors = new float[numComponents];
       
   140 
       
   141         for (int i=0; i < numColorComponents; i++) {
       
   142             // Get the mask offset and #bits
       
   143             DecomposeMask(colorMaskArray[i], i, space.getName(i));
       
   144         }
       
   145         if (alphaMask != 0) {
       
   146             DecomposeMask(alphaMask, numColorComponents, "alpha");
       
   147             if (nBits[numComponents-1] == 1) {
       
   148                 transparency = Transparency.BITMASK;
       
   149             }
       
   150         }
       
   151     }
       
   152 
       
   153     /**
       
   154      * Constructs a <code>PackedColorModel</code> from the specified
       
   155      * masks which indicate which bits in an <code>int</code> pixel
       
   156      * representation contain the alpha, red, green and blue color samples.
       
   157      * Color components are in the specified <code>ColorSpace</code>, which
       
   158      * must be of type ColorSpace.TYPE_RGB.  All of the bits in each
       
   159      * mask must be contiguous and fit in the specified number of
       
   160      * least significant bits of an <code>int</code> pixel representation.  If
       
   161      * <code>amask</code> is 0, there is no alpha.  If there is alpha,
       
   162      * the <code>boolean</code> <code>isAlphaPremultiplied</code>
       
   163      * specifies how to interpret color and alpha samples
       
   164      * in pixel values.  If the <code>boolean</code> is <code>true</code>,
       
   165      * color samples are assumed to have been multiplied by the alpha sample.
       
   166      * The transparency, <code>trans</code>, specifies what alpha values
       
   167      * can be represented by this color model.
       
   168      * The transfer type is the type of primitive array used to represent
       
   169      * pixel values.
       
   170      * @param space the specified <code>ColorSpace</code>
       
   171      * @param bits the number of bits in the pixel values
       
   172      * @param rmask specifies the mask representing
       
   173      *         the bits of the pixel values that represent the red
       
   174      *         color component
       
   175      * @param gmask specifies the mask representing
       
   176      *         the bits of the pixel values that represent the green
       
   177      *         color component
       
   178      * @param bmask specifies the mask representing
       
   179      *         the bits of the pixel values that represent
       
   180      *         the blue color component
       
   181      * @param amask specifies the mask representing
       
   182      *         the bits of the pixel values that represent
       
   183      *         the alpha component
       
   184      * @param isAlphaPremultiplied <code>true</code> if color samples are
       
   185      *        premultiplied by the alpha sample; <code>false</code> otherwise
       
   186      * @param trans specifies the alpha value that can be represented by
       
   187      *        this color model
       
   188      * @param transferType the type of array used to represent pixel values
       
   189      * @throws IllegalArgumentException if <code>space</code> is not a
       
   190      *         TYPE_RGB space
       
   191      * @see ColorSpace
       
   192      */
       
   193     public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask,
       
   194                             int bmask, int amask,
       
   195                             boolean isAlphaPremultiplied,
       
   196                             int trans, int transferType) {
       
   197         super (bits, PackedColorModel.createBitsArray(rmask, gmask, bmask,
       
   198                                                       amask),
       
   199                space, (amask == 0 ? false : true),
       
   200                isAlphaPremultiplied, trans, transferType);
       
   201 
       
   202         if (space.getType() != ColorSpace.TYPE_RGB) {
       
   203             throw new IllegalArgumentException("ColorSpace must be TYPE_RGB.");
       
   204         }
       
   205         maskArray = new int[numComponents];
       
   206         maskOffsets = new int[numComponents];
       
   207         scaleFactors = new float[numComponents];
       
   208 
       
   209         DecomposeMask(rmask, 0, "red");
       
   210 
       
   211         DecomposeMask(gmask, 1, "green");
       
   212 
       
   213         DecomposeMask(bmask, 2, "blue");
       
   214 
       
   215         if (amask != 0) {
       
   216             DecomposeMask(amask, 3, "alpha");
       
   217             if (nBits[3] == 1) {
       
   218                 transparency = Transparency.BITMASK;
       
   219             }
       
   220         }
       
   221     }
       
   222 
       
   223     /**
       
   224      * Returns the mask indicating which bits in a pixel
       
   225      * contain the specified color/alpha sample.  For color
       
   226      * samples, <code>index</code> corresponds to the placement of color
       
   227      * sample names in the color space.  Thus, an <code>index</code>
       
   228      * equal to 0 for a CMYK ColorSpace would correspond to
       
   229      * Cyan and an <code>index</code> equal to 1 would correspond to
       
   230      * Magenta.  If there is alpha, the alpha <code>index</code> would be:
       
   231      * <pre>
       
   232      *      alphaIndex = numComponents() - 1;
       
   233      * </pre>
       
   234      * @param index the specified color or alpha sample
       
   235      * @return the mask, which indicates which bits of the <code>int</code>
       
   236      *         pixel representation contain the color or alpha sample specified
       
   237      *         by <code>index</code>.
       
   238      * @throws ArrayIndexOutOfBoundsException if <code>index</code> is
       
   239      *         greater than the number of components minus 1 in this
       
   240      *         <code>PackedColorModel</code> or if <code>index</code> is
       
   241      *         less than zero
       
   242      */
       
   243     final public int getMask(int index) {
       
   244         return maskArray[index];
       
   245     }
       
   246 
       
   247     /**
       
   248      * Returns a mask array indicating which bits in a pixel
       
   249      * contain the color and alpha samples.
       
   250      * @return the mask array , which indicates which bits of the
       
   251      *         <code>int</code> pixel
       
   252      *         representation contain the color or alpha samples.
       
   253      */
       
   254     final public int[] getMasks() {
       
   255         return maskArray.clone();
       
   256     }
       
   257 
       
   258     /*
       
   259      * A utility function to compute the mask offset and scalefactor,
       
   260      * store these and the mask in instance arrays, and verify that
       
   261      * the mask fits in the specified pixel size.
       
   262      */
       
   263     private void DecomposeMask(int mask,  int idx, String componentName) {
       
   264         int off = 0;
       
   265         int count = nBits[idx];
       
   266 
       
   267         // Store the mask
       
   268         maskArray[idx]   = mask;
       
   269 
       
   270         // Now find the shift
       
   271         if (mask != 0) {
       
   272             while ((mask & 1) == 0) {
       
   273                 mask >>>= 1;
       
   274                 off++;
       
   275             }
       
   276         }
       
   277 
       
   278         if (off + count > pixel_bits) {
       
   279             throw new IllegalArgumentException(componentName + " mask "+
       
   280                                         Integer.toHexString(maskArray[idx])+
       
   281                                                " overflows pixel (expecting "+
       
   282                                                pixel_bits+" bits");
       
   283         }
       
   284 
       
   285         maskOffsets[idx] = off;
       
   286         if (count == 0) {
       
   287             // High enough to scale any 0-ff value down to 0.0, but not
       
   288             // high enough to get Infinity when scaling back to pixel bits
       
   289             scaleFactors[idx] = 256.0f;
       
   290         } else {
       
   291             scaleFactors[idx] = 255.0f / ((1 << count) - 1);
       
   292         }
       
   293 
       
   294     }
       
   295 
       
   296     /**
       
   297      * Creates a <code>SampleModel</code> with the specified width and
       
   298      * height that has a data layout compatible with this
       
   299      * <code>ColorModel</code>.
       
   300      * @param w the width (in pixels) of the region of the image data
       
   301      *          described
       
   302      * @param h the height (in pixels) of the region of the image data
       
   303      *          described
       
   304      * @return the newly created <code>SampleModel</code>.
       
   305      * @throws IllegalArgumentException if <code>w</code> or
       
   306      *         <code>h</code> is not greater than 0
       
   307      * @see SampleModel
       
   308      */
       
   309     public SampleModel createCompatibleSampleModel(int w, int h) {
       
   310         return new SinglePixelPackedSampleModel(transferType, w, h,
       
   311                                                 maskArray);
       
   312     }
       
   313 
       
   314     /**
       
   315      * Checks if the specified <code>SampleModel</code> is compatible
       
   316      * with this <code>ColorModel</code>.  If <code>sm</code> is
       
   317      * <code>null</code>, this method returns <code>false</code>.
       
   318      * @param sm the specified <code>SampleModel</code>,
       
   319      * or <code>null</code>
       
   320      * @return <code>true</code> if the specified <code>SampleModel</code>
       
   321      *         is compatible with this <code>ColorModel</code>;
       
   322      *         <code>false</code> otherwise.
       
   323      * @see SampleModel
       
   324      */
       
   325     public boolean isCompatibleSampleModel(SampleModel sm) {
       
   326         if (! (sm instanceof SinglePixelPackedSampleModel)) {
       
   327             return false;
       
   328         }
       
   329 
       
   330         // Must have the same number of components
       
   331         if (numComponents != sm.getNumBands()) {
       
   332             return false;
       
   333         }
       
   334 
       
   335         // Transfer type must be the same
       
   336         if (sm.getTransferType() != transferType) {
       
   337             return false;
       
   338         }
       
   339 
       
   340         SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sm;
       
   341         // Now compare the specific masks
       
   342         int[] bitMasks = sppsm.getBitMasks();
       
   343         if (bitMasks.length != maskArray.length) {
       
   344             return false;
       
   345         }
       
   346 
       
   347         /* compare 'effective' masks only, i.e. only part of the mask
       
   348          * which fits the capacity of the transfer type.
       
   349          */
       
   350         int maxMask = (int)((1L << DataBuffer.getDataTypeSize(transferType)) - 1);
       
   351         for (int i=0; i < bitMasks.length; i++) {
       
   352             if ((maxMask & bitMasks[i]) != (maxMask & maskArray[i])) {
       
   353                 return false;
       
   354             }
       
   355         }
       
   356 
       
   357         return true;
       
   358     }
       
   359 
       
   360     /**
       
   361      * Returns a {@link WritableRaster} representing the alpha channel of
       
   362      * an image, extracted from the input <code>WritableRaster</code>.
       
   363      * This method assumes that <code>WritableRaster</code> objects
       
   364      * associated with this <code>ColorModel</code> store the alpha band,
       
   365      * if present, as the last band of image data.  Returns <code>null</code>
       
   366      * if there is no separate spatial alpha channel associated with this
       
   367      * <code>ColorModel</code>.  This method creates a new
       
   368      * <code>WritableRaster</code>, but shares the data array.
       
   369      * @param raster a <code>WritableRaster</code> containing an image
       
   370      * @return a <code>WritableRaster</code> that represents the alpha
       
   371      *         channel of the image contained in <code>raster</code>.
       
   372      */
       
   373     public WritableRaster getAlphaRaster(WritableRaster raster) {
       
   374         if (hasAlpha() == false) {
       
   375             return null;
       
   376         }
       
   377 
       
   378         int x = raster.getMinX();
       
   379         int y = raster.getMinY();
       
   380         int[] band = new int[1];
       
   381         band[0] = raster.getNumBands() - 1;
       
   382         return raster.createWritableChild(x, y, raster.getWidth(),
       
   383                                           raster.getHeight(), x, y,
       
   384                                           band);
       
   385     }
       
   386 
       
   387     /**
       
   388      * Tests if the specified <code>Object</code> is an instance
       
   389      * of <code>PackedColorModel</code> and equals this
       
   390      * <code>PackedColorModel</code>.
       
   391      * @param obj the <code>Object</code> to test for equality
       
   392      * @return <code>true</code> if the specified <code>Object</code>
       
   393      * is an instance of <code>PackedColorModel</code> and equals this
       
   394      * <code>PackedColorModel</code>; <code>false</code> otherwise.
       
   395      */
       
   396     public boolean equals(Object obj) {
       
   397         if (!(obj instanceof PackedColorModel)) {
       
   398             return false;
       
   399         }
       
   400 
       
   401         if (!super.equals(obj)) {
       
   402             return false;
       
   403         }
       
   404 
       
   405         PackedColorModel cm = (PackedColorModel) obj;
       
   406         int numC = cm.getNumComponents();
       
   407         if (numC != numComponents) {
       
   408             return false;
       
   409         }
       
   410         for(int i=0; i < numC; i++) {
       
   411             if (maskArray[i] != cm.getMask(i)) {
       
   412                 return false;
       
   413             }
       
   414         }
       
   415         return true;
       
   416     }
       
   417 
       
   418     private final static int[] createBitsArray(int[]colorMaskArray,
       
   419                                                int alphaMask) {
       
   420         int numColors = colorMaskArray.length;
       
   421         int numAlpha = (alphaMask == 0 ? 0 : 1);
       
   422         int[] arr = new int[numColors+numAlpha];
       
   423         for (int i=0; i < numColors; i++) {
       
   424             arr[i] = countBits(colorMaskArray[i]);
       
   425             if (arr[i] < 0) {
       
   426                 throw new IllegalArgumentException("Noncontiguous color mask ("
       
   427                                      + Integer.toHexString(colorMaskArray[i])+
       
   428                                      "at index "+i);
       
   429             }
       
   430         }
       
   431         if (alphaMask != 0) {
       
   432             arr[numColors] = countBits(alphaMask);
       
   433             if (arr[numColors] < 0) {
       
   434                 throw new IllegalArgumentException("Noncontiguous alpha mask ("
       
   435                                      + Integer.toHexString(alphaMask));
       
   436             }
       
   437         }
       
   438         return arr;
       
   439     }
       
   440 
       
   441     private final static int[] createBitsArray(int rmask, int gmask, int bmask,
       
   442                                          int amask) {
       
   443         int[] arr = new int[3 + (amask == 0 ? 0 : 1)];
       
   444         arr[0] = countBits(rmask);
       
   445         arr[1] = countBits(gmask);
       
   446         arr[2] = countBits(bmask);
       
   447         if (arr[0] < 0) {
       
   448             throw new IllegalArgumentException("Noncontiguous red mask ("
       
   449                                      + Integer.toHexString(rmask));
       
   450         }
       
   451         else if (arr[1] < 0) {
       
   452             throw new IllegalArgumentException("Noncontiguous green mask ("
       
   453                                      + Integer.toHexString(gmask));
       
   454         }
       
   455         else if (arr[2] < 0) {
       
   456             throw new IllegalArgumentException("Noncontiguous blue mask ("
       
   457                                      + Integer.toHexString(bmask));
       
   458         }
       
   459         if (amask != 0) {
       
   460             arr[3] = countBits(amask);
       
   461             if (arr[3] < 0) {
       
   462                 throw new IllegalArgumentException("Noncontiguous alpha mask ("
       
   463                                      + Integer.toHexString(amask));
       
   464             }
       
   465         }
       
   466         return arr;
       
   467     }
       
   468 
       
   469     private final static int countBits(int mask) {
       
   470         int count = 0;
       
   471         if (mask != 0) {
       
   472             while ((mask & 1) == 0) {
       
   473                 mask >>>= 1;
       
   474             }
       
   475             while ((mask & 1) == 1) {
       
   476                 mask >>>= 1;
       
   477                 count++;
       
   478             }
       
   479         }
       
   480         if (mask != 0) {
       
   481             return -1;
       
   482         }
       
   483         return count;
       
   484     }
       
   485 
       
   486 }