OSDN Git Service

Merged gcj-eclipse branch to trunk.
[pf3gnuchains/gcc-fork.git] / libjava / classpath / java / awt / image / SinglePixelPackedSampleModel.java
1 /* Copyright (C) 2000, 2002, 2003, 2004, 2006,  Free Software Foundation
2
3 This file is part of GNU Classpath.
4
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)
8 any later version.
9
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.
14
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
18 02110-1301 USA.
19
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
23 combination.
24
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. */
36
37 package java.awt.image;
38
39 import java.util.Arrays;
40
41 import gnu.java.awt.BitMaskExtent;
42 import gnu.java.awt.Buffers;
43
44 /**
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.
48  * 
49  * @author Rolf W. Rasmussen (rolfwr@ii.uib.no)
50  */
51 public class SinglePixelPackedSampleModel extends SampleModel
52 {
53   private int scanlineStride;
54   private int[] bitMasks;
55   private int[] bitOffsets;
56   private int[] sampleSize;
57   
58   /**
59    * Creates a new <code>SinglePixelPackedSampleModel</code>.
60    * 
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.
66    */
67   public SinglePixelPackedSampleModel(int dataType, int w, int h,
68                                       int[] bitMasks)
69   {
70     this(dataType, w, h, w, bitMasks);
71   }
72
73   /**
74    * Creates a new <code>SinglePixelPackedSampleModel</code>.
75    * 
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.
83    */
84   public SinglePixelPackedSampleModel(int dataType, int w, int h,
85                                       int scanlineStride, int[] bitMasks)
86   {
87     super(dataType, w, h, bitMasks.length);
88
89     switch (dataType)
90       {
91       case DataBuffer.TYPE_BYTE:
92       case DataBuffer.TYPE_USHORT:
93       case DataBuffer.TYPE_INT:
94         break;
95       default:
96         throw new IllegalArgumentException(
97             "SinglePixelPackedSampleModel unsupported dataType");
98       }
99     
100     this.scanlineStride = scanlineStride;
101     this.bitMasks = bitMasks;
102     
103     bitOffsets = new int[numBands];
104     sampleSize = new int[numBands];
105     
106     BitMaskExtent extent = new BitMaskExtent();
107     for (int b = 0; b < numBands; b++)
108       {
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;
114       }
115   }
116
117   /**
118    * Returns the number of data elements.
119    * 
120    * @return <code>1</code>.
121    */
122   public int getNumDataElements()
123   {
124     return 1;
125   }
126
127   /**
128    * Creates a new <code>SampleModel</code> that is compatible with this
129    * model and has the specified width and height.
130    * 
131    * @param w  the width (in pixels).
132    * @param h  the height (in pixels).
133    * 
134    * @return The new sample model.
135    */
136   public SampleModel createCompatibleSampleModel(int w, int h)
137   {
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);
142   }
143
144
145   /**
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.
149    * 
150    * @return The data buffer.
151    */
152   public DataBuffer createDataBuffer()
153   {
154     int size;
155
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;
160
161     return Buffers.createBuffer(getDataType(), size);
162   }
163
164   /**
165    * Returns an array containing the size (in bits) for each band accessed by
166    * the <code>SampleModel</code>.
167    * 
168    * @return An array.
169    * 
170    * @see #getSampleSize(int)
171    */
172   public int[] getSampleSize()
173   {
174     return (int[]) sampleSize.clone();
175   }
176   
177   /**
178    * Returns the size (in bits) of the samples for the specified band.
179    * 
180    * @param band  the band (in the range <code>0</code> to 
181    *     <code>getNumBands() - 1</code>).
182    *     
183    * @return The sample size (in bits).
184    */
185   public int getSampleSize(int band)
186   {
187     return sampleSize[band];
188   }
189
190   /**
191    * Returns the index in the data buffer that stores the pixel at (x, y).
192    * 
193    * @param x  the x-coordinate.
194    * @param y  the y-coordinate.
195    * 
196    * @return The index in the data buffer that stores the pixel at (x, y).
197    */
198   public int getOffset(int x, int y)
199   {
200     return scanlineStride*y + x;
201   }
202
203   public int[] getBitOffsets()
204   {
205     return bitOffsets;
206   }
207
208   public int[] getBitMasks()
209   {
210     return bitMasks;
211   }
212
213   /**
214    * Returns the number of data elements from a pixel in one row to the
215    * corresponding pixel in the next row.
216    * 
217    * @return The scanline stride.
218    */
219   public int getScanlineStride()
220   {
221     return scanlineStride;
222   }
223
224   /**
225    * Creates a new <code>SinglePixelPackedSampleModel</code> that accesses
226    * the specified subset of bands.
227    * 
228    * @param bands  an array containing band indices (<code>null</code> not
229    *     permitted).
230    * 
231    * @return A new sample model.
232    * 
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.
236    */
237   public SampleModel createSubsetSampleModel(int[] bands)
238   {
239     if (bands.length > numBands)
240       throw new RasterFormatException("Too many bands.");
241     
242     int numBands = bands.length;
243     
244     int[] bitMasks = new int[numBands];
245
246     for (int b = 0; b < numBands; b++)
247       bitMasks[b] = this.bitMasks[bands[b]];
248
249     return new SinglePixelPackedSampleModel(dataType, width, height,
250                                             scanlineStride, bitMasks);
251   }
252
253   public Object getDataElements(int x, int y, Object obj,
254                                 DataBuffer data)
255   {
256     int offset = scanlineStride*y + x + data.getOffset();
257     
258     return Buffers.getData(data, offset, obj,
259                            0, // destination offset,
260                            1  // length
261                            );
262   }
263   
264   /**
265    * This is a more efficient implementation of the default implementation in 
266    * the super class. 
267    * @param x The x-coordinate of the pixel rectangle to store in 
268    *     <code>obj</code>.
269    * @param y The y-coordinate of the pixel rectangle to store in 
270    *     <code>obj</code>.
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 
274    *     creation.
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)
279    */
280   public Object getDataElements(int x, int y, int w, int h, Object obj,
281                                                         DataBuffer data)
282   {
283     int size = w*h;
284     int dataSize = size;
285     Object pixelData = null;
286     switch (getTransferType())
287     {
288       case DataBuffer.TYPE_BYTE:
289         pixelData = ((DataBufferByte) data).getData();
290         if (obj == null) obj = new byte[dataSize];
291         break;
292        case DataBuffer.TYPE_USHORT:
293          pixelData = ((DataBufferUShort) data).getData();
294          if (obj == null) obj = new short[dataSize];
295          break;
296         case DataBuffer.TYPE_INT:
297           pixelData = ((DataBufferInt) data).getData();
298           if (obj == null) obj = new int[dataSize];
299           break;
300          default:
301              // Seems like the only sensible thing to do.
302            throw new ClassCastException();
303       }
304       if(x == 0 && scanlineStride == w)
305       { 
306         // The full width need to be copied therefore we can copy in one shot.
307         System.arraycopy(pixelData, scanlineStride*y + data.getOffset(), obj, 
308                          0, size);
309       }
310       else
311       {  
312         // Since we do not need the full width we need to copy line by line.
313         int outOffset = 0;
314         int dataOffset = scanlineStride*y + x + data.getOffset();
315         for (int yy = y; yy<(y+h); yy++)
316         {
317           System.arraycopy(pixelData, dataOffset, obj, outOffset, w);
318           dataOffset += scanlineStride;
319           outOffset += w;
320         }
321       }
322     return obj;
323   }
324   
325   /**
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).
330    * 
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).
336    * 
337    * @return The pixel sample values.
338    * 
339    * @throws NullPointerException if <code>data</code> is <code>null</code>.
340    */
341   public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
342   {
343     int offset = scanlineStride*y + x;
344     if (iArray == null) iArray = new int[numBands];
345     int samples = data.getElem(offset);
346
347     for (int b = 0; b < numBands; b++)
348       iArray[b] = (samples & bitMasks[b]) >>> bitOffsets[b];
349         
350     return iArray;
351   }
352
353   /**
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).
361    * 
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).
369    * 
370    * @return The pixel sample values.
371    * 
372    * @throws NullPointerException if <code>data</code> is <code>null</code>.
373    */
374   public int[] getPixels(int x, int y, int w, int h, int[] iArray,
375                          DataBuffer data)
376   {
377     int offset = scanlineStride*y + x;
378     if (iArray == null) iArray = new int[numBands*w*h];
379     int outOffset = 0;
380     for (y = 0; y < h; y++)
381       {
382         int lineOffset = offset;
383         for (x = 0; x < w; x++)
384           {
385             int samples = data.getElem(lineOffset++);
386             for (int b = 0; b < numBands; b++)
387               iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b];
388           }
389         offset += scanlineStride;
390       }
391     return iArray;      
392   }
393
394   /**
395    * Returns the sample value for the pixel at (x, y) in the specified data 
396    * buffer.
397    * 
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).
403    * 
404    * @return The sample value.
405    * 
406    * @throws NullPointerException if <code>data</code> is <code>null</code>.
407    */
408   public int getSample(int x, int y, int b, DataBuffer data)
409   {
410     int offset = scanlineStride*y + x;
411     int samples = data.getElem(offset);
412     return (samples & bitMasks[b]) >>> bitOffsets[b];
413   }
414   
415   public void setDataElements(int x, int y, Object obj, DataBuffer data)
416   {
417     
418     int transferType = getTransferType();
419         switch (transferType)
420           {
421           case DataBuffer.TYPE_BYTE:
422             {
423               byte[] in = (byte[]) obj;
424               data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xff);
425               break;
426             }
427           case DataBuffer.TYPE_USHORT:
428             {
429               short[] in = (short[]) obj;
430           data.setElem(y * scanlineStride + x, ((int) in[0]) & 0xffff);
431           break;
432             }
433           case DataBuffer.TYPE_INT:
434             {
435               int[] in = (int[]) obj;
436           data.setElem(y * scanlineStride + x, in[0]);
437           break;
438             }
439           }
440     }
441
442   /**
443    * Sets the samples for the pixel at (x, y) in the specified data buffer to
444    * the specified values. 
445    * 
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).
450    * 
451    * @throws NullPointerException if either <code>iArray</code> or 
452    *     <code>data</code> is <code>null</code>.
453    */
454   public void setPixel(int x, int y, int[] iArray, DataBuffer data)
455   {
456     int offset = scanlineStride*y + x;
457     
458     int samples = 0;
459     for (int b = 0; b < numBands; b++)
460       samples |= (iArray[b] << bitOffsets[b]) & bitMasks[b];
461
462     data.setElem(offset, samples);
463   }
464
465   /**
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)
477    */
478   public void setPixels(int x, int y, int w, int h, int[] iArray,
479                                                 DataBuffer data)
480   {
481     int inOffset = 0;
482     int[] pixel = new int[numBands];
483     for (int yy=y; yy<(y+h); yy++)
484      {
485       int offset = scanlineStride*yy + x;
486       for (int xx=x; xx<(x+w); xx++)
487        { 
488         int samples = 0;
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;
493         offset += 1;
494       }
495     }
496   }
497   
498   /**
499    * Sets the sample value for a band for the pixel at (x, y) in the 
500    * specified data buffer. 
501    * 
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).
508    * 
509    * @throws NullPointerException if <code>data</code> is <code>null</code>.
510    */
511   public void setSample(int x, int y, int b, int s, DataBuffer data)
512   {
513     int offset = scanlineStride*y + x;
514     int samples = data.getElem(offset);
515     int bitMask = bitMasks[b];
516     samples &= ~bitMask;
517     samples |= (s << bitOffsets[b]) & bitMask;
518     data.setElem(offset, samples);
519   }
520   
521   /**
522    * Tests this sample model for equality with an arbitrary object.  This 
523    * method returns <code>true</code> if and only if:
524    * <ul>
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:
529    *     <ul>
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>.
537    *     </ul>
538    *   </li>
539    * </ul>
540    * 
541    * @param obj  the object (<code>null</code> permitted)
542    * 
543    * @return <code>true</code> if this model is equal to <code>obj</code>, and
544    *     <code>false</code> otherwise.
545    */
546   public boolean equals(Object obj) 
547   {
548     if (this == obj) 
549       return true;
550     if (! (obj instanceof SinglePixelPackedSampleModel)) 
551       return false;
552     SinglePixelPackedSampleModel that = (SinglePixelPackedSampleModel) obj;
553     if (this.dataType != that.dataType)
554       return false;
555     if (this.width != that.width)
556       return false;
557     if (this.height != that.height)
558       return false;
559     if (this.numBands != that.numBands)
560       return false;
561     if (this.scanlineStride != that.scanlineStride)
562       return false;
563     if (!Arrays.equals(this.bitMasks, that.bitMasks))
564       return false;
565     if (!Arrays.equals(this.bitOffsets, that.bitOffsets)) 
566       return false;
567     return true;
568   }
569   
570   /**
571    * Returns a hash code for this <code>SinglePixelPackedSampleModel</code>.
572    * 
573    * @return A hash code.
574    */
575   public int hashCode()
576   {
577     // this hash code won't match Sun's, but that shouldn't matter...
578     int result = 193;
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];
588     return result;
589   }
590   
591   /**
592    * Creates a String with some information about this SampleModel.
593    * @return A String describing this SampleModel.
594    * @see java.lang.Object#toString()
595    */
596   public String toString()
597   {
598     StringBuffer result = new StringBuffer();
599     result.append(getClass().getName());
600     result.append("[");
601     result.append("scanlineStride=").append(scanlineStride);
602     for(int i = 0; i < bitMasks.length; i+=1)
603     {
604       result.append(", mask[").append(i).append("]=0x").append(
605           Integer.toHexString(bitMasks[i]));
606     }
607     
608     result.append("]");
609     return result.toString();
610   }
611 }