/* * 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.util.Arrays; import org.apache.harmony.awt.internal.nls.Messages; /** * The SinglePixelPackedSampleModel class represents pixel data where several * samples combine to create a single pixel and are stored in a single data * array element. This class supports TYPE_BYTE, TYPE_USHORT, TYPE_INT data * types. * * @since Android 1.0 */ public class SinglePixelPackedSampleModel extends SampleModel { /** * The bit masks. */ private int bitMasks[]; /** * The bit offsets. */ private int bitOffsets[]; /** * The bit sizes. */ private int bitSizes[]; /** * The scanline stride. */ private int scanlineStride; /** * The max bit size. */ private int maxBitSize; /** * Instantiates a new SinglePixelPackedSampleModel with the specified * parameters. * * @param dataType * the data type of samples. * @param w * the width of the image data. * @param h * the height of the image data. * @param bitMasks * the bit masks for all the bands. */ public SinglePixelPackedSampleModel(int dataType, int w, int h, int bitMasks[]) { this(dataType, w, h, w, bitMasks); } /** * Instantiates a new SinglePixelPackedSampleModel 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 scanlineStride * the scanline stride of the image data. * @param bitMasks * the bit masks for all the bands. */ public SinglePixelPackedSampleModel(int dataType, int w, int h, int scanlineStride, int bitMasks[]) { super(dataType, w, h, bitMasks.length); 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; this.bitMasks = bitMasks.clone(); this.bitOffsets = new int[this.numBands]; this.bitSizes = new int[this.numBands]; this.maxBitSize = 0; for (int i = 0; i < this.numBands; i++) { int offset = 0; int size = 0; int mask = bitMasks[i]; if (mask != 0) { while ((mask & 1) == 0) { mask >>>= 1; offset++; } while ((mask & 1) == 1) { mask >>>= 1; size++; } if (mask != 0) { // awt.62=Wrong mask : {0} throw new IllegalArgumentException(Messages.getString("awt.62", bitMasks[i])); //$NON-NLS-1$ } } this.bitOffsets[i] = offset; this.bitSizes[i] = size; if (this.maxBitSize < size) { this.maxBitSize = size; } } } @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)data.getElem(y * scanlineStride + x); obj = bdata; break; case DataBuffer.TYPE_USHORT: short sdata[]; if (obj == null) { sdata = new short[1]; } else { sdata = (short[])obj; } sdata[0] = (short)data.getElem(y * scanlineStride + x); obj = sdata; break; case DataBuffer.TYPE_INT: int idata[]; if (obj == null) { idata = new int[1]; } else { idata = (int[])obj; } idata[0] = data.getElem(y * scanlineStride + x); obj = idata; break; } return obj; } @Override public void setDataElements(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: data.setElem(y * scanlineStride + x, ((byte[])obj)[0] & 0xff); break; case DataBuffer.TYPE_USHORT: data.setElem(y * scanlineStride + x, ((short[])obj)[0] & 0xffff); break; case DataBuffer.TYPE_INT: data.setElem(y * scanlineStride + x, ((int[])obj)[0]); break; } } /** * Compares this SinglePixelPackedSampleModel object with the specified * object. * * @param o * the Object to be compared. * @return true, if this SinglePixelPackedSampleModel object is equal to the * specified object, false otherwise. */ @Override public boolean equals(Object o) { if ((o == null) || !(o instanceof SinglePixelPackedSampleModel)) { return false; } SinglePixelPackedSampleModel model = (SinglePixelPackedSampleModel)o; return this.width == model.width && this.height == model.height && this.numBands == model.numBands && this.dataType == model.dataType && Arrays.equals(this.bitMasks, model.bitMasks) && Arrays.equals(this.bitOffsets, model.bitOffsets) && Arrays.equals(this.bitSizes, model.bitSizes) && this.scanlineStride == model.scanlineStride; } @Override public SampleModel createSubsetSampleModel(int bands[]) { if (bands.length > this.numBands) { // awt.64=The number of the bands in the subset is greater than the // number of bands in the sample model throw new RasterFormatException(Messages.getString("awt.64")); //$NON-NLS-1$ } int masks[] = new int[bands.length]; for (int i = 0; i < bands.length; i++) { masks[i] = this.bitMasks[bands[i]]; } return new SinglePixelPackedSampleModel(this.dataType, this.width, this.height, this.scanlineStride, masks); } @Override public SampleModel createCompatibleSampleModel(int w, int h) { return new SinglePixelPackedSampleModel(this.dataType, w, h, this.bitMasks); } @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[this.numBands]; } else { pixel = iArray; } for (int i = 0; i < this.numBands; i++) { pixel[i] = getSample(x, y, i, data); } return pixel; } @Override public void setPixel(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$ } for (int i = 0; i < this.numBands; i++) { setSample(x, y, i, iArray[i], data); } } @Override public int getSample(int x, int y, int b, 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 sample = data.getElem(y * scanlineStride + x); return ((sample & this.bitMasks[b]) >>> this.bitOffsets[b]); } @Override public int[] getPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) || ((long)y + (long)h > this.height)) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } int pixels[]; if (iArray == null) { pixels = new int[w * h * this.numBands]; } else { pixels = iArray; } int idx = 0; for (int i = y; i < y + h; i++) { for (int j = x; j < x + w; j++) { for (int n = 0; n < this.numBands; n++) { pixels[idx++] = getSample(j, i, n, data); } } } return pixels; } @Override public void setPixels(int x, int y, int w, int h, int iArray[], DataBuffer data) { if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) || ((long)y + (long)h > this.height)) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } int idx = 0; for (int i = y; i < y + h; i++) { for (int j = x; j < x + w; j++) { for (int n = 0; n < this.numBands; n++) { setSample(j, i, n, iArray[idx++], data); } } } } @Override public void setSample(int x, int y, int b, int s, 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 tmp = data.getElem(y * scanlineStride + x); tmp &= ~this.bitMasks[b]; tmp |= (s << this.bitOffsets[b]) & this.bitMasks[b]; data.setElem(y * scanlineStride + x, tmp); } @Override public int[] getSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) || ((long)y + (long)h > this.height)) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } int samples[]; int idx = 0; if (iArray == null) { samples = new int[w * h]; } else { samples = iArray; } for (int i = y; i < y + h; i++) { for (int j = x; j < x + w; j++) { samples[idx++] = getSample(j, i, b, data); } } return samples; } @Override public void setSamples(int x, int y, int w, int h, int b, int iArray[], DataBuffer data) { if ((x < 0) || (y < 0) || ((long)x + (long)w > this.width) || ((long)y + (long)h > this.height)) { // awt.63=Coordinates are not in bounds throw new ArrayIndexOutOfBoundsException(Messages.getString("awt.63")); //$NON-NLS-1$ } int idx = 0; for (int i = y; i < y + h; i++) { for (int j = x; j < x + w; j++) { setSample(x + j, y + i, b, iArray[idx++], data); } } } @Override public DataBuffer createDataBuffer() { DataBuffer data = null; int size = (this.height - 1) * scanlineStride + width; switch (this.dataType) { case DataBuffer.TYPE_BYTE: data = new DataBufferByte(size); break; case DataBuffer.TYPE_USHORT: data = new DataBufferUShort(size); break; case DataBuffer.TYPE_INT: data = new DataBufferInt(size); break; } return data; } /** * 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); } @Override public int getSampleSize(int band) { return bitSizes[band]; } @Override public int[] getSampleSize() { return bitSizes.clone(); } /** * Gets an array of the bit offsets of the data array elements. * * @return an array of the bit offsets. */ public int[] getBitOffsets() { return bitOffsets.clone(); } /** * Gets an array of the bit masks for all bands. * * @return an array of the bit masks for all bands. */ public int[] getBitMasks() { return bitMasks.clone(); } /** * 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; for (int element : bitMasks) { hash ^= element; tmp = hash >>> 24; hash <<= 8; hash |= tmp; } for (int element : bitOffsets) { hash ^= element; tmp = hash >>> 24; hash <<= 8; hash |= tmp; } for (int element : bitSizes) { hash ^= element; tmp = hash >>> 24; hash <<= 8; hash |= tmp; } hash ^= scanlineStride; return hash; } /** * Gets the scanline stride. * * @return the scanline stride */ public int getScanlineStride() { return this.scanlineStride; } @Override public int getNumDataElements() { return 1; } }