OSDN Git Service

2004-11-30 Thomas Fitzsimmons <fitzsim@redhat.com>
[pf3gnuchains/gcc-fork.git] / libjava / java / awt / image / BandedSampleModel.java
1 /* Copyright (C) 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 /**
40  * MultiPixelPackedSampleModel provides a single band model that supports
41  * multiple pixels in a single unit.  Pixels have 2^n bits and 2^k pixels fit
42  * per data element.
43  *
44  * @author Jerry Quinn <jlquinn@optonline.net>
45  */
46 public final class BandedSampleModel extends ComponentSampleModel
47 {
48   private int[] bitMasks;
49   private int[] bitOffsets;
50   private int[] sampleSize;
51   private int dataBitOffset;
52   private int elemBits;
53   private int numberOfBits;
54   private int numElems;
55
56   public BandedSampleModel(int dataType, int w, int h, int numBands)
57   {
58     super(dataType, w, h, 1, w, new int[numBands]);
59   }
60
61   public BandedSampleModel(int dataType, int w, int h, int scanlineStride,
62                            int[] bankIndices, int[] bandOffsets)
63   {
64     super(dataType, w, h, 1, scanlineStride, bankIndices, bandOffsets);
65   }
66
67   public SampleModel createCompatibleSampleModel(int w, int h)
68   {
69     // NOTE: blackdown 1.4.1 sets all offsets to 0.  Sun's 1.4.2 docs
70     // disagree.
71
72     // Compress offsets so minimum is 0, others w*scanlineStride
73     int[] newoffsets = new int[bandOffsets.length];
74     int[] order = new int[bandOffsets.length];
75     for (int i=0; i < bandOffsets.length; i++)
76       order[i] = i;
77     // FIXME: This is N^2, but not a big issue, unless there's a lot of
78     // bands...
79     for (int i=0; i < bandOffsets.length; i++)
80       for (int j=i+1; j < bandOffsets.length; i++)
81         if (bankIndices[order[i]] > bankIndices[order[j]]
82             || (bankIndices[order[i]] == bankIndices[order[j]]
83                 && bandOffsets[order[i]] > bandOffsets[order[j]]))
84           {
85             int t = order[i]; order[i] = order[j]; order[j] = t;
86           }
87     int bank = 0;
88     int offset = 0;
89     for (int i=0; i < bandOffsets.length; i++)
90       {
91         if (bankIndices[order[i]] != bank)
92           {
93             bank = bankIndices[order[i]];
94             offset = 0;
95           }
96         newoffsets[order[i]] = offset;
97         offset += w * scanlineStride;
98       }
99     
100     return new BandedSampleModel(dataType, w, h, scanlineStride, bankIndices, newoffsets);
101   }
102
103
104   public SampleModel createSubsetSampleModel(int[] bands)
105   {
106     int[] newoff = new int[bands.length];
107     int[] newbanks = new int[bands.length];
108     for (int i=0; i < bands.length; i++)
109       {
110         int b = bands[i];
111         newoff[i] = bandOffsets[b];
112         newbanks[i] = bankIndices[b];
113       }
114
115     if (bands.length > bankIndices.length)
116       throw new
117         RasterFormatException("BandedSampleModel createSubsetSampleModel too"
118                               +" many bands");
119     
120     return new BandedSampleModel(dataType, width, height, scanlineStride,
121                                  newbanks, newoff);
122   }
123
124   /**
125    * Extract all samples of one pixel and return in an array of transfer type.
126    *
127    * Extracts the pixel at x, y from data and stores samples into the array
128    * obj.  If obj is null, a new array of getTransferType() is created.
129    *
130    * @param x The x-coordinate of the pixel rectangle to store in <code>obj</code>.
131    * @param y The y-coordinate of the pixel rectangle to store in <code>obj</code>.
132    * @param obj The primitive array to store the pixels into or null to force creation.
133    * @param data The DataBuffer that is the source of the pixel data.
134    * @return The primitive array containing the pixel data.
135    * @see java.awt.image.SampleModel#getDataElements(int, int, java.lang.Object, java.awt.image.DataBuffer)
136    */
137   public Object getDataElements(int x, int y, Object obj,
138                                 DataBuffer data)
139   {
140     int pixel = getSample(x, y, 0, data);
141     switch (getTransferType())
142     {
143     case DataBuffer.TYPE_BYTE:
144       {
145         byte[] b = (byte[])obj;
146         if (b == null) b = new byte[numBands];
147         for (int i=0; i < numBands; i++)
148           b[i] = (byte)getSample(x, y, i, data);
149         return b;
150       }
151     case DataBuffer.TYPE_SHORT:
152     case DataBuffer.TYPE_USHORT:
153       {
154         short[] b = (short[])obj;
155         if (b == null) b = new short[numBands];
156         for (int i=0; i < numBands; i++)
157           b[i] = (short)getSample(x, y, i, data);
158         return b;
159       }
160     case DataBuffer.TYPE_INT:
161       {
162         int[] b = (int[])obj;
163         if (b == null) b = new int[numBands];
164         for (int i=0; i < numBands; i++)
165           b[i] = getSample(x, y, i, data);
166         return b;
167       }
168     case DataBuffer.TYPE_FLOAT:
169       {
170         float[] b = (float[])obj;
171         if (b == null) b = new float[numBands];
172         for (int i=0; i < numBands; i++)
173           b[i] = getSampleFloat(x, y, i, data);
174         return b;
175       }
176     case DataBuffer.TYPE_DOUBLE:
177       {
178         double[] b = (double[])obj;
179         if (b == null) b = new double[numBands];
180         for (int i=0; i < numBands; i++)
181           b[i] = getSample(x, y, i, data);
182         return b;
183       }
184
185     default:
186       // Seems like the only sensible thing to do.
187       throw new ClassCastException();
188     }
189   }
190
191   public int[] getPixel(int x, int y, int[] iArray, DataBuffer data)
192   {
193     if (iArray == null) iArray = new int[numBands];
194     for (int i=0; i < numBands; i++)
195       iArray[i] = getSample(x, y, 0, data);
196         
197     return iArray;
198   }
199
200   /**
201    * Copy pixels from a region into an array.
202    *
203    * Copies the samples of the pixels in the rectangle starting at x, y that
204    * is w pixels wide and h scanlines high.  When there is more than one band,
205    * the samples stored in order before the next pixel.  This ordering isn't
206    * well specified in Sun's docs as of 1.4.2.
207    *
208    * If iArray is null, a new array is allocated, filled, and returned.
209    *
210    * @param x The x-coordinate of the pixel rectangle to store in
211    * <code>iArray</code>.
212    * @param y The y-coordinate of the pixel rectangle to store in
213    * <code>iArray</code>.
214    * @param w The width in pixels of the rectangle.
215    * @param h The height in pixels of the rectangle.
216    * @param iArray The int array to store the pixels into or null to force
217    * creation.
218    * @param data The DataBuffer that is the source of the pixel data.
219    * @return The primitive array containing the pixel data.
220    */
221   public int[] getPixels(int x, int y, int w, int h, int[] iArray,
222                          DataBuffer data)
223   {
224     if (iArray == null) iArray = new int[w*h*numBands];
225     int outOffset = 0;
226     for (y=0; y<h; y++)
227       {
228         for (x=0; x<w;)
229           {
230             for (int b=0; b < numBands; b++)
231               {
232                 int offset = bandOffsets[b] + y * scanlineStride + x;
233                 iArray[outOffset++] =
234                   data.getElem(bankIndices[b], offset);
235               }
236           }
237       }
238     return iArray;      
239   }
240
241   public int getSample(int x, int y, int b, DataBuffer data)
242   {
243     int offset = bandOffsets[b] + y * scanlineStride + x;
244     return data.getElem(bankIndices[b], offset);
245   }
246   
247   public float getSampleFloat(int x, int y, int b, DataBuffer data)
248   {
249     int offset = bandOffsets[b] + y * scanlineStride + x;
250     return data.getElemFloat(bankIndices[b], offset);
251   }
252   
253   public double getSampleDouble(int x, int y, int b, DataBuffer data)
254   {
255     int offset = bandOffsets[b] + y * scanlineStride + x;
256     return data.getElemDouble(bankIndices[b], offset);
257   }
258   
259   /**
260    * Copy one band's samples from a region into an array.
261    *
262    * Copies from one band the samples of the pixels in the rectangle starting
263    * at x, y that is w pixels wide and h scanlines high.
264    *
265    * If iArray is null, a new array is allocated, filled, and returned.
266    *
267    * @param x The x-coordinate of the pixel rectangle to store in
268    * <code>iArray</code>.
269    * @param y The y-coordinate of the pixel rectangle to store in
270    * <code>iArray</code>.
271    * @param w The width in pixels of the rectangle.
272    * @param h The height in pixels of the rectangle.
273    * @param b The band to retrieve.
274    * @param iArray The int array to store the pixels into or null to force
275    * creation.
276    * @param data The DataBuffer that is the source of the pixel data.
277    * @return The primitive array containing the pixel data.
278    */
279   public int[] getSamples(int x, int y, int w, int h, int b, int[] iArray,
280                           DataBuffer data)
281   {
282     if (iArray == null) iArray = new int[w*h];
283     int outOffset = 0;
284     for (y=0; y<h; y++)
285       {
286         for (x=0; x<w;)
287           {
288             int offset = bandOffsets[b] + y * scanlineStride + x;
289             iArray[outOffset++] =
290               data.getElem(bankIndices[b], offset);
291           }
292       }
293     return iArray;      
294   }
295
296
297   /**
298    * Set the pixel at x, y to the value in the first element of the primitive
299    * array obj.
300    *
301    * @param x The x-coordinate of the data elements in <code>obj</code>.
302    * @param y The y-coordinate of the data elements in <code>obj</code>.
303    * @param obj The primitive array containing the data elements to set.
304    * @param data The DataBuffer to store the data elements into.
305    * @see java.awt.image.SampleModel#setDataElements(int, int, int, int, java.lang.Object, java.awt.image.DataBuffer)
306    */
307   public void setDataElements(int x, int y, Object obj, DataBuffer data)
308   {
309     int transferType = getTransferType();
310     if (getTransferType() != data.getDataType())
311       {
312         throw new IllegalArgumentException("transfer type ("+
313                                            getTransferType()+"), "+
314                                            "does not match data "+
315                                            "buffer type (" +
316                                            data.getDataType() +
317                                            ").");
318       }
319
320     int offset = y * scanlineStride + x;
321     
322     try
323       {
324         switch (transferType)
325           {
326           case DataBuffer.TYPE_BYTE:
327             {
328               DataBufferByte out = (DataBufferByte) data;
329               byte[] in = (byte[]) obj;
330               for (int i=0; i < numBands; i++)
331                 out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[0];
332               return;
333             }
334           case DataBuffer.TYPE_SHORT:
335             {
336               DataBufferShort out = (DataBufferShort) data;
337               short[] in = (short[]) obj;
338               for (int i=0; i < numBands; i++)
339                 out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[0];
340               return;
341             }
342           case DataBuffer.TYPE_USHORT:
343             {
344               DataBufferUShort out = (DataBufferUShort) data;
345               short[] in = (short[]) obj;
346               for (int i=0; i < numBands; i++)
347                 out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[0];
348               return;
349             }
350           case DataBuffer.TYPE_INT:
351             {
352               DataBufferInt out = (DataBufferInt) data;
353               int[] in = (int[]) obj;
354               for (int i=0; i < numBands; i++)
355                 out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[0];
356               return;
357             }
358           case DataBuffer.TYPE_FLOAT:
359             {
360               DataBufferFloat out = (DataBufferFloat) data;
361               float[] in = (float[]) obj;
362               for (int i=0; i < numBands; i++)
363                 out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[0];
364               return;
365             }
366           case DataBuffer.TYPE_DOUBLE:
367             {
368               DataBufferDouble out = (DataBufferDouble) data;
369               double[] in = (double[]) obj;
370               for (int i=0; i < numBands; i++)
371                 out.getData(bankIndices[i])[offset + bandOffsets[i]] = in[0];
372               return;
373             }
374           default:
375             throw new ClassCastException("Unsupported data type");
376           }
377       }
378     catch (ArrayIndexOutOfBoundsException aioobe)
379       {
380         String msg = "While writing data elements" +
381           ", x="+x+", y="+y+
382           ", width="+width+", height="+height+
383           ", scanlineStride="+scanlineStride+
384           ", offset="+offset+
385           ", data.getSize()="+data.getSize()+
386           ", data.getOffset()="+data.getOffset()+
387           ": " +
388           aioobe;
389         throw new ArrayIndexOutOfBoundsException(msg);
390       }
391     }
392
393   public void setPixel(int x, int y, int[] iArray, DataBuffer data)
394   {
395     for (int b=0; b < numBands; b++)
396       data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x,
397                    iArray[b]);
398   }
399
400   public void setPixels(int x, int y, int w, int h, int[] iArray,
401                         DataBuffer data)
402   {
403     int inOffset = 0;
404     for (int hh = 0; hh < h; hh++)
405       {
406         for (int ww = 0; ww < w; ww++)
407           {
408             int offset = y * scanlineStride + (x + ww);
409             for (int b=0; b < numBands; b++)
410               data.setElem(bankIndices[b], bandOffsets[b] + offset,
411                            iArray[inOffset++]);
412           }
413         y++;
414       }
415   }
416
417   public void setSample(int x, int y, int b, int s, DataBuffer data)
418   {
419     data.setElem(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s);
420   }
421   
422   public void setSample(int x, int y, int b, float s, DataBuffer data)
423   {
424     data.setElemFloat(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s);
425   }
426   
427   public void setSample(int x, int y, int b, double s, DataBuffer data)
428   {
429     data.setElemDouble(bankIndices[b], bandOffsets[b] + y * scanlineStride + x, s);
430   }
431   
432   public void setSamples(int x, int y, int w, int h, int b, int[] iArray,
433                          DataBuffer data)
434   {
435     int inOffset = 0;
436
437     switch (getTransferType())
438       {
439       case DataBuffer.TYPE_BYTE:
440         {
441           DataBufferByte out = (DataBufferByte) data;
442           byte[] bank = out.getData(bankIndices[b]);
443           for (int hh = 0; hh < h; hh++)
444             {
445               for (int ww = 0; ww < w; ww++)
446                 {
447                   int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
448                   bank[offset] = (byte)iArray[inOffset++];
449                 }
450               y++;
451             }
452           return;
453         }
454       case DataBuffer.TYPE_SHORT:
455         {
456           DataBufferShort out = (DataBufferShort) data;
457           short[] bank = out.getData(bankIndices[b]);
458           for (int hh = 0; hh < h; hh++)
459             {
460               for (int ww = 0; ww < w; ww++)
461                 {
462                   int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
463                   bank[offset] = (short)iArray[inOffset++];
464                 }
465               y++;
466             }
467           return;
468         }
469       case DataBuffer.TYPE_USHORT:
470         {
471           DataBufferShort out = (DataBufferShort) data;
472           short[] bank = out.getData(bankIndices[b]);
473           for (int hh = 0; hh < h; hh++)
474             {
475               for (int ww = 0; ww < w; ww++)
476                 {
477                   int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
478                   bank[offset] = (short)iArray[inOffset++];
479                 }
480               y++;
481             }
482           return;
483         }
484       case DataBuffer.TYPE_INT:
485         {
486           DataBufferInt out = (DataBufferInt) data;
487           int[] bank = out.getData(bankIndices[b]);
488           for (int hh = 0; hh < h; hh++)
489             {
490               for (int ww = 0; ww < w; ww++)
491                 {
492                   int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
493                   bank[offset] = iArray[inOffset++];
494                 }
495               y++;
496             }
497           return;
498         }
499       case DataBuffer.TYPE_FLOAT:
500       case DataBuffer.TYPE_DOUBLE:
501         break;
502       default:
503         throw new ClassCastException("Unsupported data type");
504       }
505
506     // Default implementation probably slower for float and double
507     for (int hh = 0; hh < h; hh++)
508       {
509         for (int ww = 0; ww < w; ww++)
510           {
511             int offset = bandOffsets[b] + y * scanlineStride + (x + ww);
512             data.setElem(bankIndices[b], offset, iArray[inOffset++]);
513           }
514         y++;
515       }
516   }
517
518   /**
519    * Creates a String with some information about this SampleModel.
520    * @return A String describing this SampleModel.
521    * @see java.lang.Object#toString()
522    */
523   public String toString()
524   {
525     StringBuffer result = new StringBuffer();
526     result.append(getClass().getName());
527     result.append("[");
528     result.append("scanlineStride=").append(scanlineStride);
529     for(int i=0; i < bitMasks.length; i+=1)
530     {
531       result.append(", mask[").append(i).append("]=0x").append(Integer.toHexString(bitMasks[i]));
532     }
533     
534     result.append("]");
535     return result.toString();
536   }
537 }