/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
/**
* @author Igor V. Stolyarov
* @version $Revision$
*/
package java.awt.image;
import java.awt.Transparency;
import java.awt.color.ColorSpace;
import java.util.Arrays;
import org.apache.harmony.awt.internal.nls.Messages;
/**
* The class PackedColorModel represents a color model where the components are
* just the red, green, and blue bands, plus an alpha band if alpha is
* supported.
*
* @since Android 1.0
*/
public abstract class PackedColorModel extends ColorModel {
/**
* The component masks.
*/
int componentMasks[];
/**
* The offsets.
*/
int offsets[];
/**
* The scales.
*/
float scales[];
/**
* Instantiates a new packed color model.
*
* @param space
* the color space.
* @param bits
* the array of component masks.
* @param colorMaskArray
* the array that gives the bitmask corresponding to each color
* band (red, green, and blue).
* @param alphaMask
* the bitmask corresponding to the alpha band.
* @param isAlphaPremultiplied
* whether the alpha is pre-multiplied in this color model.
* @param trans
* the transparency strategy, @see java.awt.Transparency.
* @param transferType
* the transfer type (primitive java type to use for the
* components).
* @throws IllegalArgumentException
* if the number of bits in the combined bitmasks for the color
* bands is less than one or greater than 32.
*/
public PackedColorModel(ColorSpace space, int bits, int colorMaskArray[], int alphaMask,
boolean isAlphaPremultiplied, int trans, int transferType) {
super(bits, createBits(colorMaskArray, alphaMask), space, (alphaMask == 0 ? false : true),
isAlphaPremultiplied, trans, validateTransferType(transferType));
if (pixel_bits < 1 || pixel_bits > 32) {
// awt.236=The bits is less than 1 or greater than 32
throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$
}
componentMasks = new int[numComponents];
for (int i = 0; i < numColorComponents; i++) {
componentMasks[i] = colorMaskArray[i];
}
if (hasAlpha) {
componentMasks[numColorComponents] = alphaMask;
if (this.bits[numColorComponents] == 1) {
transparency = Transparency.BITMASK;
}
}
parseComponents();
}
/**
* Instantiates a new packed color model.
*
* @param space
* the color space.
* @param bits
* the array of component masks.
* @param rmask
* the bitmask corresponding to the red band.
* @param gmask
* the bitmask corresponding to the green band.
* @param bmask
* the bitmask corresponding to the blue band.
* @param amask
* the bitmask corresponding to the alpha band.
* @param isAlphaPremultiplied
* whether the alpha is pre-multiplied in this color model.
* @param trans
* the transparency strategy, @see java.awt.Transparency.
* @param transferType
* the transfer type (primitive java type to use for the
* components).
* @throws IllegalArgumentException
* if the number of bits in the combined bitmasks for the color
* bands is less than one or greater than 32.
*/
public PackedColorModel(ColorSpace space, int bits, int rmask, int gmask, int bmask, int amask,
boolean isAlphaPremultiplied, int trans, int transferType) {
super(bits, createBits(rmask, gmask, bmask, amask), space, (amask == 0 ? false : true),
isAlphaPremultiplied, trans, validateTransferType(transferType));
if (pixel_bits < 1 || pixel_bits > 32) {
// awt.236=The bits is less than 1 or greater than 32
throw new IllegalArgumentException(Messages.getString("awt.236")); //$NON-NLS-1$
}
if (cs.getType() != ColorSpace.TYPE_RGB) {
// awt.239=The space is not a TYPE_RGB space
throw new IllegalArgumentException(Messages.getString("awt.239")); //$NON-NLS-1$
}
for (int i = 0; i < numColorComponents; i++) {
if (cs.getMinValue(i) != 0.0f || cs.getMaxValue(i) != 1.0f) {
// awt.23A=The min/max normalized component values are not
// 0.0/1.0
throw new IllegalArgumentException(Messages.getString("awt.23A")); //$NON-NLS-1$
}
}
componentMasks = new int[numComponents];
componentMasks[0] = rmask;
componentMasks[1] = gmask;
componentMasks[2] = bmask;
if (hasAlpha) {
componentMasks[3] = amask;
if (this.bits[3] == 1) {
transparency = Transparency.BITMASK;
}
}
parseComponents();
}
@Override
public WritableRaster getAlphaRaster(WritableRaster raster) {
if (!hasAlpha) {
return null;
}
int x = raster.getMinX();
int y = raster.getMinY();
int w = raster.getWidth();
int h = raster.getHeight();
int band[] = new int[1];
band[0] = raster.getNumBands() - 1;
return raster.createWritableChild(x, y, w, h, x, y, band);
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (!(obj instanceof PackedColorModel)) {
return false;
}
PackedColorModel cm = (PackedColorModel)obj;
return (pixel_bits == cm.getPixelSize() && transferType == cm.getTransferType()
&& cs.getType() == cm.getColorSpace().getType() && hasAlpha == cm.hasAlpha()
&& isAlphaPremultiplied == cm.isAlphaPremultiplied()
&& transparency == cm.getTransparency()
&& numColorComponents == cm.getNumColorComponents()
&& numComponents == cm.getNumComponents()
&& Arrays.equals(bits, cm.getComponentSize()) && Arrays.equals(componentMasks, cm
.getMasks()));
}
@Override
public boolean isCompatibleSampleModel(SampleModel sm) {
if (sm == null) {
return false;
}
if (!(sm instanceof SinglePixelPackedSampleModel)) {
return false;
}
SinglePixelPackedSampleModel esm = (SinglePixelPackedSampleModel)sm;
return ((esm.getNumBands() == numComponents) && (esm.getTransferType() == transferType) && Arrays
.equals(esm.getBitMasks(), componentMasks));
}
@Override
public SampleModel createCompatibleSampleModel(int w, int h) {
return new SinglePixelPackedSampleModel(transferType, w, h, componentMasks);
}
/**
* Gets the bitmask corresponding to the specified color component.
*
* @param index
* the index of the desired color.
* @return the mask.
*/
public final int getMask(int index) {
return componentMasks[index];
}
/**
* Gets the bitmasks of the components.
*
* @return the masks.
*/
public final int[] getMasks() {
return (componentMasks.clone());
}
/**
* Creates the bits.
*
* @param colorMaskArray
* the color mask array.
* @param alphaMask
* the alpha mask.
* @return the int[].
*/
private static int[] createBits(int colorMaskArray[], int alphaMask) {
int bits[];
int numComp;
if (alphaMask == 0) {
numComp = colorMaskArray.length;
} else {
numComp = colorMaskArray.length + 1;
}
bits = new int[numComp];
int i = 0;
for (; i < colorMaskArray.length; i++) {
bits[i] = countCompBits(colorMaskArray[i]);
if (bits[i] < 0) {
// awt.23B=The mask of the {0} component is not contiguous
throw new IllegalArgumentException(Messages.getString("awt.23B", i)); //$NON-NLS-1$
}
}
if (i < numComp) {
bits[i] = countCompBits(alphaMask);
if (bits[i] < 0) {
// awt.23C=The mask of the alpha component is not contiguous
throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$
}
}
return bits;
}
/**
* Creates the bits.
*
* @param rmask
* the rmask.
* @param gmask
* the gmask.
* @param bmask
* the bmask.
* @param amask
* the amask.
* @return the int[].
*/
private static int[] createBits(int rmask, int gmask, int bmask, int amask) {
int numComp;
if (amask == 0) {
numComp = 3;
} else {
numComp = 4;
}
int bits[] = new int[numComp];
bits[0] = countCompBits(rmask);
if (bits[0] < 0) {
// awt.23D=The mask of the red component is not contiguous
throw new IllegalArgumentException(Messages.getString("awt.23D")); //$NON-NLS-1$
}
bits[1] = countCompBits(gmask);
if (bits[1] < 0) {
// awt.23E=The mask of the green component is not contiguous
throw new IllegalArgumentException(Messages.getString("awt.23E")); //$NON-NLS-1$
}
bits[2] = countCompBits(bmask);
if (bits[2] < 0) {
// awt.23F=The mask of the blue component is not contiguous
throw new IllegalArgumentException(Messages.getString("awt.23F")); //$NON-NLS-1$
}
if (amask != 0) {
bits[3] = countCompBits(amask);
if (bits[3] < 0) {
// awt.23C=The mask of the alpha component is not contiguous
throw new IllegalArgumentException(Messages.getString("awt.23C")); //$NON-NLS-1$
}
}
return bits;
}
/**
* Count comp bits.
*
* @param compMask
* the comp mask.
* @return the int.
*/
private static int countCompBits(int compMask) {
int bits = 0;
if (compMask != 0) {
// Deleting final zeros
while ((compMask & 1) == 0) {
compMask >>>= 1;
}
// Counting component bits
while ((compMask & 1) == 1) {
compMask >>>= 1;
bits++;
}
}
if (compMask != 0) {
return -1;
}
return bits;
}
/**
* Validate transfer type.
*
* @param transferType
* the transfer type.
* @return the int.
*/
private static int validateTransferType(int transferType) {
if (transferType != DataBuffer.TYPE_BYTE && transferType != DataBuffer.TYPE_USHORT
&& transferType != DataBuffer.TYPE_INT) {
// awt.240=The transferType not is one of DataBuffer.TYPE_BYTE,
// DataBuffer.TYPE_USHORT or DataBuffer.TYPE_INT
throw new IllegalArgumentException(Messages.getString("awt.240")); //$NON-NLS-1$
}
return transferType;
}
/**
* Parses the components.
*/
private void parseComponents() {
offsets = new int[numComponents];
scales = new float[numComponents];
for (int i = 0; i < numComponents; i++) {
int off = 0;
int mask = componentMasks[i];
while ((mask & 1) == 0) {
mask >>>= 1;
off++;
}
offsets[i] = off;
if (bits[i] == 0) {
scales[i] = 256.0f; // May be any value different from zero,
// because will dividing by zero
} else {
scales[i] = 255.0f / maxValues[i];
}
}
}
}