diff options
Diffstat (limited to 'libjava/java/awt/image/MultiPixelPackedSampleModel.java')
-rw-r--r-- | libjava/java/awt/image/MultiPixelPackedSampleModel.java | 387 |
1 files changed, 387 insertions, 0 deletions
diff --git a/libjava/java/awt/image/MultiPixelPackedSampleModel.java b/libjava/java/awt/image/MultiPixelPackedSampleModel.java new file mode 100644 index 00000000000..0525d37bd42 --- /dev/null +++ b/libjava/java/awt/image/MultiPixelPackedSampleModel.java @@ -0,0 +1,387 @@ +/* Copyright (C) 2004 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA +02111-1307 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.awt.image; + +import gnu.java.awt.Buffers; + +/** + * MultiPixelPackedSampleModel provides a single band model that supports + * multiple pixels in a single unit. Pixels have 2^n bits and 2^k pixels fit + * per data element. + * + * @author Jerry Quinn <jlquinn@optonline.net> + */ +public class MultiPixelPackedSampleModel extends SampleModel +{ + private int scanlineStride; + private int[] bitMasks; + private int[] bitOffsets; + private int[] sampleSize; + private int dataBitOffset; + private int elemBits; + private int numberOfBits; + private int numElems; + + public MultiPixelPackedSampleModel(int dataType, int w, int h, + int numberOfBits) + { + this(dataType, w, h, 0, numberOfBits, 0); + } + + public MultiPixelPackedSampleModel(int dataType, int w, int h, + int numberOfBits, int scanlineStride, + int dataBitOffset) + { + super(dataType, w, h, 1); + + switch (dataType) + { + case DataBuffer.TYPE_BYTE: + elemBits = 8; + break; + case DataBuffer.TYPE_USHORT: + elemBits = 16; + break; + case DataBuffer.TYPE_INT: + elemBits = 32; + break; + default: + throw new IllegalArgumentException("MultiPixelPackedSampleModel" + + " unsupported dataType"); + } + + this.dataBitOffset = dataBitOffset; + + this.numberOfBits = numberOfBits; + if (numberOfBits > elemBits) + throw new RasterFormatException("MultiPixelPackedSampleModel pixel size" + + " larger than dataType"); + switch (numberOfBits) + { + case 1: case 2: case 4: case 8: case 16: case 32: break; + default: + throw new RasterFormatException("MultiPixelPackedSampleModel pixel" + + " size not 2^n bits"); + } + numElems = elemBits / numberOfBits; + + // Compute scan line large enough for w pixels. + if (scanlineStride == 0) + scanlineStride = ((dataBitOffset + w * numberOfBits) / elemBits) + 1; + this.scanlineStride = scanlineStride; + + + sampleSize = new int[1]; + sampleSize[0] = numberOfBits; + + bitMasks = new int[numElems]; + bitOffsets = new int[numElems]; + for (int i=0; i < numElems; i++) + { + bitOffsets[i] = numberOfBits * i; + bitMasks[i] = ((1 << numberOfBits) - 1) << bitOffsets[i]; + } + } + + public SampleModel createCompatibleSampleModel(int w, int h) + { + /* FIXME: We can avoid recalculation of bit offsets and sample + sizes here by passing these from the current instance to a + special private constructor. */ + return new MultiPixelPackedSampleModel(dataType, w, h, numberOfBits); + } + + + /** + * Creates a DataBuffer for holding pixel data in the format and + * layout described by this SampleModel. The returned buffer will + * consist of one single bank. + */ + public DataBuffer createDataBuffer() + { + int size; + + // FIXME: The comment refers to SinglePixelPackedSampleModel. See if the + // same can be done for MultiPixelPackedSampleModel. + // We can save (scanlineStride - width) pixels at the very end of + // the buffer. The Sun reference implementation (J2SE 1.3.1 and + // 1.4.1_01) seems to do this; tested with Mauve test code. + size = scanlineStride * height; + + return Buffers.createBuffer(getDataType(), size); + } + + + public int getNumDataElements() + { + return 1; + } + + public int[] getSampleSize() + { + return sampleSize; + } + + public int getSampleSize(int band) + { + return sampleSize[0]; + } + + public int getOffset(int x, int y) + { + return scanlineStride * y + ((dataBitOffset + x*numberOfBits) / elemBits); + } + + public int getBitOffset(int x) + { + return (dataBitOffset + x*numberOfBits) % elemBits; + } + + public int getDataBitOffset() + { + return dataBitOffset; + } + + public int getScanlineStride() + { + return scanlineStride; + } + + public int getPixelBitStride() + { + return numberOfBits; + } + + + public SampleModel createSubsetSampleModel(int[] bands) + { + int numBands = bands.length; + if (numBands != 1) + throw new RasterFormatException("MultiPixelPackedSampleModel only" + + " supports one band"); + + return new MultiPixelPackedSampleModel(dataType, width, height, + numberOfBits, scanlineStride, + dataBitOffset); + } + + /** + * Extract one pixel and return in an array of transfer type. + * + * Extracts the pixel at x, y from data and stores into the 0th index of the + * array obj, since there is only one band. If obj is null, a new array of + * getTransferType() is created. + * + * @param x The x-coordinate of the pixel rectangle to store in <code>obj</code>. + * @param y The y-coordinate of the pixel rectangle to store in <code>obj</code>. + * @param obj The primitive array to store the pixels into or null to force creation. + * @param data The DataBuffer that is the source of the pixel data. + * @return The primitive array containing the pixel data. + * @see java.awt.image.SampleModel#getDataElements(int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public Object getDataElements(int x, int y, Object obj, + DataBuffer data) + { + int pixel = getSample(x, y, 0, data); + switch (getTransferType()) + { + case DataBuffer.TYPE_BYTE: + if (obj == null) obj = new byte[1]; + ((byte[])obj)[0] = (byte)pixel; + return obj; + case DataBuffer.TYPE_USHORT: + if (obj == null) obj = new short[1]; + ((short[])obj)[0] = (short)pixel; + return obj; + case DataBuffer.TYPE_INT: + if (obj == null) obj = new int[1]; + ((int[])obj)[0] = pixel; + return obj; + default: + // Seems like the only sensible thing to do. + throw new ClassCastException(); + } + } + + public int[] getPixel(int x, int y, int[] iArray, DataBuffer data) + { + if (iArray == null) iArray = new int[1]; + iArray[0] = getSample(x, y, 0, data); + + return iArray; + } + + public int[] getPixels(int x, int y, int w, int h, int[] iArray, + DataBuffer data) + { + int offset = getOffset(x, y); + if (iArray == null) iArray = new int[w*h]; + int outOffset = 0; + for (y=0; y<h; y++) + { + int lineOffset = offset; + for (x=0; x<w;) + { + int samples = data.getElem(lineOffset++); + for (int b=0; b<numElems && x<w; b++) + { + iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b]; + x++; + } + } + offset += scanlineStride; + } + return iArray; + } + + public int getSample(int x, int y, int b, DataBuffer data) + { + int pos = + ((dataBitOffset + x * numberOfBits) % elemBits) / numberOfBits; + int offset = getOffset(x, y); + int samples = data.getElem(offset); + return (samples & bitMasks[pos]) >>> bitOffsets[pos]; + } + + /** + * Set the pixel at x, y to the value in the first element of the primitive + * array obj. + * + * @param x The x-coordinate of the data elements in <code>obj</code>. + * @param y The y-coordinate of the data elements in <code>obj</code>. + * @param obj The primitive array containing the data elements to set. + * @param data The DataBuffer to store the data elements into. + * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer) + */ + public void setDataElements(int x, int y, Object obj, DataBuffer data) + { + int transferType = getTransferType(); + if (getTransferType() != data.getDataType()) + { + throw new IllegalArgumentException("transfer type ("+ + getTransferType()+"), "+ + "does not match data "+ + "buffer type (" + + data.getDataType() + + ")."); + } + + int offset = getOffset(x, y); + + try + { + switch (transferType) + { + case DataBuffer.TYPE_BYTE: + { + DataBufferByte out = (DataBufferByte) data; + byte[] in = (byte[]) obj; + out.getData()[offset] = in[0]; + return; + } + case DataBuffer.TYPE_USHORT: + { + DataBufferUShort out = (DataBufferUShort) data; + short[] in = (short[]) obj; + out.getData()[offset] = in[0]; + return; + } + case DataBuffer.TYPE_INT: + { + DataBufferInt out = (DataBufferInt) data; + int[] in = (int[]) obj; + out.getData()[offset] = in[0]; + return; + } + default: + throw new ClassCastException("Unsupported data type"); + } + } + catch (ArrayIndexOutOfBoundsException aioobe) + { + String msg = "While writing data elements" + + ", x="+x+", y="+y+ + ", width="+width+", height="+height+ + ", scanlineStride="+scanlineStride+ + ", offset="+offset+ + ", data.getSize()="+data.getSize()+ + ", data.getOffset()="+data.getOffset()+ + ": " + + aioobe; + throw new ArrayIndexOutOfBoundsException(msg); + } + } + + public void setPixel(int x, int y, int[] iArray, DataBuffer data) + { + setSample(x, y, 0, iArray[0], data); + } + + public void setSample(int x, int y, int b, int s, DataBuffer data) + { + int bitpos = + ((dataBitOffset + x * numberOfBits) % elemBits) / numberOfBits; + int offset = getOffset(x, y); + + s = s << bitOffsets[bitpos]; + s = s & bitMasks[bitpos]; + + int sample = data.getElem(offset); + sample |= s; + data.setElem(offset, sample); + } + + /** + * Creates a String with some information about this SampleModel. + * @return A String describing this SampleModel. + * @see java.lang.Object#toString() + */ + public String toString() + { + StringBuffer result = new StringBuffer(); + result.append(getClass().getName()); + result.append("["); + result.append("scanlineStride=").append(scanlineStride); + for(int i=0; i < bitMasks.length; i+=1) + { + result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i])); + } + + result.append("]"); + return result.toString(); + } +} |