KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > java > awt > image > PackedColorModel


1 /*
2  * @(#)PackedColorModel.java 1.38 03/12/19
3  *
4  * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
5  * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
6  */

7
8 package java.awt.image;
9
10 import java.awt.Transparency JavaDoc;
11 import java.awt.color.ColorSpace JavaDoc;
12
13 /**
14  * The <code>PackedColorModel</code> class is an abstract
15  * {@link ColorModel} class that works with pixel values which represent
16  * color and alpha information as separate samples and which pack all
17  * samples for a single pixel into a single int, short, or byte quantity.
18  * This class can be used with an arbitrary {@link ColorSpace}. The number of
19  * color samples in the pixel values must be the same as the number of color
20  * components in the <code>ColorSpace</code>. There can be a single alpha
21  * sample. The array length is always 1 for those methods that use a
22  * primitive array pixel representation of type <code>transferType</code>.
23  * The transfer types supported are DataBuffer.TYPE_BYTE,
24  * DataBuffer.TYPE_USHORT, and DataBuffer.TYPE_INT.
25  * Color and alpha samples are stored in the single element of the array
26  * in bits indicated by bit masks. Each bit mask must be contiguous and
27  * masks must not overlap. The same masks apply to the single int
28  * pixel representation used by other methods. The correspondence of
29  * masks and color/alpha samples is as follows:
30  * <ul>
31  * <li> Masks are identified by indices running from 0 through
32  * {@link ColorModel#getNumComponents() getNumComponents}&nbsp;-&nbsp;1.
33  * <li> The first
34  * {@link ColorModel#getNumColorComponents() getNumColorComponents}
35  * indices refer to color samples.
36  * <li> If an alpha sample is present, it corresponds the last index.
37  * <li> The order of the color indices is specified
38  * by the <code>ColorSpace</code>. Typically, this reflects the name of
39  * the color space type (for example, TYPE_RGB), index 0
40  * corresponds to red, index 1 to green, and index 2 to blue.
41  * </ul>
42  * <p>
43  * The translation from pixel values to color/alpha components for
44  * display or processing purposes is a one-to-one correspondence of
45  * samples to components.
46  * A <code>PackedColorModel</code> is typically used with image data
47  * that uses masks to define packed samples. For example, a
48  * <code>PackedColorModel</code> can be used in conjunction with a
49  * {@link SinglePixelPackedSampleModel} to construct a
50  * {@link BufferedImage}. Normally the masks used by the
51  * {@link SampleModel} and the <code>ColorModel</code> would be the same.
52  * However, if they are different, the color interpretation of pixel data is
53  * done according to the masks of the <code>ColorModel</code>.
54  * <p>
55  * A single <code>int</code> pixel representation is valid for all objects
56  * of this class since it is always possible to represent pixel values
57  * used with this class in a single <code>int</code>. Therefore, methods
58  * that use this representation do not throw an
59  * <code>IllegalArgumentException</code> due to an invalid pixel value.
60  * <p>
61  * A subclass of <code>PackedColorModel</code> is {@link DirectColorModel},
62  * which is similar to an X11 TrueColor visual.
63  *
64  * @see DirectColorModel
65  * @see SinglePixelPackedSampleModel
66  * @see BufferedImage
67  * @version 10 Feb 1997
68  */

