480 lines
15 KiB
Java
480 lines
15 KiB
Java
/*
|
|
* 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);
|
|
}
|
|
}
|