001: /*
002: * @(#)DirectColorModel.java 1.28 06/10/10
003: *
004: * Copyright 1990-2006 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER
006: *
007: * This program is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU General Public License version
009: * 2 only, as published by the Free Software Foundation.
010: *
011: * This program is distributed in the hope that it will be useful, but
012: * WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * General Public License version 2 for more details (a copy is
015: * included at /legal/license.txt).
016: *
017: * You should have received a copy of the GNU General Public License
018: * version 2 along with this work; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
020: * 02110-1301 USA
021: *
022: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
023: * Clara, CA 95054 or visit www.sun.com if you need additional
024: * information or have any questions.
025: *
026: */
027:
028: package java.awt.image;
029:
030: import java.awt.AWTException;
031: import java.awt.Transparency;
032: import java.awt.color.ColorSpace;
033:
034: /**
035: * A ColorModel class that specifies a translation from pixel values
036: * to alpha, red, green, and blue color components for pixels which
037: * have the color components embedded directly in the bits of the
038: * pixel itself. This color model is similar to an X11 TrueColor
039: * visual.
040:
041: * <p>Many of the methods in this class are final. This is because the
042: * underlying native graphics code makes assumptions about the layout
043: * and operation of this class and those assumptions are reflected in
044: * the implementations of the methods here that are marked final. You
045: * can subclass this class for other reaons, but you cannot override
046: * or modify the behaviour of those methods.
047: *
048: * @see ColorModel
049: *
050: * @version 1.24 08/21/02
051: * @author Jim Graham
052: */
053: public class DirectColorModel extends ColorModel {
054: private int red_mask;
055: private int green_mask;
056: private int blue_mask;
057: private int alpha_mask;
058: private int red_offset;
059: private int green_offset;
060: private int blue_offset;
061: private int alpha_offset;
062: private int red_scale;
063: private int green_scale;
064: private int blue_scale;
065: private int alpha_scale;
066:
067: /**
068: * Constructs a DirectColorModel from the given masks specifying
069: * which bits in the pixel contain the red, green and blue color
070: * components. Pixels described by this color model will all
071: * have alpha components of 255 (fully opaque). All of the bits
072: * in each mask must be contiguous and fit in the specified number
073: * of least significant bits of the integer.
074: */
075: public DirectColorModel(int bits, int rmask, int gmask, int bmask) {
076: this (bits, rmask, gmask, bmask, 0);
077: }
078:
079: /**
080: * Constructs a DirectColorModel from the given masks specifying
081: * which bits in the pixel contain the alhpa, red, green and blue
082: * color components. All of the bits in each mask must be contiguous
083: * and fit in the specified number of least significant bits of the
084: * integer.
085: */
086: public DirectColorModel(int bits, int rmask, int gmask, int bmask,
087: int amask) {
088: super (bits);
089: nBits = createBitsArray(rmask, gmask, bmask, amask);
090: red_mask = rmask;
091: green_mask = gmask;
092: blue_mask = bmask;
093: alpha_mask = amask;
094: calculateOffsets();
095: /* 4709812
096: * Set transparency to OPAQUE if amask is 0.
097: */
098: if (amask == 0) {
099: supportsAlpha = false;
100: transparency = Transparency.OPAQUE;
101: }
102: }
103:
104: /**
105: * Constructs a <code>DirectColorModel</code> from the specified
106: * parameters. Color components are in the specified
107: * <code>ColorSpace</code>, which must be of type ColorSpace.TYPE_RGB.
108: * The masks specify which bits in an <code>int</code> pixel
109: * representation contain the red, green and blue color samples and
110: * the alpha sample, if present. If <code>amask</code> is 0, pixel
111: * values do not contain alpha information and all pixels are treated
112: * as opaque, which means that alpha = 1.0. All of the
113: * bits in each mask must be contiguous and fit in the specified number
114: * of least significant bits of an <code>int</code> pixel
115: * representation. If there is alpha, the <code>boolean</code>
116: * <code>isAlphaPremultiplied</code> specifies how to interpret
117: * color and alpha samples in pixel values. If the <code>boolean</code>
118: * is <code>true</code>, color samples are assumed to have been
119: * multiplied by the alpha sample. The transparency value is
120: * Transparency.OPAQUE, if no alpha is present, or
121: * Transparency.TRANSLUCENT otherwise. The transfer type
122: * is the type of primitive array used to represent pixel values and
123: * must be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or
124: * DataBuffer.TYPE_INT.
125: * @param space the specified <code>ColorSpace</code>
126: * @param bits the number of bits in the pixel values; for example,
127: * the sum of the number of bits in the masks.
128: * @param rmask specifies a mask indicating which bits in an
129: * integer pixel contain the red component
130: * @param gmask specifies a mask indicating which bits in an
131: * integer pixel contain the green component
132: * @param bmask specifies a mask indicating which bits in an
133: * integer pixel contain the blue component
134: * @param amask specifies a mask indicating which bits in an
135: * integer pixel contain the alpha component
136: * @param isAlphaPremultiplied <code>true</code> if color samples are
137: * premultiplied by the alpha sample; <code>false</code> otherwise
138: * @param transferType the type of array used to represent pixel values
139: */
140: public DirectColorModel(ColorSpace space, int bits, int rmask,
141: int gmask, int bmask, int amask,
142: boolean isAlphaPremultiplied, int transferType) {
143: super (bits, createBitsArray(rmask, gmask, bmask, amask), space,
144: amask == 0 ? false : true, isAlphaPremultiplied,
145: amask == 0 ? Transparency.OPAQUE
146: : Transparency.TRANSLUCENT, transferType);
147: red_mask = rmask;
148: green_mask = gmask;
149: blue_mask = bmask;
150: alpha_mask = amask;
151: calculateOffsets();
152: }
153:
154: private final static int[] createBitsArray(int rmask, int gmask,
155: int bmask, int amask) {
156: int[] arr = new int[3 + (amask == 0 ? 0 : 1)];
157: arr[0] = countBits(rmask);
158: arr[1] = countBits(gmask);
159: arr[2] = countBits(bmask);
160: if (arr[0] < 0) {
161: throw new IllegalArgumentException(
162: "Noncontiguous red mask ("
163: + Integer.toHexString(rmask));
164: } else if (arr[1] < 0) {
165: throw new IllegalArgumentException(
166: "Noncontiguous green mask ("
167: + Integer.toHexString(gmask));
168: } else if (arr[2] < 0) {
169: throw new IllegalArgumentException(
170: "Noncontiguous blue mask ("
171: + Integer.toHexString(bmask));
172: }
173: if (amask != 0) {
174: arr[3] = countBits(amask);
175: if (arr[3] < 0) {
176: throw new IllegalArgumentException(
177: "Noncontiguous alpha mask ("
178: + Integer.toHexString(amask));
179: }
180: }
181: return arr;
182: }
183:
184: private final static int countBits(int mask) {
185: int saveMask = mask;
186: int count = 0;
187: if (mask != 0) {
188: while ((mask & 1) == 0) {
189: mask >>>= 1;
190: }
191: while ((mask & 1) == 1) {
192: mask >>>= 1;
193: count++;
194: }
195: }
196: if (mask != 0) {
197: return -1;
198: }
199: return count;
200: }
201:
202: /**
203: * Returns the mask indicating which bits in a pixel contain the red
204: * color component.
205: */
206: final public int getRedMask() {
207: return red_mask;
208: }
209:
210: /**
211: * Returns the mask indicating which bits in a pixel contain the green
212: * color component.
213: */
214: final public int getGreenMask() {
215: return green_mask;
216: }
217:
218: /**
219: * Returns the mask indicating which bits in a pixel contain the blue
220: * color component.
221: */
222: final public int getBlueMask() {
223: return blue_mask;
224: }
225:
226: /**
227: * Returns the mask indicating which bits in a pixel contain the alpha
228: * transparency component.
229: */
230: final public int getAlphaMask() {
231: return alpha_mask;
232: }
233:
234: private int accum_mask = 0;
235:
236: /*
237: * A utility function to decompose a single mask and verify that it
238: * fits in the specified pixel size, and that it does not overlap any
239: * other color component. The values necessary to decompose and
240: * manipulate pixels are calculated as a side effect.
241: */
242: private void decomposeMask(int mask, String componentName,
243: int values[]) {
244: if ((mask & accum_mask) != 0) {
245: throw new IllegalArgumentException(componentName
246: + " mask bits not unique");
247: }
248: int off = 0;
249: int count = 0;
250: if (mask != 0) {
251: while ((mask & 1) == 0) {
252: mask >>>= 1;
253: off++;
254: }
255: while ((mask & 1) == 1) {
256: mask >>>= 1;
257: count++;
258: }
259: }
260: if (mask != 0) {
261: throw new IllegalArgumentException(componentName
262: + " mask bits not contiguous");
263: }
264: if (off + count > pixel_bits) {
265: throw new IllegalArgumentException(componentName
266: + " mask overflows pixel");
267: }
268: int scale;
269: if (count < 8) {
270: scale = (1 << count) - 1;
271: } else {
272: scale = 0;
273: if (count > 8) {
274: off += (count - 8);
275: }
276: }
277: values[0] = off;
278: values[1] = scale;
279: }
280:
281: /*
282: * A utility function to verify all of the masks and to store
283: * the auxilliary values needed to manipulate the pixels.
284: */
285: private void calculateOffsets() {
286: int values[] = new int[2];
287: decomposeMask(red_mask, "red", values);
288: red_offset = values[0];
289: red_scale = values[1];
290: decomposeMask(green_mask, "green", values);
291: green_offset = values[0];
292: green_scale = values[1];
293: decomposeMask(blue_mask, "blue", values);
294: blue_offset = values[0];
295: blue_scale = values[1];
296: decomposeMask(alpha_mask, "alpha", values);
297: alpha_offset = values[0];
298: alpha_scale = values[1];
299: }
300:
301: /**
302: * Returns the red color compoment for the specified pixel in the
303: * range 0-255.
304: */
305: final public int getRed(int pixel) {
306: int r = ((pixel & red_mask) >>> red_offset);
307: if (red_scale != 0) {
308: r = r * 255 / red_scale;
309: }
310: if (isAlphaPremultiplied) {
311: int alpha = getAlpha(pixel);
312: if (alpha == 0)
313: return 0;
314: r *= 255;
315: r /= alpha;
316: r = Math.min(255, r);
317: }
318: return r;
319: }
320:
321: /**
322: * Returns the green color compoment for the specified pixel in the
323: * range 0-255.
324: */
325: final public int getGreen(int pixel) {
326: int g = ((pixel & green_mask) >>> green_offset);
327: if (green_scale != 0) {
328: g = g * 255 / green_scale;
329: }
330: if (isAlphaPremultiplied) {
331: int alpha = getAlpha(pixel);
332: if (alpha == 0)
333: return 0;
334: g *= 255;
335: g /= alpha;
336: g = Math.min(255, g);
337: }
338: return g;
339: }
340:
341: /**
342: * Returns the blue color compoment for the specified pixel in the
343: * range 0-255.
344: */
345: final public int getBlue(int pixel) {
346: int b = ((pixel & blue_mask) >>> blue_offset);
347: if (blue_scale != 0) {
348: b = b * 255 / blue_scale;
349: }
350: if (isAlphaPremultiplied) {
351: int alpha = getAlpha(pixel);
352: if (alpha == 0)
353: return 0;
354: b *= 255;
355: b /= alpha;
356: b = Math.min(255, b);
357: }
358: return b;
359: }
360:
361: /**
362: * Return the alpha transparency value for the specified pixel in the
363: * range 0-255.
364: */
365: final public int getAlpha(int pixel) {
366: if (alpha_mask == 0)
367: return 255;
368: int a = ((pixel & alpha_mask) >>> alpha_offset);
369: if (alpha_scale != 0) {
370: a = a * 255 / alpha_scale;
371: }
372: return a;
373: }
374:
375: /**
376: * Returns the color of the pixel in the default RGB color model.
377: * @see ColorModel#getRGBdefault
378: */
379: final public int getRGB(int pixel) {
380: return (getAlpha(pixel) << 24) | (getRed(pixel) << 16)
381: | (getGreen(pixel) << 8) | (getBlue(pixel) << 0);
382: }
383: }
|