blob: 3dc13d8f4df3da4a13174ab4a8d38f5468804426 [file] [log] [blame]
/*
* 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 org.apache.harmony.awt.internal.nls.Messages;
/**
* The MultiPixelPackedSampleModel class represents image data with one band.
* This class packs multiple pixels with one sample in one data element and
* supports the following data types: DataBuffer.TYPE_BYTE,
* DataBuffer.TYPE_USHORT, or DataBuffer.TYPE_INT.
*
* @since Android 1.0
*/
public class MultiPixelPackedSampleModel extends SampleModel {
/**
* The pixel bit stride.
*/
private int pixelBitStride;
/**
* The scanline stride.
*/
private int scanlineStride;
/**
* The data bit offset.
*/
private int dataBitOffset;
/**
* The bit mask.
*/
private int bitMask;
/**
* The data element size.
*/
private int dataElementSize;
/**
* The pixels per data element.
*/
private int pixelsPerDataElement;
/**
* Instantiates a new MultiPixelPackedSampleModel with the specified
* parameters.
*
* @param dataType
* the data type of the samples.
* @param w
* the width of the image data.
* @param h
* the height of the image data.
* @param numberOfBits
* the number of bits per pixel.
* @param scanlineStride
* the scanline stride of the of the image data.
* @param dataBitOffset
* the array of the band offsets.
*/
public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits,
int scanlineStride, int dataBitOffset) {
super(dataType, w, h, 1);
if (dataType != DataBuffer.TYPE_BYTE && dataType != DataBuffer.TYPE_USHORT
&& dataType != DataBuffer.TYPE_INT) {
// awt.61=Unsupported data type: {0}
throw new IllegalArgumentException(Messages.getString("awt.61", //$NON-NLS-1$
dataType));
}
this.scanlineStride = scanlineStride;
if (numberOfBits == 0) {
// awt.20C=Number of Bits equals to zero
throw new RasterFormatException(Messages.getString("awt.20C")); //$NON-NLS-1$
}
this.pixelBitStride = numberOfBits;
this.dataElementSize = DataBuffer.getDataTypeSize(dataType);
if (dataElementSize % pixelBitStride != 0) {
// awt.20D=The number of bits per pixel is not a power of 2 or
// pixels span data element boundaries
throw new RasterFormatException(Messages.getString("awt.20D")); //$NON-NLS-1$
}
if (dataBitOffset % numberOfBits != 0) {
// awt.20E=Data Bit offset is not a multiple of pixel bit stride
throw new RasterFormatException(Messages.getString("awt.20E")); //$NON-NLS-1$
}
this.dataBitOffset = dataBitOffset;
this.pixelsPerDataElement = dataElementSize / pixelBitStride;
this.bitMask = (1 << numberOfBits) - 1;
}
/**
* Instantiates a new MultiPixelPackedSampleModel with the specified
* parameters.
*
* @param dataType
* the data type of the samples.
* @param w
* the width of the image data.
* @param h
* the height of the image data.
* @param numberOfBits
* the number of bits per pixel.
*/
public MultiPixelPackedSampleModel(int dataType, int w, int h, int numberOfBits) {
this(dataType, w, h, numberOfBits,
(numberOfBits * w + DataBuffer.getDataTypeSize(dataType) - 1)
/ DataBuffer.getDataTypeSize(dataType), 0);
}
@Override
public Object getDataElements(int x, int y, Object obj, DataBuffer data) {
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
// awt.63=Coordinates are not in bounds
throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
}
switch (getTransferType()) {
case DataBuffer.TYPE_BYTE:
byte bdata[];
if (obj == null) {
bdata = new byte[1];
} else {
bdata = (byte[])obj;
}
bdata[0] = (byte)getSample(x, y, 0, data);
obj = bdata;
break;
case DataBuffer.TYPE_USHORT:
short sdata[];
if (obj == null) {
sdata = new short[1];
} else {
sdata = (short[])obj;
}
sdata[0] = (short)getSample(x, y, 0, data);
obj = sdata;
break;
case DataBuffer.TYPE_INT:
int idata[];
if (obj == null) {
idata = new int[1];
} else {
idata = (int[])obj;
}
idata[0] = getSample(x, y, 0, data);
obj = idata;
break;
}
return obj;
}
@Override
public void setDataElements(int x, int y, Object obj, DataBuffer data) {
setSample(x, y, obj, data, 1, 0);
}
/**
* Compares this MultiPixelPackedSampleModel object with the specified
* object.
*
* @param o
* the Object to be compared.
* @return true, if the object is a MultiPixelPackedSampleModel with the
* same data parameter values as this MultiPixelPackedSampleModel,
* false otherwise.
*/
@Override
public boolean equals(Object o) {
if ((o == null) || !(o instanceof MultiPixelPackedSampleModel)) {
return false;
}
MultiPixelPackedSampleModel model = (MultiPixelPackedSampleModel)o;
return this.width == model.width && this.height == model.height
&& this.numBands == model.numBands && this.dataType == model.dataType
&& this.pixelBitStride == model.pixelBitStride && this.bitMask == model.bitMask
&& this.pixelsPerDataElement == model.pixelsPerDataElement
&& this.dataElementSize == model.dataElementSize
&& this.dataBitOffset == model.dataBitOffset
&& this.scanlineStride == model.scanlineStride;
}
@Override
public SampleModel createSubsetSampleModel(int bands[]) {
if (bands != null && bands.length != 1) {
// awt.20F=Number of bands must be only 1
throw new RasterFormatException(Messages.getString("awt.20F")); //$NON-NLS-1$
}
return createCompatibleSampleModel(width, height);
}
@Override
public SampleModel createCompatibleSampleModel(int w, int h) {
return new MultiPixelPackedSampleModel(dataType, w, h, pixelBitStride);
}
@Override
public int[] getPixel(int x, int y, int iArray[], DataBuffer data) {
if (x < 0 || y < 0 || x >= this.width || y >= this.height) {
// awt.63=Coordinates are not in bounds
throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
}
int pixel[];
if (iArray == null) {
pixel = new int[numBands];
} else {
pixel = iArray;
}
pixel[0] = getSample(x, y, 0, data);
return pixel;
}
@Override
public void setPixel(int x, int y, int iArray[], DataBuffer data) {
setSample(x, y, iArray, data, 2, 0);
}
@Override
public int getSample(int x, int y, int b, DataBuffer data) {
if (x < 0 || y < 0 || x >= this.width || y >= this.height || b != 0) {
// awt.63=Coordinates are not in bounds
throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
}
int bitnum = dataBitOffset + x * pixelBitStride;
int elem = data.getElem(y * scanlineStride + bitnum / dataElementSize);
int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride;
return (elem >> shift) & bitMask;
}
@Override
public void setSample(int x, int y, int b, int s, DataBuffer data) {
if (b != 0) {
// awt.63=Coordinates are not in bounds
throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
}
setSample(x, y, null, data, 3, s);
}
@Override
public DataBuffer createDataBuffer() {
DataBuffer dataBuffer = null;
int size = scanlineStride * height;
switch (dataType) {
case DataBuffer.TYPE_BYTE:
dataBuffer = new DataBufferByte(size + (dataBitOffset + 7) / 8);
break;
case DataBuffer.TYPE_USHORT:
dataBuffer = new DataBufferUShort(size + (dataBitOffset + 15) / 16);
break;
case DataBuffer.TYPE_INT:
dataBuffer = new DataBufferInt(size + (dataBitOffset + 31) / 32);
break;
}
return dataBuffer;
}
/**
* Gets the offset of the specified pixel in the data array.
*
* @param x
* the X coordinate of the specified pixel.
* @param y
* the Y coordinate of the specified pixel.
* @return the offset of the specified pixel.
*/
public int getOffset(int x, int y) {
return y * scanlineStride + (x * pixelBitStride + dataBitOffset) / dataElementSize;
}
@Override
public int getSampleSize(int band) {
return pixelBitStride;
}
/**
* Gets the bit offset in the data element which is stored for the specified
* pixel of a scanline.
*
* @param x
* the pixel.
* @return the bit offset of the pixel in the data element.
*/
public int getBitOffset(int x) {
return (x * pixelBitStride + dataBitOffset) % dataElementSize;
}
@Override
public int[] getSampleSize() {
int sampleSizes[] = {
pixelBitStride
};
return sampleSizes;
}
/**
* Returns a hash code of this MultiPixelPackedSampleModel class.
*
* @return the hash code of this MultiPixelPackedSampleModel class.
*/
@Override
public int hashCode() {
int hash = 0;
int tmp = 0;
hash = width;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= height;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= numBands;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= dataType;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= scanlineStride;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= pixelBitStride;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= dataBitOffset;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= bitMask;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= dataElementSize;
tmp = hash >>> 24;
hash <<= 8;
hash |= tmp;
hash ^= pixelsPerDataElement;
return hash;
}
@Override
public int getTransferType() {
if (pixelBitStride > 16) {
return DataBuffer.TYPE_INT;
} else if (pixelBitStride > 8) {
return DataBuffer.TYPE_USHORT;
} else {
return DataBuffer.TYPE_BYTE;
}
}
/**
* Gets the scanline stride of this MultiPixelPackedSampleModel.
*
* @return the scanline stride of this MultiPixelPackedSampleModel.
*/
public int getScanlineStride() {
return scanlineStride;
}
/**
* Gets the pixel bit stride of this MultiPixelPackedSampleModel.
*
* @return the pixel bit stride of this MultiPixelPackedSampleModel.
*/
public int getPixelBitStride() {
return pixelBitStride;
}
@Override
public int getNumDataElements() {
return 1;
}
/**
* Gets the data bit offset.
*
* @return the data bit offset.
*/
public int getDataBitOffset() {
return dataBitOffset;
}
/**
* This method is used by other methods of this class. The behavior of this
* method depends on the method which has been invoke this one. The argument
* methodId is used to choose valid behavior in a particular case. If
* methodId is equal to 1 it means that this method has been invoked by the
* setDataElements() method, 2 - means setPixel(), and setSample() in any
* other cases.
*
* @param x
* the x.
* @param y
* the y.
* @param obj
* the obj.
* @param data
* the data.
* @param methodId
* the method id.
* @param s
* the s.
*/
private void setSample(final int x, final int y, final Object obj, final DataBuffer data,
final int methodId, int s) {
if ((x < 0) || (y < 0) || (x >= this.width) || (y >= this.height)) {
// awt.63=Coordinates are not in bounds
throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$
}
final int bitnum = dataBitOffset + x * pixelBitStride;
final int idx = y * scanlineStride + bitnum / dataElementSize;
final int shift = dataElementSize - (bitnum & (dataElementSize - 1)) - pixelBitStride;
final int mask = ~(bitMask << shift);
int elem = data.getElem(idx);
switch (methodId) {
case 1: { // Invoked from setDataElements()
switch (getTransferType()) {
case DataBuffer.TYPE_BYTE:
s = ((byte[])obj)[0] & 0xff;
break;
case DataBuffer.TYPE_USHORT:
s = ((short[])obj)[0] & 0xffff;
break;
case DataBuffer.TYPE_INT:
s = ((int[])obj)[0];
break;
}
break;
}
case 2: { // Invoked from setPixel()
s = ((int[])obj)[0];
break;
}
}
elem &= mask;
elem |= (s & bitMask) << shift;
data.setElem(idx, elem);
}
}