1 /* Copyright (C) 2000 Free Software Foundation
3 This file is part of libgcj.
5 This software is copyrighted work licensed under the terms of the
6 Libgcj License. Please consult the file "LIBGCJ_LICENSE" for
9 package java.awt.image;
11 import java.awt.Point;
12 import java.awt.Transparency;
13 import java.awt.color.ColorSpace;
14 import gnu.gcj.awt.Buffers;
17 * A color model operates with colors in several formats:
20 * <li>normalized: component samples are in range [0.0, 1.0].</li>
22 * <li>color model pixel value: all the color component samples for a
23 * sigle pixel packed/encoded in a way natural for the color
26 * <li>color model pixel int value: only makes sense if the natural
27 * encoding of a single pixel can fit in a single int value.</li>
29 * <li>array of transferType containing a single pixel: the pixel is
30 * encoded in the natural way of the color model, taking up as many
31 * array elements as needed.</li>
33 * <li>sRGB pixel int value: a pixel in sRGB color space, encoded in
34 * default 0xAARRGGBB format, assumed not alpha premultiplied.</li>
36 * <li>single [0, 255] scaled int samples from default sRGB color
37 * space. These are always assumed to be alpha non-premultiplied.</li>
39 * <li>arrays of unnormalized component samples of single pixel: these
40 * samples are scaled and multiplied according to the color model, but
41 * is otherwise not packed or encoded. Each element of the array is one
42 * separate component sample. The color model only operate on the
43 * components from one pixel at a time, but using offsets, allows
44 * manipulation of arrays that contain the components of more than one
49 * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
52 public abstract class ColorModel implements Transparency
54 protected int pixel_bits;
55 protected int transferType;
61 boolean isAlphaPremultiplied;
63 static int[] nArray(int value, int times)
65 int[] array = new int[times];
66 java.util.Arrays.fill(array, value);
70 static byte[] nArray(byte value, int times)
72 byte[] array = new byte[times];
73 java.util.Arrays.fill(array, value);
77 public ColorModel(int bits)
79 this(bits * 4, // total bits, sRGB, four channels
80 nArray(bits, 4), // bits for each channel
81 null, // FIXME: should be sRGB
83 false, // not premultiplied
85 Buffers.smallestAppropriateTransferType(bits * 4));
88 protected ColorModel(int pixel_bits, int[] bits, ColorSpace cspace,
89 boolean hasAlpha, boolean isAlphaPremultiplied,
90 int transparency, int transferType)
92 this.pixel_bits = pixel_bits;
95 this.hasAlpha = hasAlpha;
96 this.isAlphaPremultiplied = isAlphaPremultiplied;
97 this.transparency = transparency;
98 this.transferType = transferType;
101 public static ColorModel getRGBdefault()
103 return new DirectColorModel(8, 0xff0000, 0xff00, 0xff, 0xff000000);
106 public final boolean hasAlpha()
111 public final boolean isAlphaPremultiplied()
113 return isAlphaPremultiplied;
116 public int getPixelSize()
121 public int getComponentSize(int componentIdx)
123 return bits[componentIdx];
126 public int[] getComponentSize()
131 public int getTransparency()
136 public int getNumComponents()
138 return getNumColorComponents() + (hasAlpha ? 1 : 0);
141 public int getNumColorComponents()
143 return cspace.getNumComponents();
147 * Converts pixel value to sRGB and extract red int sample scaled
150 * @param pixel pixel value that will be interpreted according to
151 * the color model, (assumed alpha premultiplied if color model says
154 * @return red sample scaled to range [0, 255], from default color
155 * space sRGB, alpha non-premultiplied.
157 public abstract int getRed(int pixel);
160 * Converts pixel value to sRGB and extract green int sample
161 * scaled to range [0, 255].
165 public abstract int getGreen(int pixel);
168 * Converts pixel value to sRGB and extract blue int sample
169 * scaled to range [0, 255].
173 public abstract int getBlue(int pixel);
176 * Extract alpha int sample from pixel value, scaled to [0, 255].
178 * @param pixel pixel value that will be interpreted according to
181 * @return alpha sample, scaled to range [0, 255].
183 public abstract int getAlpha(int pixel);
186 * Converts a pixel int value of the color space of the color
187 * model to a sRGB pixel int value.
189 * This method is typically overriden in subclasses to provide a
190 * more efficient implementation.
192 * @param pixel pixel value that will be interpreted according to
195 * @return a pixel in sRGB color space, encoded in default
196 * 0xAARRGGBB format. */
197 public int getRGB(int pixel)
200 ((getAlpha(pixel) & 0xff) << 24) |
201 (( getRed(pixel) & 0xff) << 16) |
202 ((getGreen(pixel) & 0xff) << 8) |
203 (( getBlue(pixel) & 0xff) << 0);
208 * In this color model we know that the whole pixel value will
209 * always be contained within the first element of the pixel
212 final int getPixelFromArray(Object inData) {
214 Buffers.createBufferFromData(transferType, inData, 1);
215 Object da = Buffers.getData(data);
217 return data.getElem(0);
221 * Converts pixel in the given array to sRGB and extract blue int
222 * sample scaled to range [0-255].
224 * This method is typically overriden in subclasses to provide a
225 * more efficient implementation.
227 * @param array of transferType containing a single pixel. The
228 * pixel should be encoded in the natural way of the color model.
230 public int getRed(Object inData)
232 return getRed(getPixelFromArray(inData));
236 * @see #getRed(Object)
238 public int getGreen(Object inData)
240 return getGreen(getPixelFromArray(inData));
244 * @see #getRed(Object)
246 public int getBlue(Object inData) {
247 return getBlue(getPixelFromArray(inData));
251 * @see #getRed(Object)
253 public int getAlpha(Object inData) {
254 return getBlue(getPixelFromArray(inData));
258 * Converts a pixel in the given array of the color space of the
259 * color model to an sRGB pixel int value.
261 * <p>This method performs the inverse function of
262 * <code>getDataElements(int rgb, Object pixel)</code>.
263 * I.e. <code>(rgb == cm.getRGB(cm.getDataElements(rgb,
266 * @param inData array of transferType containing a single pixel. The
267 * pixel should be encoded in the natural way of the color model.
269 * @return a pixel in sRGB color space, encoded in default
272 * @see #getDataElements(int, Object)
274 public int getRGB(Object inData)
277 ((getAlpha(inData) & 0xff) << 24) |
278 (( getRed(inData) & 0xff) << 16) |
279 ((getGreen(inData) & 0xff) << 8) |
280 (( getBlue(inData) & 0xff) << 0);
284 * Converts an sRGB pixel int value to an array containing a
285 * single pixel of the color space of the color model.
287 * <p>This method performs the inverse function of
288 * <code>getRGB(Object inData)</code>.
290 * Outline of conversion process:
294 * <li>Convert rgb to normalized [0.0, 1.0] sRGB values.</li>
296 * <li>Convert to color space components using fromRGB in
299 * <li>If color model has alpha and should be premultiplied,
300 * multiply color space components with alpha value</li>
302 * <li>Scale the components to the correct number of bits.</li>
304 * <li>Arrange the components in the output array</li>
308 * @param rgb The color to be converted to dataElements. A pixel
309 * in sRGB color space, encoded in default 0xAARRGGBB format,
310 * assumed not alpha premultiplied.
312 * @param pixel to avoid needless creation of arrays, an array to
313 * use to return the pixel can be given. If null, a suitable array
316 * @return An array of transferType values representing the color,
317 * in the color model format. The color model defines whether the
319 * @see #getRGB(Object)
321 public Object getDataElements(int rgb, Object pixel)
324 throw new UnsupportedOperationException();
328 * Fills an array with the unnormalized component samples from a
329 * pixel value. I.e. decompose the pixel, but not perform any
332 * This method is typically overriden in subclasses to provide a
333 * more efficient implementation.
335 * @param pixel pixel value encoded according to the color model.
337 * @return arrays of unnormalized component samples of single
338 * pixel. The scale and multiplication state of the samples are
339 * according to the color model. Each component sample is stored
340 * as a separate element in the array.
342 public int[] getComponents(int pixel, int[] components, int offset) {
344 throw new UnsupportedOperationException();
348 * Fills an array with the unnormalized component samples from an
349 * array of transferType containing a single pixel. I.e. decompose
350 * the pixel, but not perform any color conversion.
352 * This method is typically overriden in subclasses to provide a
353 * more efficient implementation.
355 * @param array of transferType containing a single pixel. The
356 * pixel should be encoded in the natural way of the color model.
358 * @return arrays of unnormalized component samples of single
359 * pixel. The scale and multiplication state of the samples are
360 * according to the color model. Each component sample is stored
361 * as a separate element in the array.
363 public int[] getComponents(Object pixel, int[] components, int offset)
365 throw new UnsupportedOperationException();
369 * Convert normalized components to unnormalized components.
371 public int[] getUnnormalizedComponents(float[] normComponents,
376 int numComponents = getNumComponents();
377 if (components == null)
379 components = new int[offset + numComponents];
382 for (int i=0; i<numComponents; i++)
384 float in = normComponents[normOffset++];
385 int out = (int) (in * ((2<<getComponentSize(i)) - 1));
386 components[offset++] = out;
392 * Convert unnormalized components to normalized components.
394 public float[] getNormalizedComponents(int[] components,
396 float[] normComponents,
399 int numComponents = getNumComponents();
400 if (normComponents == null)
402 normComponents = new float[normOffset + numComponents];
405 for (int i=0; i<numComponents; i++)
407 float in = components[offset++];
408 float out = in / ((2<<getComponentSize(i)) - 1);
409 normComponents[normOffset++] = out;
411 return normComponents;
415 * Converts the unnormalized component samples from an array to a
416 * pixel value. I.e. composes the pixel from component samples, but
417 * does not perform any color conversion or scaling of the samples.
419 * This method performs the inverse function of
420 * <code>getComponents(int pixel, int[] components,
421 * int offset)</code>. I.e.
423 * <code>(pixel == cm.getDataElement(cm.getComponents(pixel, null,
426 * This method is typically overriden in subclasses to provide a
427 * more efficient implementation.
429 * @param arrays of unnormalized component samples of single
430 * pixel. The scale and multiplication state of the samples are
431 * according to the color model. Each component sample is stored
432 * as a separate element in the array.
434 * @return pixel value encoded according to the color model.
436 public int getDataElement(int[] components, int offset)
438 throw new UnsupportedOperationException();
441 public Object getDataElements(int[] components, int offset, Object obj)
443 throw new UnsupportedOperationException();
446 public boolean equals(Object obj)
448 if (!(obj instanceof ColorModel)) return false;
450 ColorModel o = (ColorModel) obj;
452 (pixel_bits == o.pixel_bits) &&
453 (transferType == o.transferType) &&
454 (transparency == o.transparency) &&
455 (hasAlpha == o.hasAlpha) &&
456 (isAlphaPremultiplied == isAlphaPremultiplied) &&
457 (bits.equals(o.bits)) &&
458 (cspace.equals(o.cspace));
461 public final ColorSpace getColorSpace()
466 // Typically overridden
467 public ColorModel coerceData(WritableRaster raster,
468 boolean isAlphaPremultiplied)
470 if (this.isAlphaPremultiplied == isAlphaPremultiplied)
473 int w = raster.getWidth();
474 int h = raster.getHeight();
475 int x = raster.getMinX();
476 int y = raster.getMinY();
478 int numColors = getNumColorComponents();
479 int numComponents = getNumComponents();
480 int alphaScale = (1<<getComponentSize(numColors)) - 1;
481 double[] pixels = raster.getPixels(x, y, w, h, (double[]) null);
483 for (int i=0; i<size; i++)
485 double alpha = pixels[i*numComponents+numColors]*alphaScale;
486 for (int c=0; c<numColors; c++)
488 int offset = i*numComponents+c;
489 if (isAlphaPremultiplied)
490 pixels[offset] = pixels[offset]/alpha;
492 pixels[offset] = pixels[offset]*alpha;
496 raster.setPixels(0, 0, w, h, pixels);
498 // FIXME: what can we return?
502 // Typically overridden
503 public boolean isCompatibleRaster(Raster raster)
505 SampleModel sampleModel = raster.getSampleModel();
506 return isCompatibleSampleModel(sampleModel);
509 // Typically overridden
510 public WritableRaster createCompatibleWritableRaster(int w, int h)
512 return new WritableRaster(createCompatibleSampleModel(w, h),
516 // Typically overridden
517 public SampleModel createCompatibleSampleModel(int w, int h)
519 throw new UnsupportedOperationException();
522 // Typically overridden
523 public boolean isCompatibleSampleModel(SampleModel sm)
525 return sm.getTransferType() == transferType;
528 public void finalize() {
532 * Subclasses must override this method if it is possible for the
533 * color model to have an alpha channel.
535 * @return null, as per JDK 1.3 doc. Subclasses will only return
536 * null if no alpha raster exists.
538 public WritableRaster getAlphaRaster(WritableRaster raster)
542 /* It is a mystery to me why we couldn't use the following code...
545 if (!hasAlpha()) return null;
547 SampleModel sm = raster.getSampleModel();
548 int[] alphaBand = { sm.getNumBands() - 1 };
549 SampleModel alphaModel = sm.createSubsetSampleModel(alphaBand);
550 DataBuffer buffer = raster.getDataBuffer();
551 Point origin = new Point(0, 0);
552 return Raster.createWritableRaster(alphaModel, buffer, origin);
555 ...here, and avoided overriding the method in subclasses,
556 but the Sun docs state that this method always will return
557 null, and that overriding is required. Oh, well.
563 return "pixel_bits=" + pixel_bits +
564 ", cspace=" + cspace +
565 ", transferType=" + transferType +
566 ", transparency=" + transparency +
567 ", hasAlpha=" + hasAlpha +
568 ", isAlphaPremultiplied=" + isAlphaPremultiplied;
571 public String toString()
573 return getClass().getName() + "[" + stringParam() + "]";