69
70 public abstract class PackedColorModel extends ColorModel JavaDoc {
71     int[] maskArray;
72     int[] maskOffsets;
73     float[] scaleFactors;
74
75     /**
76      * Constructs a <code>PackedColorModel</code> from a color mask array,
77      * which specifies which bits in an <code>int</code> pixel representation
78      * contain each of the color samples, and an alpha mask. Color
79      * components are in the specified <code>ColorSpace</code>. The length of
80      * <code>colorMaskArray</code> should be the number of components in
81      * the <code>ColorSpace</code>. All of the bits in each mask
82      * must be contiguous and fit in the specified number of least significant
83      * bits of an <code>int</code> pixel representation. If the
84      * <code>alphaMask</code> is 0, there is no alpha. If there is alpha,
85      * the <code>boolean</code> <code>isAlphaPremultiplied</code> specifies
86      * how to interpret color and alpha samples in pixel values. If the
87      * <code>boolean</code> is <code>true</code>, color samples are assumed
88      * to have been multiplied by the alpha sample. The transparency,
89      * <code>trans</code>, specifies what alpha values can be represented
90      * by this color model. The transfer type is the type of primitive
91      * array used to represent pixel values.
92      * @param space the specified <code>ColorSpace</code>
93      * @param bits the number of bits in the pixel values
94      * @param colorMaskArray array that specifies the masks representing
95      * the bits of the pixel values that represent the color
96      * components
97      * @param alphaMask specifies the mask representing
98      * the bits of the pixel values that represent the alpha
99      * component
100      * @param isAlphaPremultiplied <code>true</code> if color samples are
101      * premultiplied by the alpha sample; <code>false</code> otherwise
102      * @param trans specifies the alpha value that can be represented by
103      * this color model
104      * @param transferType the type of array used to represent pixel values
105      * @throws IllegalArgumentException if <code>bits</code> is less than
106      * 1 or greater than 32
107      */

108     public PackedColorModel (ColorSpace JavaDoc space, int bits,
109                              int[] colorMaskArray, int alphaMask,
110                              boolean isAlphaPremultiplied,
111                              int trans, int transferType) {
112         super(bits, PackedColorModel.createBitsArray(colorMaskArray,
113                                                      alphaMask),
114               space, (alphaMask == 0 ? false : true),
115               isAlphaPremultiplied, trans, transferType);
116         if (bits < 1 || bits > 32) {
117             throw new IllegalArgumentException JavaDoc("Number of bits must be between"
118                                                +" 1 and 32.");
119         }
120         maskArray = new int[numComponents];
121         maskOffsets = new int[numComponents];
122         scaleFactors = new float[numComponents];
123
124         for (int i=0; i < numColorComponents; i++) {
125             // Get the mask offset and #bits
126
DecomposeMask(colorMaskArray[i], i, space.getName(i));
127         }
128         if (alphaMask != 0) {
129             DecomposeMask(alphaMask, numColorComponents, "alpha");
130             if (nBits[numComponents-1] == 1) {
131                 transparency = Transparency.BITMASK;
132             }
133         }
134     }
135
136     /**
137      * Constructs a <code>PackedColorModel</code> from the specified
138      * masks which indicate which bits in an <code>int</code> pixel
139      * representation contain the alpha, red, green and blue color samples.
140      * Color components are in the specified <code>ColorSpace</code>, which
141      * must be of type ColorSpace.TYPE_RGB. All of the bits in each
142      * mask must be contiguous and fit in the specified number of
143      * least significant bits of an <code>int</code> pixel representation. If
144      * <code>amask</code> is 0, there is no alpha. If there is alpha,
145      * the <code>boolean</code> <code>isAlphaPremultiplied</code>
146      * specifies how to interpret color and alpha samples
147      * in pixel values. If the <code>boolean</code> is <code>true</code>,
148      * color samples are assumed to have been multiplied by the alpha sample.
149      * The transparency, <code>trans</code>, specifies what alpha values
150      * can be represented by this color model.
151      * The transfer type is the type of primitive array used to represent
152      * pixel values.
153      * @param space the specified <code>ColorSpace</code>
154      * @param bits the number of bits in the pixel values
155      * @param rmask specifies the mask representing
156      * the bits of the pixel values that represent the red
157      * color component
158      * @param gmask specifies the mask representing
159      * the bits of the pixel values that represent the green
160      * color component
161      * @param bmask specifies the mask representing
162      * the bits of the pixel values that represent
163      * the blue color component
164      * @param amask specifies the mask representing
165      * the bits of the pixel values that represent
166      * the alpha component
167      * @param isAlphaPremultiplied <code>true</code> if color samples are
168      * premultiplied by the alpha sample; <code>false</code> otherwise
169      * @param trans specifies the alpha value that can be represented by
170      * this color model
171      * @param transferType the type of array used to represent pixel values
172      * @throws IllegalArgumentException if <code>space</code> is not a
173      * TYPE_RGB space
174      * @see ColorSpace
175      */

176     public PackedColorModel(ColorSpace JavaDoc space, int bits, int rmask, int gmask,
177                             int bmask, int amask,
178                             boolean isAlphaPremultiplied,
179                             int trans, int transferType) {
180         super (bits, PackedColorModel.createBitsArray(rmask, gmask, bmask,
181                                                       amask),
182                space, (amask == 0 ? false : true),
183                isAlphaPremultiplied, trans, transferType);
184
185         if (space.getType() != ColorSpace.TYPE_RGB) {
186             throw new IllegalArgumentException JavaDoc("ColorSpace must be TYPE_RGB.");
187         }
188         maskArray = new int[numComponents];
189         maskOffsets = new int[numComponents];
190         scaleFactors = new float[numComponents];
191
192         DecomposeMask(rmask, 0, "red");
193
194         DecomposeMask(gmask, 1, "green");
195
196         DecomposeMask(bmask, 2, "blue");
197
198         if (amask != 0) {
199             DecomposeMask(amask, 3, "alpha");
200             if (nBits[3] == 1) {
201                 transparency = Transparency.BITMASK;
202             }
203         }
204     }
205
206     /**
207      * Returns the mask indicating which bits in a pixel
208      * contain the specified color/alpha sample. For color
209      * samples, <code>index</code> corresponds to the placement of color
210      * sample names in the color space. Thus, an <code>index</code>
211      * equal to 0 for a CMYK ColorSpace would correspond to
212      * Cyan and an <code>index</code> equal to 1 would correspond to
213      * Magenta. If there is alpha, the alpha <code>index</code> would be:
214      * <pre>
215      * alphaIndex = numComponents() - 1;
216      * </pre>
217      * @param index the specified color or alpha sample
218      * @return the mask, which indicates which bits of the <code>int</code>
219      * pixel representation contain the color or alpha sample specified
220      * by <code>index</code>.
221      * @throws ArrayIndexOutOfBoundsException if <code>index</code> is
222      * greater than the number of components minus 1 in this
223      * <code>PackedColorModel</code> or if <code>index</code> is
224      * less than zero
225      */

226     final public int getMask(int index) {
227     return maskArray[index];
228     }
229
230     /**
231      * Returns a mask array indicating which bits in a pixel
232      * contain the color and alpha samples.
233      * @return the mask array , which indicates which bits of the
234      * <code>int</code> pixel
235      * representation contain the color or alpha samples.
236      */

237     final public int[] getMasks() {
238     return (int[]) maskArray.clone();
239     }
240
241     /*
242      * A utility function to compute the mask offset and scalefactor,
243      * store these and the mask in instance arrays, and verify that
244      * the mask fits in the specified pixel size.
245      */

246     private void DecomposeMask(int mask, int idx, String JavaDoc componentName) {
247     int off = 0;
248     int count = nBits[idx];
249
250         // Store the mask
251
maskArray[idx] = mask;
252
253         // Now find the shift
254
if (mask != 0) {
255         while ((mask & 1) == 0) {
256         mask >>>= 1;
257         off++;
258         }
259     }
260
261     if (off + count > pixel_bits) {
262         throw new IllegalArgumentException JavaDoc(componentName + " mask "+
263                                         Integer.toHexString(maskArray[idx])+
264                                                " overflows pixel (expecting "+
265                                                pixel_bits+" bits");
266     }
267
268     maskOffsets[idx] = off;
269     if (count == 0) {
270         // High enough to scale any 0-ff value down to 0.0, but not
271
// high enough to get Infinity when scaling back to pixel bits
272
scaleFactors[idx] = 256.0f;
273     } else {
274         scaleFactors[idx] = 255.0f / ((1 << count) - 1);
275     }
276
277     }
278
279     /**
280      * Creates a <code>SampleModel</code> with the specified width and
281      * height that has a data layout compatible with this
282      * <code>ColorModel</code>.
283      * @param w the width (in pixels) of the region of the image data
284      * described
285      * @param h the height (in pixels) of the region of the image data
286      * described
287      * @return the newly created <code>SampleModel</code>.
288      * @throws IllegalArgumentException if <code>w</code> or
289      * <code>h</code> is not greater than 0
290      * @see SampleModel
291      */

292     public SampleModel JavaDoc createCompatibleSampleModel(int w, int h) {
293         return new SinglePixelPackedSampleModel JavaDoc(transferType, w, h,
294                                                 maskArray);
295     }
296     
297     /**
298      * Checks if the specified <code>SampleModel</code> is compatible
299      * with this <code>ColorModel</code>. If <code>sm</code> is
300      * <code>null</code>, this method returns <code>false</code>.
301      * @param sm the specified <code>SampleModel</code>,
302      * or <code>null</code>
303      * @return <code>true</code> if the specified <code>SampleModel</code>
304      * is compatible with this <code>ColorModel</code>;
305      * <code>false</code> otherwise.
306      * @see SampleModel
307      */

308     public boolean isCompatibleSampleModel(SampleModel JavaDoc sm) {
309         if (! (sm instanceof SinglePixelPackedSampleModel JavaDoc)) {
310             return false;
311         }
312
313         // Must have the same number of components
314
if (numComponents != sm.getNumBands()) {
315             return false;
316         }
317         
318         // Transfer type must be the same
319
if (sm.getTransferType() != transferType) {
320             return false;
321         }
322
323         SinglePixelPackedSampleModel JavaDoc sppsm = (SinglePixelPackedSampleModel JavaDoc) sm;
324         // Now compare the specific masks
325
int[] bitMasks = sppsm.getBitMasks();
326         if (bitMasks.length != maskArray.length) {
327             return false;
328         }
329         for (int i=0; i < bitMasks.length; i++) {
330             if (bitMasks[i] != maskArray[i]) {
331                 return false;
332             }
333         }
334
335         return true;
336     }
337
338     /**
339      * Returns a {@link WritableRaster} representing the alpha channel of
340      * an image, extracted from the input <code>WritableRaster</code>.
341      * This method assumes that <code>WritableRaster</code> objects
342      * associated with this <code>ColorModel</code> store the alpha band,
343      * if present, as the last band of image data. Returns <code>null</code>
344      * if there is no separate spatial alpha channel associated with this
345      * <code>ColorModel</code>. This method creates a new
346      * <code>WritableRaster</code>, but shares the data array.
347      * @param raster a <code>WritableRaster</code> containing an image
348      * @return a <code>WritableRaster</code> that represents the alpha
349      * channel of the image contained in <code>raster</code>.
350      */

351     public WritableRaster JavaDoc getAlphaRaster(WritableRaster JavaDoc raster) {
352         if (hasAlpha() == false) {
353             return null;
354         }
355
356         int x = raster.getMinX();
357         int y = raster.getMinY();
358         int[] band = new int[1];
359         band[0] = raster.getNumBands() - 1;
360         return raster.createWritableChild(x, y, raster.getWidth(),
361                                           raster.getHeight(), x, y,
362                                           band);
363     }
364
365     /**
366      * Tests if the specified <code>Object</code> is an instance
367      * of <code>PackedColorModel</code> and equals this
368      * <code>PackedColorModel</code>.
369      * @param obj the <code>Object</code> to test for equality
370      * @return <code>true</code> if the specified <code>Object</code>
371      * is an instance of <code>PackedColorModel</code> and equals this
372      * <code>PackedColorModel</code>; <code>false</code> otherwise.
373      */

374     public boolean equals(Object JavaDoc obj) {
375         if (!(obj instanceof PackedColorModel JavaDoc)) {
376             return false;
377         }
378
379         if (!super.equals(obj)) {
380             return false;
381         }
382
383         PackedColorModel JavaDoc cm = (PackedColorModel JavaDoc) obj;
384         int numC = cm.getNumComponents();
385         if (numC != numComponents) {
386             return false;
387         }
388         for(int i=0; i < numC; i++) {
389             if (maskArray[i] != cm.getMask(i)) {
390                 return false;
391             }
392         }
393         return true;
394     }
395
396     private final static int[] createBitsArray(int[]colorMaskArray,
397                                                int alphaMask) {
398         int numColors = colorMaskArray.length;
399         int numAlpha = (alphaMask == 0 ? 0 : 1);
400         int[] arr = new int[numColors+numAlpha];
401         for (int i=0; i < numColors; i++) {
402             arr[i] = countBits(colorMaskArray[i]);
403             if (arr[i] < 0) {
404                 throw new IllegalArgumentException JavaDoc("Noncontiguous color mask ("
405                                      + Integer.toHexString(colorMaskArray[i])+
406                                      "at index "+i);
407             }
408         }
409         if (alphaMask != 0) {
410             arr[numColors] = countBits(alphaMask);
411             if (arr[numColors] < 0) {
412                 throw new IllegalArgumentException JavaDoc("Noncontiguous alpha mask ("
413                                      + Integer.toHexString(alphaMask));
414             }
415         }
416         return arr;
417     }
418
419     private final static int[] createBitsArray(int rmask, int gmask, int bmask,
420                                          int amask) {
421         int[] arr = new int[3 + (amask == 0 ? 0 : 1)];
422         arr[0] = countBits(rmask);
423         arr[1] = countBits(gmask);
424         arr[2] = countBits(bmask);
425         if (arr[0] < 0) {
426             throw new IllegalArgumentException JavaDoc("Noncontiguous red mask ("
427                                      + Integer.toHexString(rmask));
428         }
429         else if (arr[1] < 0) {
430             throw new IllegalArgumentException JavaDoc("Noncontiguous green mask ("
431                                      + Integer.toHexString(gmask));
432         }
433         else if (arr[2] < 0) {
434             throw new IllegalArgumentException JavaDoc("Noncontiguous blue mask ("
435                                      + Integer.toHexString(bmask));
436         }
437         if (amask != 0) {
438             arr[3] = countBits(amask);
439             if (arr[3] < 0) {
440                 throw new IllegalArgumentException JavaDoc("Noncontiguous alpha mask ("
441                                      + Integer.toHexString(amask));
442             }
443         }
444         return arr;
445     }
446
447     private final static int countBits(int mask) {
448         int count = 0;
449     if (mask != 0) {
450         while ((mask & 1) == 0) {
451         mask >>>= 1;
452         }
453         while ((mask & 1) == 1) {
454         mask >>>= 1;
455         count++;
456         }
457     }
458         if (mask != 0) {
459             return -1;
460         }
461         return count;
462     }
463
464 }
465
Popular Tags