OSDN Git Service

2004-11-30 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / image / SinglePixelPackedSampleModel.java
1 /* Copyright (C) 2000, 2002, 2003, 2004  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., 59 Temple Place, Suite 330, Boston, MA
18 02111-1307 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 gnu.java.awt.BitMaskExtent;
40 import gnu.java.awt.Buffers;
41
42 /**
43  * @author Rolf W. Rasmussen <rolfwr@ii.uib.no>
44  */
45 public class SinglePixelPackedSampleModel extends SampleModel
46 {
47   private int scanlineStride;
48   private int[] bitMasks;
49   private int[] bitOffsets;
50   private int[] sampleSize;
51   
52   public SinglePixelPackedSampleModel(int dataType, int w, int h,
53                                       int[] bitMasks)
54   {
55     this(dataType, w, h, w, bitMasks);
56   }
57
58   public SinglePixelPackedSampleModel(int dataType, int w, int h,
59                                       int scanlineStride, int[] bitMasks)
60   {
61     super(dataType, w, h, bitMasks.length);
62
63     switch (dataType)
64       {
65       case DataBuffer.TYPE_BYTE:
66       case DataBuffer.TYPE_USHORT:
67       case DataBuffer.TYPE_INT:
68         break;
69       default:
70         throw new IllegalArgumentException("SinglePixelPackedSampleModel unsupported dataType");
71       }
72     
73     this.scanlineStride = scanlineStride;
74     this.bitMasks = bitMasks;
75     
76     bitOffsets = new int[numBands];
77     sampleSize = new int[numBands];
78     
79     BitMaskExtent extent = new BitMaskExtent();
80     for (int b=0; b<numBands; b++)
81       {
82         extent.setMask(bitMasks[b]);
83         sampleSize[b] = extent.bitWidth;
84         bitOffsets[b] = extent.leastSignificantBit;
85       }
86   }
87
88   public int getNumDataElements()
89   {
90     return 1;
91   }
92
93   public SampleModel createCompatibleSampleModel(int w, int h)
94   {
95     /* FIXME: We can avoid recalculation of bit offsets and sample
96        sizes here by passing these from the current instance to a
97        special private constructor. */
98     return new SinglePixelPackedSampleModel(dataType, w, h, bitMasks);
99   }
100
101
102   /**
103    * Creates a DataBuffer for holding pixel data in the format and
104    * layout described by this SampleModel. The returned buffer will
105    * consist of one single bank.
106    */
107   public DataBuffer createDataBuffer()
108   {
109     int size;
110
111     // We can save (scanlineStride - width) pixels at the very end of
112     // the buffer. The Sun reference implementation (J2SE 1.3.1 and
113     // 1.4.1_01) seems to do this; tested with Mauve test code.
114     size = scanlineStride * (height - 1) + width;
115
116     return Buffers.createBuffer(getDataType(), size);
117   }
118
119
120   public int[] getSampleSize()
121   {
122     return sampleSize;
123   }
124   
125   public int getSampleSize(int band)
126   {
127     return sampleSize[band];
128   }
129
130   public int getOffset(int x, int y)
131   {
132     return scanlineStride*y + x;
133   }
134
135   public int[] getBitOffsets()
136   {
137     return bitOffsets;
138   }
139
140   public int[] getBitMasks()
141   {
142     return bitMasks;
143   }
144
145   public int getScanlineStride()
146   {
147     return scanlineStride;
148   }
149
150   public SampleModel createSubsetSampleModel(int[] bands)
151   {
152     // FIXME: Is this the right way to interpret bands?
153     
154     int numBands = bands.length;
155     
156     int[] bitMasks = new int[numBands];
157
158     for (int b=0; b<numBands; b++)
159       bitMasks[b] = this.bitMasks[bands[b]];
160
161     return new SinglePixelPackedSampleModel(dataType, width, height,
162                                             scanlineStride, bitMasks);
163   }
164
165   public Object getDataElements(int x, int y, Object obj,
166                                 DataBuffer data)
167   {
168     int offset = scanlineStride*y + x + data.getOffset();
169     
170     return Buffers.getData(data, offset, obj,
171                            0, // destination offset,
172                            1  // length
173                            );
174   }
175   
176   /**
177    * This is a more efficient implementation of the default implementation in the super
178    * class. 
179    * @param x The x-coordinate of the pixel rectangle to store in <code>obj</code>.
180    * @param y The y-coordinate of the pixel rectangle to store in <code>obj</code>.
181    * @param w The width of the pixel rectangle to store in <code>obj</code>.
182    * @param h The height of the pixel rectangle to store in <code>obj</code>.
183    * @param obj The primitive array to store the pixels into or null to force creation.
184    * @param data The DataBuffer that is the source of the pixel data.
185    * @return The primitive array containing the pixel data.
186    * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer)
187    */
188   public Object getDataElements(int x, int y, int w, int h, Object obj,
189                                                         DataBuffer data)
190   {
191     int size = w*h;
192     int dataSize = size;
193     Object pixelData = null;
194     switch (getTransferType())
195     {
196       case DataBuffer.TYPE_BYTE:
197         pixelData = ((DataBufferByte) data).getData();
198         if (obj == null) obj = new byte[dataSize];
199         break;
200        case DataBuffer.TYPE_USHORT:
201          pixelData = ((DataBufferUShort) data).getData();
202          if (obj == null) obj = new short[dataSize];
203          break;
204         case DataBuffer.TYPE_INT:
205           pixelData = ((DataBufferInt) data).getData();
206           if (obj == null) obj = new int[dataSize];
207           break;
208          default:
209              // Seems like the only sensible thing to do.
210            throw new ClassCastException();
211       }
212       if(x==0 && scanlineStride == w)
213       { 
214         // The full width need to be copied therefore we can copy in one shot.
215         System.arraycopy(pixelData, scanlineStride*y + data.getOffset(), obj, 0, size);
216       }
217       else
218       {  
219         // Since we do not need the full width we need to copy line by line.
220         int outOffset = 0;
221         int dataOffset = scanlineStride*y + x + data.getOffset();
222         for (int yy = y; yy<(y+h); yy++)
223         {
224           System.arraycopy(pixelData, dataOffset, obj, outOffset, w);
225           dataOffset += scanlineStride;
226           outOffset += w;
227         }
228       }
229     return obj;
230   }
231   
232
233   public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
234   {
235     int offset = scanlineStride*y + x;
236     if (iArray == null) iArray = new int[numBands];
237     int samples = data.getElem(offset);
238
239     for (int b=0; b<numBands; b++)
240       iArray[b] = (samples & bitMasks[b]) >>> bitOffsets[b];
241         
242     return iArray;
243   }
244
245   public int[] getPixels(int x, int y, int w, int h, int[] iArray,
246                          DataBuffer data)
247   {
248     int offset = scanlineStride*y + x;
249     if (iArray == null) iArray = new int[numBands*w*h];
250     int outOffset = 0;
251     for (y=0; y<h; y++)
252       {
253         int lineOffset = offset;
254         for (x=0; x<w; x++)
255           {
256             int samples = data.getElem(lineOffset++);
257             for (int b=0; b<numBands; b++)
258               iArray[outOffset++] = (samples & bitMasks[b]) >>> bitOffsets[b];
259           }
260         offset += scanlineStride;
261       }
262     return iArray;      
263   }
264
265   public int getSample(int x, int y, int b, DataBuffer data)
266   {
267     int offset = scanlineStride*y + x;
268     int samples = data.getElem(offset);
269     return (samples & bitMasks[b]) >>> bitOffsets[b];
270   }
271   
272   /**
273    * This method implements a more efficient way to set data elements than the default
274    * implementation of the super class. It sets the data elements line by line instead 
275    * of pixel by pixel.
276    * @param x The x-coordinate of the data elements in <code>obj</code>.
277    * @param y The y-coordinate of the data elements in <code>obj</code>.
278    * @param w The width of the data elements in <code>obj</code>.
279    * @param h The height of the data elements in <code>obj</code>.
280    * @param obj The primitive array containing the data elements to set.
281    * @param data The DataBuffer to store the data elements into.
282    * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer)
283    */
284   public void setDataElements(int x, int y, int w, int h,
285                                 Object obj, DataBuffer data)
286   {
287     
288     Object pixelData;
289     switch (getTransferType())
290     {
291       case DataBuffer.TYPE_BYTE:
292         pixelData = ((DataBufferByte) data).getData();
293         break;
294        case DataBuffer.TYPE_USHORT:
295          pixelData = ((DataBufferUShort) data).getData();
296          break;
297        case DataBuffer.TYPE_INT:
298          pixelData = ((DataBufferInt) data).getData();
299          break;
300        default:
301           // Seems like the only sensible thing to do.
302           throw new ClassCastException();
303     }
304     
305     int inOffset = 0;
306     int dataOffset = scanlineStride*y + x + data.getOffset();
307     for (int yy=y; yy<(y+h); yy++)
308     {
309       System.arraycopy(obj,inOffset,pixelData,dataOffset,w);
310       dataOffset += scanlineStride;
311       inOffset += w;
312     }
313   }
314   
315   
316   public void setDataElements(int x, int y, Object obj, DataBuffer data)
317   {
318     int offset = scanlineStride*y + x + data.getOffset();
319     
320     int transferType = getTransferType();
321     if (getTransferType() != data.getDataType())
322       {
323         throw new IllegalArgumentException("transfer type ("+
324                                            getTransferType()+"), "+
325                                            "does not match data "+
326                                            "buffer type (" +
327                                            data.getDataType() +
328                                            ").");
329       }
330
331     try
332       {
333         switch (transferType)
334           {
335           case DataBuffer.TYPE_BYTE:
336             {
337               DataBufferByte out = (DataBufferByte) data;
338               byte[] in = (byte[]) obj;
339               out.getData()[offset] = in[0];
340               return;
341             }
342           case DataBuffer.TYPE_USHORT:
343             {
344               DataBufferUShort out = (DataBufferUShort) data;
345               short[] in = (short[]) obj;
346               out.getData()[offset] = in[0];
347               return;
348             }
349           case DataBuffer.TYPE_INT:
350             {
351               DataBufferInt out = (DataBufferInt) data;
352               int[] in = (int[]) obj;
353               out.getData()[offset] = in[0];
354               return;
355             }
356             // FIXME: Fill in the other possible types.
357           default:
358             throw new InternalError();
359           }
360       }
361     catch (ArrayIndexOutOfBoundsException aioobe)
362       {
363         String msg = "While writing data elements" +
364           ", x="+x+", y="+y+
365           ", width="+width+", height="+height+
366           ", scanlineStride="+scanlineStride+
367           ", offset="+offset+
368           ", data.getSize()="+data.getSize()+
369           ", data.getOffset()="+data.getOffset()+
370           ": " +
371           aioobe;
372         throw new ArrayIndexOutOfBoundsException(msg);
373       }
374     }
375
376   public void setPixel(int x, int y, int[] iArray, DataBuffer data)
377   {
378     int offset = scanlineStride*y + x;
379     
380     int samples = 0;
381     for (int b=0; b<numBands; b++)
382       samples |= (iArray[b] << bitOffsets[b]) & bitMasks[b];
383
384     data.setElem(offset, samples);
385   }
386
387   /**
388    * This method implements a more efficient way to set pixels than the default
389    * implementation of the super class. It copies the pixel components directly
390    * from the input array instead of creating a intermediate buffer.
391    * @param x The x-coordinate of the pixel rectangle in <code>obj</code>.
392    * @param y The y-coordinate of the pixel rectangle in <code>obj</code>.
393    * @param w The width of the pixel rectangle in <code>obj</code>.
394    * @param h The height of the pixel rectangle in <code>obj</code>.
395    * @param iArray The primitive array containing the pixels to set.
396    * @param data The DataBuffer to store the pixels into.
397    * @see java.awt.image.SampleModel#setPixels(int, int, int, int, int[], java.awt.image.DataBuffer)
398    */
399   public void setPixels(int x, int y, int w, int h, int[] iArray,
400                                                 DataBuffer data)
401   {
402     int inOffset = 0;
403     int[] pixel = new int[numBands];
404     for (int yy=y; yy<(y+h); yy++)
405      {
406       int offset = scanlineStride*yy + x;
407       for (int xx=x; xx<(x+w); xx++)
408        { 
409         int samples = 0;
410         for (int b=0; b<numBands; b++)
411           samples |= (iArray[inOffset+b] << bitOffsets[b]) & bitMasks[b];
412         data.setElem(0, offset, samples);
413         inOffset += numBands;
414         offset += 1;
415       }
416     }
417   }
418   
419   
420   public void setSample(int x, int y, int b, int s, DataBuffer data)
421   {
422     int offset = scanlineStride*y + x;
423     int samples = data.getElem(offset);
424     int bitMask = bitMasks[b];
425     samples &= ~bitMask;
426     samples |= (s << bitOffsets[b]) & bitMask;
427     data.setElem(offset, samples);
428   }
429   
430   /**
431    * Creates a String with some information about this SampleModel.
432    * @return A String describing this SampleModel.
433    * @see java.lang.Object#toString()
434    */
435   public String toString()
436   {
437     StringBuffer result = new StringBuffer();
438     result.append(getClass().getName());
439     result.append("[");
440     result.append("scanlineStride=").append(scanlineStride);
441     for(int i=0; i < bitMasks.length; i+=1)
442     {
443       result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i]));
444     }
445     
446     result.append("]");
447     return result.toString();
448   }
449 }