1 /* Copyright (C) 2000, 2002, 2003, 2004, 2006, Free Software Foundation
3 This file is part of GNU Classpath.
5 GNU Classpath is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2, or (at your option)
10 GNU Classpath is distributed in the hope that it will be useful, but
11 WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with GNU Classpath; see the file COPYING. If not, write to the
17 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 Linking this library statically or dynamically with other modules is
21 making a combined work based on this library. Thus, the terms and
22 conditions of the GNU General Public License cover the whole
25 As a special exception, the copyright holders of this library give you
26 permission to link this library with independent modules to produce an
27 executable, regardless of the license terms of these independent
28 modules, and to copy and distribute the resulting executable under
29 terms of your choice, provided that you also meet, for each linked
30 independent module, the terms and conditions of the license of that
31 module. An independent module is a module which is not derived from
32 or based on this library. If you modify this library, you may extend
33 this exception to your version of the library, but you are not
34 obligated to do so. If you do not wish to do so, delete this
35 exception statement from your version. */
37 package java.awt.image;
39 import java.util.Arrays;
41 import gnu.java.awt.BitMaskExtent;
42 import gnu.java.awt.Buffers;
45 * A <code>SampleModel</code> used when all samples are stored in a single
46 * data element in the {@link DataBuffer}, and each data element contains
47 * samples for one pixel only.
49 * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
51 public class SinglePixelPackedSampleModel extends SampleModel
53 private int scanlineStride;
54 private int[] bitMasks;
55 private int[] bitOffsets;
56 private int[] sampleSize;
59 * Creates a new <code>SinglePixelPackedSampleModel</code>.
61 * @param dataType the data buffer type.
62 * @param w the width (in pixels).
63 * @param h the height (in pixels).
64 * @param bitMasks an array containing the bit mask used to extract the
65 * sample value for each band.
67 public SinglePixelPackedSampleModel(int dataType, int w, int h,
70 this(dataType, w, h, w, bitMasks);
74 * Creates a new <code>SinglePixelPackedSampleModel</code>.
76 * @param dataType the data buffer type.
77 * @param w the width (in pixels).
78 * @param h the height (in pixels).
79 * @param scanlineStride the number of data elements between a pixel on one
80 * row and the corresponding pixel on the next row.
81 * @param bitMasks an array containing the bit mask used to extract the
82 * sample value for each band.
84 public SinglePixelPackedSampleModel(int dataType, int w, int h,
85 int scanlineStride, int[] bitMasks)
87 super(dataType, w, h, bitMasks.length);
91 case DataBuffer.TYPE_BYTE:
92 case DataBuffer.TYPE_USHORT:
93 case DataBuffer.TYPE_INT:
96 throw new IllegalArgumentException(
97 "SinglePixelPackedSampleModel unsupported dataType");
100 this.scanlineStride = scanlineStride;
101 this.bitMasks = bitMasks;
103 bitOffsets = new int[numBands];
104 sampleSize = new int[numBands];
106 BitMaskExtent extent = new BitMaskExtent();
107 for (int b = 0; b < numBands; b++)
109 // the mask is an unsigned integer
110 long mask = bitMasks[b] & 0xFFFFFFFFL;
111 extent.setMask(mask);
112 sampleSize[b] = extent.bitWidth;
113 bitOffsets[b] = extent.leastSignificantBit;
118 * Returns the number of data elements.
120 * @return <code>1</code>.
122 public int getNumDataElements()
128 * Creates a new <code>SampleModel</code> that is compatible with this
129 * model and has the specified width and height.
131 * @param w the width (in pixels).
132 * @param h the height (in pixels).
134 * @return The new sample model.
136 public SampleModel createCompatibleSampleModel(int w, int h)
138 /* FIXME: We can avoid recalculation of bit offsets and sample
139 sizes here by passing these from the current instance to a
140 special private constructor. */
141 return new SinglePixelPackedSampleModel(dataType, w, h, bitMasks);
146 * Creates a DataBuffer for holding pixel data in the format and
147 * layout described by this SampleModel. The returned buffer will
148 * consist of one single bank.
150 * @return The data buffer.
152 public DataBuffer createDataBuffer()
156 // We can save (scanlineStride - width) pixels at the very end of
157 // the buffer. The Sun reference implementation (J2SE 1.3.1 and
158 // 1.4.1_01) seems to do this; tested with Mauve test code.
159 size = scanlineStride * (height - 1) + width;
161 return Buffers.createBuffer(getDataType(), size);
165 * Returns an array containing the size (in bits) for each band accessed by
166 * the <code>SampleModel</code>.
170 * @see #getSampleSize(int)
172 public int[] getSampleSize()
174 return (int[]) sampleSize.clone();
178 * Returns the size (in bits) of the samples for the specified band.
180 * @param band the band (in the range <code>0</code> to
181 * <code>getNumBands() - 1</code>).
183 * @return The sample size (in bits).
185 public int getSampleSize(int band)
187 return sampleSize[band];
191 * Returns the index in the data buffer that stores the pixel at (x, y).
193 * @param x the x-coordinate.
194 * @param y the y-coordinate.
196 * @return The index in the data buffer that stores the pixel at (x, y).
198 public int getOffset(int x, int y)
200 return scanlineStride*y + x;
203 public int[] getBitOffsets()
208 public int[] getBitMasks()
214 * Returns the number of data elements from a pixel in one row to the
215 * corresponding pixel in the next row.
217 * @return The scanline stride.
219 public int getScanlineStride()
221 return scanlineStride;
225 * Creates a new <code>SinglePixelPackedSampleModel</code> that accesses
226 * the specified subset of bands.
228 * @param bands an array containing band indices (<code>null</code> not
231 * @return A new sample model.
233 * @throws NullPointerException if <code>bands</code> is <code>null</code>.
234 * @throws RasterFormatException if <code>bands.length</code> is greater
235 * than the number of bands in this model.
237 public SampleModel createSubsetSampleModel(int[] bands)
239 if (bands.length > numBands)
240 throw new RasterFormatException("Too many bands.");
242 int numBands = bands.length;
244 int[] bitMasks = new int[numBands];
246 for (int b = 0; b < numBands; b++)
247 bitMasks[b] = this.bitMasks[bands[b]];
249 return new SinglePixelPackedSampleModel(dataType, width, height,
250 scanlineStride, bitMasks);
253 public Object getDataElements(int x, int y, Object obj,
256 int offset = scanlineStride*y + x + data.getOffset();
258 return Buffers.getData(data, offset, obj,
259 0, // destination offset,
265 * This is a more efficient implementation of the default implementation in
267 * @param x The x-coordinate of the pixel rectangle to store in
269 * @param y The y-coordinate of the pixel rectangle to store in
271 * @param w The width of the pixel rectangle to store in <code>obj</code>.
272 * @param h The height of the pixel rectangle to store in <code>obj</code>.
273 * @param obj The primitive array to store the pixels into or null to force
275 * @param data The DataBuffer that is the source of the pixel data.
276 * @return The primitive array containing the pixel data.
277 * @see java.awt.image.SampleModel#getDataElements(int, int, int, int,
278 * java.lang.Object, java.awt.image.DataBuffer)
280 public Object getDataElements(int x, int y, int w, int h, Object obj,
285 Object pixelData = null;
286 switch (getTransferType())
288 case DataBuffer.TYPE_BYTE:
289 pixelData = ((DataBufferByte) data).getData();
290 if (obj == null) obj = new byte[dataSize];
292 case DataBuffer.TYPE_USHORT:
293 pixelData = ((DataBufferUShort) data).getData();
294 if (obj == null) obj = new short[dataSize];
296 case DataBuffer.TYPE_INT:
297 pixelData = ((DataBufferInt) data).getData();
298 if (obj == null) obj = new int[dataSize];
301 // Seems like the only sensible thing to do.
302 throw new ClassCastException();
304 if(x == 0 && scanlineStride == w)
306 // The full width need to be copied therefore we can copy in one shot.
307 System.arraycopy(pixelData, scanlineStride*y + data.getOffset(), obj,
312 // Since we do not need the full width we need to copy line by line.
314 int dataOffset = scanlineStride*y + x + data.getOffset();
315 for (int yy = y; yy<(y+h); yy++)
317 System.arraycopy(pixelData, dataOffset, obj, outOffset, w);
318 dataOffset += scanlineStride;
326 * Returns an array containing the samples for the pixel at (x, y) in the
327 * specified data buffer. If <code>iArray</code> is not <code>null</code>,
328 * it will be populated with the sample values and returned as the result of
329 * this function (this avoids allocating a new array instance).
331 * @param x the x-coordinate of the pixel.
332 * @param y the y-coordinate of the pixel.
333 * @param iArray an array to populate with the sample values and return as
334 * the result (if <code>null</code>, a new array will be allocated).
335 * @param data the data buffer (<code>null</code> not permitted).
337 * @return The pixel sample values.
339 * @throws NullPointerException if <code>data</code> is <code>null</code>.
341 public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
343 int offset = scanlineStride*y + x;
344 if (iArray == null) iArray = new int[numBands];
345 int samples = data.getElem(offset);
347 for (int b = 0; b < numBands; b++)
348 iArray[b] = (samples & bitMasks[b]) >>> bitOffsets[b];
354 * Returns an array containing the samples for the pixels in the region
355 * specified by (x, y, w, h) in the specified data buffer. The array is
356 * ordered by pixels (that is, all the samples for the first pixel are
357 * grouped together, followed by all the samples for the second pixel, and so
358 * on). If <code>iArray</code> is not <code>null</code>, it will be
359 * populated with the sample values and returned as the result of this
360 * function (this avoids allocating a new array instance).
362 * @param x the x-coordinate of the top-left pixel.
363 * @param y the y-coordinate of the top-left pixel.
364 * @param w the width of the region of pixels.
365 * @param h the height of the region of pixels.
366 * @param iArray an array to populate with the sample values and return as
367 * the result (if <code>null</code>, a new array will be allocated).
368 * @param data the data buffer (<code>null</code> not permitted).
370 * @return The pixel sample values.
372 * @throws NullPointerException if <code>data</code> is <code>null</code>.
374 public int[] getPixels(int x, int y, int w, int h, int[] iArray,
377 int offset = scanlineStride*y + x;
378 if (iArray == null) iArray = new int[numBands*w*h];
380 for (y = 0; y < h; y++)
382 int lineOffset = offset;
383 for (x = 0; x < w; x++)
385 int samples = data.getElem(lineOffset++);
386 for (int b = 0; b < numBands; b++)
387 iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b];
389 offset += scanlineStride;
395 * Returns the sample value for the pixel at (x, y) in the specified data
398 * @param x the x-coordinate of the pixel.
399 * @param y the y-coordinate of the pixel.
400 * @param b the band (in the range <code>0</code> to
401 * <code>getNumBands() - 1</code>).
402 * @param data the data buffer (<code>null</code> not permitted).
404 * @return The sample value.
406 * @throws NullPointerException if <code>data</code> is <code>null</code>.
408 public int getSample(int x, int y, int b, DataBuffer data)
410 int offset = scanlineStride*y + x;
411 int samples = data.getElem(offset);
412 return (samples & bitMasks[b]) >>> bitOffsets[b];
415 public void setDataElements(int x, int y, Object obj, DataBuffer data)
418 int transferType = getTransferType();
419 switch (transferType)
421 case DataBuffer.TYPE_BYTE:
423 byte[] in = (byte[]) obj;
424 data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xff);
427 case DataBuffer.TYPE_USHORT:
429 short[] in = (short[]) obj;
430 data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xffff);
433 case DataBuffer.TYPE_INT:
435 int[] in = (int[]) obj;
436 data.setElem(y * scanlineStride + x, in[0]);
443 * Sets the samples for the pixel at (x, y) in the specified data buffer to
444 * the specified values.
446 * @param x the x-coordinate of the pixel.
447 * @param y the y-coordinate of the pixel.
448 * @param iArray the sample values (<code>null</code> not permitted).
449 * @param data the data buffer (<code>null</code> not permitted).
451 * @throws NullPointerException if either <code>iArray</code> or
452 * <code>data</code> is <code>null</code>.
454 public void setPixel(int x, int y, int[] iArray, DataBuffer data)
456 int offset = scanlineStride*y + x;
459 for (int b = 0; b < numBands; b++)
460 samples |= (iArray[b] << bitOffsets[b]) & bitMasks[b];
462 data.setElem(offset, samples);
466 * This method implements a more efficient way to set pixels than the default
467 * implementation of the super class. It copies the pixel components directly
468 * from the input array instead of creating a intermediate buffer.
469 * @param x The x-coordinate of the pixel rectangle in <code>obj</code>.
470 * @param y The y-coordinate of the pixel rectangle in <code>obj</code>.
471 * @param w The width of the pixel rectangle in <code>obj</code>.
472 * @param h The height of the pixel rectangle in <code>obj</code>.
473 * @param iArray The primitive array containing the pixels to set.
474 * @param data The DataBuffer to store the pixels into.
475 * @see java.awt.image.SampleModel#setPixels(int, int, int, int, int[],
476 * java.awt.image.DataBuffer)
478 public void setPixels(int x, int y, int w, int h, int[] iArray,
482 int[] pixel = new int[numBands];
483 for (int yy=y; yy<(y+h); yy++)
485 int offset = scanlineStride*yy + x;
486 for (int xx=x; xx<(x+w); xx++)
489 for (int b = 0; b < numBands; b++)
490 samples |= (iArray[inOffset+b] << bitOffsets[b]) & bitMasks[b];
491 data.setElem(0, offset, samples);
492 inOffset += numBands;
499 * Sets the sample value for a band for the pixel at (x, y) in the
500 * specified data buffer.
502 * @param x the x-coordinate of the pixel.
503 * @param y the y-coordinate of the pixel.
504 * @param b the band (in the range <code>0</code> to
505 * <code>getNumBands() - 1</code>).
506 * @param s the sample value.
507 * @param data the data buffer (<code>null</code> not permitted).
509 * @throws NullPointerException if <code>data</code> is <code>null</code>.
511 public void setSample(int x, int y, int b, int s, DataBuffer data)
513 int offset = scanlineStride*y + x;
514 int samples = data.getElem(offset);
515 int bitMask = bitMasks[b];
517 samples |= (s << bitOffsets[b]) & bitMask;
518 data.setElem(offset, samples);
522 * Tests this sample model for equality with an arbitrary object. This
523 * method returns <code>true</code> if and only if:
525 * <li><code>obj</code> is not <code>null</code>;
526 * <li><code>obj</code> is an instance of
527 * <code>SinglePixelPackedSampleModel</code>;
528 * <li>both models have the same:
530 * <li><code>dataType</code>;
531 * <li><code>width</code>;
532 * <li><code>height</code>;
533 * <li><code>numBands</code>;
534 * <li><code>scanlineStride</code>;
535 * <li><code>bitMasks</code>;
536 * <li><code>bitOffsets</code>.
541 * @param obj the object (<code>null</code> permitted)
543 * @return <code>true</code> if this model is equal to <code>obj</code>, and
544 * <code>false</code> otherwise.
546 public boolean equals(Object obj)
550 if (! (obj instanceof SinglePixelPackedSampleModel))
552 SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel) obj;
553 if (this.dataType != that.dataType)
555 if (this.width != that.width)
557 if (this.height != that.height)
559 if (this.numBands != that.numBands)
561 if (this.scanlineStride != that.scanlineStride)
563 if (!Arrays.equals(this.bitMasks, that.bitMasks))
565 if (!Arrays.equals(this.bitOffsets, that.bitOffsets))
571 * Returns a hash code for this <code>SinglePixelPackedSampleModel</code>.
573 * @return A hash code.
575 public int hashCode()
577 // this hash code won't match Sun's, but that shouldn't matter...
579 result = 37 * result + dataType;
580 result = 37 * result + width;
581 result = 37 * result + height;
582 result = 37 * result + numBands;
583 result = 37 * result + scanlineStride;
584 for (int i = 0; i < bitMasks.length; i++)
585 result = 37 * result + bitMasks[i];
586 for (int i = 0; i < bitOffsets.length; i++)
587 result = 37 * result + bitOffsets[i];
592 * Creates a String with some information about this SampleModel.
593 * @return A String describing this SampleModel.
594 * @see java.lang.Object#toString()
596 public String toString()
598 StringBuffer result = new StringBuffer();
599 result.append(getClass().getName());
601 result.append("scanlineStride=").append(scanlineStride);
602 for(int i = 0; i < bitMasks.length; i+=1)
604 result.append(", mask[").append(i).append("]=0x").append(
605 Integer.toHexString(bitMasks[i]));
609 return result.toString();