| /* |
| * 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); |
| } |
| } |