View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, Oracle and/or its affiliates. All rights reserved.
3    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4    *
5    * This code is free software; you can redistribute it and/or modify it
6    * under the terms of the GNU General Public License version 2 only, as
7    * published by the Free Software Foundation.  Oracle designates this
8    * particular file as subject to the "Classpath" exception as provided
9    * by Oracle in the LICENSE file that accompanied this code.
10   *
11   * This code is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13   * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
14   * version 2 for more details (a copy is included in the LICENSE file that
15   * accompanied this code).
16   *
17   * You should have received a copy of the GNU General Public License version
18   * 2 along with this work; if not, write to the Free Software Foundation,
19   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20   *
21   * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22   * or visit www.oracle.com if you need additional information or have any
23   * questions.
24   */
25  
26  package sun.awt.image;
27  import java.awt.image.Raster;
28  import java.awt.image.WritableRaster;
29  import java.awt.image.RasterFormatException;
30  import java.awt.image.SampleModel;
31  import java.awt.image.ComponentSampleModel;
32  import java.awt.image.SinglePixelPackedSampleModel;
33  import java.awt.image.DataBuffer;
34  import java.awt.image.DataBufferUShort;
35  import java.awt.Rectangle;
36  import java.awt.Point;
37  
38  /**
39   * This class defines a Raster with pixels consisting of one or more 16-bit
40   * data elements stored in close proximity to each other in a short integer
41   * array.  The bit precision per data element is that
42   * of the data type (that is, the bit precision for this Raster is 16).
43   * There is only one pixel stride and one scanline stride for all
44   * bands.  This type of Raster can be used with a
45   * ComponentColorModel if there are multiple bands, or a
46   * IndexColorModel if there is only one band.
47   * <p>
48   * For example, 5-6-5 RGB image data can be represented by a
49   * ShortComponentRaster using a SinglePixelPackedSampleModel and
50   * a ComponentColorModel.
51   *
52   *
53   */
54  public class ShortComponentRaster extends SunWritableRaster {
55  
56      /** private band offset for use by native code */
57      protected int bandOffset;
58  
59      /** Data offsets for each band of image data. */
60      protected int[]         dataOffsets;
61  
62      /** Scanline stride of the image data contained in this Raster. */
63      protected int           scanlineStride;
64  
65      /** Pixel stride of the image data contained in this Raster. */
66      protected int           pixelStride;
67  
68      /** The image data array. */
69      protected short[]       data;
70  
71      int type;
72  
73      /** A cached copy of minX + width for use in bounds checks. */
74      private int maxX;
75  
76      /** A cached copy of minY + height for use in bounds checks. */
77      private int maxY;
78  
79      static private native void initIDs();
80      static {
81          /* ensure that the necessary native libraries are loaded */
82          NativeLibLoader.loadLibraries();
83          initIDs();
84      }
85  
86      /**
87       *  Constructs a ShortComponentRaster with the given SampleModel.
88       *  The Raster's upper left corner is origin and it is the same
89       *  size as the SampleModel.  A DataBuffer large enough to describe the
90       *  Raster is automatically created.  SampleModel must be of type
91       *  ComponentSampleModel or SinglePixelPackedSampleModel.
92       *  @param sampleModel     The SampleModel that specifies the layout.
93       *  @param origin          The Point that specified the origin.
94       */
95      public ShortComponentRaster(SampleModel sampleModel, Point origin) {
96          this(sampleModel,
97               sampleModel.createDataBuffer(),
98               new Rectangle(origin.x,
99                             origin.y,
100                            sampleModel.getWidth(),
101                            sampleModel.getHeight()),
102              origin,
103              null);
104     }
105 
106     /**
107      * Constructs a ShortComponentRaster with the given SampleModel
108      * and DataBuffer.  The Raster's upper left corner is origin and
109      * it is the same sizes the SampleModel.  The DataBuffer is not
110      * initialized and must be a DataBufferUShort compatible with SampleModel.
111      * SampleModel must be of type ComponentSampleModel or
112      * SinglePixelPackedSampleModel.
113      * @param sampleModel     The SampleModel that specifies the layout.
114      * @param dataBuffer      The DataBufferUShort that contains the image data.
115      * @param origin          The Point that specifies the origin.
116      */
117     public ShortComponentRaster(SampleModel sampleModel,
118                                    DataBuffer dataBuffer,
119                                    Point origin) {
120         this(sampleModel,
121              dataBuffer,
122              new Rectangle(origin.x,
123                            origin.y,
124                            sampleModel.getWidth(),
125                            sampleModel.getHeight()),
126              origin,
127              null);
128     }
129 
130     /**
131      * Constructs a ShortComponentRaster with the given SampleModel,
132      * DataBuffer, and parent.  DataBuffer must be a DataBufferUShort and
133      * SampleModel must be of type ComponentSampleModel or
134      * SinglePixelPackedSampleModel.  When translated into the base Raster's
135      * coordinate system, aRegion must be contained by the base Raster.
136      * Origin is the coodinate in the new Raster's coordinate system of
137      * the origin of the base Raster.  (The base Raster is the Raster's
138      * ancestor which has no parent.)
139      *
140      * Note that this constructor should generally be called by other
141      * constructors or create methods, it should not be used directly.
142      * @param sampleModel     The SampleModel that specifies the layout.
143      * @param dataBuffer      The DataBufferUShort that contains the image data.
144      * @param aRegion         The Rectangle that specifies the image area.
145      * @param origin          The Point that specifies the origin.
146      * @param parent          The parent (if any) of this raster.
147      */
148     public ShortComponentRaster(SampleModel sampleModel,
149                                    DataBuffer dataBuffer,
150                                    Rectangle aRegion,
151                                    Point origin,
152                                    ShortComponentRaster parent) {
153 
154         super(sampleModel, dataBuffer, aRegion, origin, parent);
155         this.maxX = minX + width;
156         this.maxY = minY + height;
157 
158         if(!(dataBuffer instanceof DataBufferUShort)) {
159             throw new RasterFormatException("ShortComponentRasters must have "+
160                                             "short DataBuffers");
161         }
162 
163         DataBufferUShort dbus = (DataBufferUShort)dataBuffer;
164         this.data = stealData(dbus, 0);
165         if (dbus.getNumBanks() != 1) {
166             throw new
167                 RasterFormatException("DataBuffer for ShortComponentRasters"+
168                                       " must only have 1 bank.");
169         }
170         int dbOffset = dbus.getOffset();
171 
172         if (sampleModel instanceof ComponentSampleModel) {
173             ComponentSampleModel csm = (ComponentSampleModel)sampleModel;
174             this.type = IntegerComponentRaster.TYPE_USHORT_SAMPLES;
175             this.scanlineStride = csm.getScanlineStride();
176             this.pixelStride = csm.getPixelStride();
177             this.dataOffsets = csm.getBandOffsets();
178             int xOffset = aRegion.x - origin.x;
179             int yOffset = aRegion.y - origin.y;
180             for (int i = 0; i < getNumDataElements(); i++) {
181                 dataOffsets[i] += dbOffset +
182                     xOffset*pixelStride+yOffset*scanlineStride;
183             }
184         } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
185             SinglePixelPackedSampleModel sppsm =
186                     (SinglePixelPackedSampleModel)sampleModel;
187             this.type = IntegerComponentRaster.TYPE_USHORT_PACKED_SAMPLES;
188             this.scanlineStride = sppsm.getScanlineStride();
189             this.pixelStride    = 1;
190             this.dataOffsets = new int[1];
191             this.dataOffsets[0] = dbOffset;
192             int xOffset = aRegion.x - origin.x;
193             int yOffset = aRegion.y - origin.y;
194             dataOffsets[0] += xOffset+yOffset*scanlineStride;
195         } else {
196             throw new RasterFormatException("ShortComponentRasters must have"+
197                 "ComponentSampleModel or SinglePixelPackedSampleModel");
198         }
199         this.bandOffset = this.dataOffsets[0];
200 
201         verify();
202     }
203 
204     /**
205      * Returns a copy of the data offsets array. For each band the data offset
206      * is the index into the band's data array, of the first sample of the
207      * band.
208      */
209     public int[] getDataOffsets() {
210         return (int[]) dataOffsets.clone();
211     }
212 
213     /**
214      * Returns the data offset for the specified band.  The data offset
215      * is the index into the data array in which the first sample
216      * of the first scanline is stored.
217      * @param band  The band whose offset is returned.
218      */
219     public int getDataOffset(int band) {
220         return dataOffsets[band];
221     }
222 
223     /**
224      * Returns the scanline stride -- the number of data array elements between
225      * a given sample and the same sample in the same column of the next row.
226      */
227     public int getScanlineStride() {
228         return scanlineStride;
229     }
230 
231     /**
232      * Returns pixel stride -- the number of data array elements  between two
233      * samples for the same band on the same scanline.
234      */
235     public int getPixelStride() {
236         return pixelStride;
237     }
238 
239     /**
240      * Returns a reference to the data array.
241      */
242     public short[] getDataStorage() {
243         return data;
244     }
245 
246     /**
247      * Returns the data elements for all bands at the specified
248      * location.
249      * An ArrayIndexOutOfBounds exception will be thrown at runtime
250      * if the pixel coordinate is out of bounds.
251      * A ClassCastException will be thrown if the input object is non null
252      * and references anything other than an array of transferType.
253      * @param x        The X coordinate of the pixel location.
254      * @param y        The Y coordinate of the pixel location.
255      * @param outData  An object reference to an array of type defined by
256      *                 getTransferType() and length getNumDataElements().
257      *                 If null an array of appropriate type and size will be
258      *                 allocated.
259      * @return         An object reference to an array of type defined by
260      *                 getTransferType() with the request pixel data.
261      */
262     public Object getDataElements(int x, int y, Object obj) {
263         if ((x < this.minX) || (y < this.minY) ||
264             (x >= this.maxX) || (y >= this.maxY)) {
265             throw new ArrayIndexOutOfBoundsException
266                 ("Coordinate out of bounds!");
267         }
268         short outData[];
269         if (obj == null) {
270             outData = new short[numDataElements];
271         } else {
272             outData = (short[])obj;
273         }
274         int off = (y-minY)*scanlineStride +
275                   (x-minX)*pixelStride;
276 
277         for (int band = 0; band < numDataElements; band++) {
278             outData[band] = data[dataOffsets[band] + off];
279         }
280 
281         return outData;
282     }
283 
284     /**
285      * Returns an array  of data elements from the specified rectangular
286      * region.
287      * An ArrayIndexOutOfBounds exception will be thrown at runtime
288      * if the pixel coordinates are out of bounds.
289      * A ClassCastException will be thrown if the input object is non null
290      * and references anything other than an array of transferType.
291      * <pre>
292      *       short[] bandData = (short[])Raster.getDataElements(x, y, w, h, null);
293      *       int numDataElements = Raster.getBands();
294      *       short[] pixel = new short[numDataElements];
295      *       // To find the data element at location (x2, y2)
296      *       System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
297      *                        pixel, 0, numDataElements);
298      * </pre>
299      * @param x        The X coordinate of the upper left pixel location.
300      * @param y        The Y coordinate of the upper left pixel location.
301      * @param width    Width of the pixel rectangle.
302      * @param height   Height of the pixel rectangle.
303      * @param outData  An object reference to an array of type defined by
304      *                 getTransferType() and length w*h*getNumDataElements().
305      *                 If null an array of appropriate type and size will be
306      *                 allocated.
307      * @return         An object reference to an array of type defined by
308      *                 getTransferType() with the request pixel data.
309      */
310     public Object getDataElements(int x, int y, int w, int h, Object obj) {
311         if ((x < this.minX) || (y < this.minY) ||
312             (x + w > this.maxX) || (y + h > this.maxY)) {
313             throw new ArrayIndexOutOfBoundsException
314                 ("Coordinate out of bounds!");
315         }
316         short outData[];
317         if (obj == null) {
318             outData = new short[w*h*numDataElements];
319         } else {
320             outData = (short[])obj;
321         }
322         int yoff = (y-minY)*scanlineStride +
323                    (x-minX)*pixelStride;
324 
325         int xoff;
326         int off = 0;
327         int xstart;
328         int ystart;
329 
330         for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
331             xoff = yoff;
332             for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
333                 for (int c = 0; c < numDataElements; c++) {
334                     outData[off++] = data[dataOffsets[c] + xoff];
335                 }
336             }
337         }
338 
339         return outData;
340     }
341 
342     /**
343      * Returns a short integer array of data elements from the
344      * specified rectangular region.
345      * An ArrayIndexOutOfBounds exception will be thrown at runtime
346      * if the pixel coordinates are out of bounds.
347      * <pre>
348      *       short[] bandData = Raster.getShortData(x, y, w, h, null);
349      *       // To find the data element at location (x2, y2)
350      *       short dataElenent = bandData[((y2-y)*w + (x2-x))];
351      * </pre>
352      * @param x        The X coordinate of the upper left pixel location.
353      * @param y        The Y coordinate of the upper left pixel location.
354      * @param width    Width of the sample rectangle.
355      * @param height   Height of the sample rectangle.
356      * @param band     The band to return.
357      * @param outData  If non-null, data elements for all bands
358      *                 at the specified location are returned in this array.
359      * @return         Data array with data elements for all bands.
360      */
361     public short[] getShortData(int x, int y, int w, int h,
362                                int band, short[] outData) {
363         // Bounds check for 'band' will be performed automatically
364         if ((x < this.minX) || (y < this.minY) ||
365             (x + w > this.maxX) || (y + h > this.maxY)) {
366             throw new ArrayIndexOutOfBoundsException
367                 ("Coordinate out of bounds!");
368         }
369         if (outData == null) {
370             outData = new short[numDataElements*w*h];
371         }
372         int yoff =  (y-minY)*scanlineStride +
373                     (x-minX)*pixelStride+ dataOffsets[band];
374         int xoff;
375         int off = 0;
376         int xstart;
377         int ystart;
378 
379         if (pixelStride == 1) {
380             if (scanlineStride == w) {
381                 System.arraycopy(data, yoff, outData, 0, w*h);
382             }
383             else {
384                 for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
385                     System.arraycopy(data, yoff, outData, off, w);
386                     off += w;
387                 }
388             }
389         }
390         else {
391             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
392                 xoff = yoff;
393                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
394                     outData[off++] = data[xoff];
395                 }
396             }
397         }
398 
399         return outData;
400     }
401 
402     /**
403      * Returns a short integer array  of data elements from the
404      * specified rectangular region.
405      * An ArrayIndexOutOfBounds exception will be thrown at runtime
406      * if the pixel coordinates are out of bounds.
407      * <pre>
408      *       short[] bandData = Raster.getShortData(x, y, w, h, null);
409      *       int numDataElements = Raster.getNumBands();
410      *       short[] pixel = new short[numDataElements];
411      *       // To find the data element at location (x2, y2)
412      *       System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
413      *                        pixel, 0, numDataElements);
414      * </pre>
415      * @param x        The X coordinate of the upper left pixel location.
416      * @param y        The Y coordinate of the upper left pixel location.
417      * @param width    Width of the pixel rectangle.
418      * @param height   Height of the pixel rectangle.
419      * @param outData  If non-null, data elements for all bands
420      *                 at the specified location are returned in this array.
421      * @return         Data array with data elements for all bands.
422      */
423     public short[] getShortData(int x, int y, int w, int h, short[] outData) {
424         if ((x < this.minX) || (y < this.minY) ||
425             (x + w > this.maxX) || (y + h > this.maxY)) {
426             throw new ArrayIndexOutOfBoundsException
427                 ("Coordinate out of bounds!");
428         }
429         if (outData == null) {
430             outData = new short[numDataElements*w*h];
431         }
432         int yoff = (y-minY)*scanlineStride +
433                    (x-minX)*pixelStride;
434         int xoff;
435         int off = 0;
436         int xstart;
437         int ystart;
438 
439         for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
440             xoff = yoff;
441             for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
442                 for (int c = 0; c < numDataElements; c++) {
443                     outData[off++] = data[dataOffsets[c] + xoff];
444                 }
445             }
446         }
447 
448         return outData;
449     }
450 
451     /**
452      * Stores the data elements for all bands at the specified location.
453      * An ArrayIndexOutOfBounds exception will be thrown at runtime
454      * if the pixel coordinate is out of bounds.
455      * A ClassCastException will be thrown if the input object is non null
456      * and references anything other than an array of transferType.
457      * @param x        The X coordinate of the pixel location.
458      * @param y        The Y coordinate of the pixel location.
459      * @param inData   An object reference to an array of type defined by
460      *                 getTransferType() and length getNumDataElements()
461      *                 containing the pixel data to place at x,y.
462      */
463     public void setDataElements(int x, int y, Object obj) {
464         if ((x < this.minX) || (y < this.minY) ||
465             (x >= this.maxX) || (y >= this.maxY)) {
466             throw new ArrayIndexOutOfBoundsException
467                 ("Coordinate out of bounds!");
468         }
469         short inData[] = (short[])obj;
470         int off = (y-minY)*scanlineStride +
471                   (x-minX)*pixelStride;
472         for (int i = 0; i < numDataElements; i++) {
473             data[dataOffsets[i] + off] = (short) inData[i];
474         }
475 
476         markDirty();
477     }
478 
479     /**
480      * Stores the Raster data at the specified location.
481      * An ArrayIndexOutOfBounds exception will be thrown at runtime
482      * if the pixel coordinates are out of bounds.
483      * @param x          The X coordinate of the pixel location.
484      * @param y          The Y coordinate of the pixel location.
485      * @param inRaster   Raster of data to place at x,y location.
486      */
487     public void setDataElements(int x, int y, Raster inRaster) {
488         int dstOffX = x + inRaster.getMinX();
489         int dstOffY = y + inRaster.getMinY();
490         int width  = inRaster.getWidth();
491         int height = inRaster.getHeight();
492         if ((dstOffX < this.minX) || (dstOffY < this.minY) ||
493             (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) {
494             throw new ArrayIndexOutOfBoundsException
495                 ("Coordinate out of bounds!");
496         }
497 
498         setDataElements(dstOffX, dstOffY, width, height, inRaster);
499     }
500 
501     /**
502      * Stores the Raster data at the specified location.
503      * @param dstX The absolute X coordinate of the destination pixel
504      * that will receive a copy of the upper-left pixel of the
505      * inRaster
506      * @param dstY The absolute Y coordinate of the destination pixel
507      * that will receive a copy of the upper-left pixel of the
508      * inRaster
509      * @param width      The number of pixels to store horizontally
510      * @param height     The number of pixels to store vertically
511      * @param inRaster   Raster of data to place at x,y location.
512      */
513     private void setDataElements(int dstX, int dstY,
514                                  int width, int height,
515                                  Raster inRaster) {
516         // Assume bounds checking has been performed previously
517         if (width <= 0 || height <= 0) {
518             return;
519         }
520 
521         // Write inRaster (minX, minY) to (dstX, dstY)
522 
523         int srcOffX = inRaster.getMinX();
524         int srcOffY = inRaster.getMinY();
525         Object tdata = null;
526 
527 //      // REMIND: Do something faster!
528 //      if (inRaster instanceof ShortComponentRaster) {
529 //      }
530 
531         for (int startY=0; startY < height; startY++) {
532             // Grab one scanline at a time
533             tdata = inRaster.getDataElements(srcOffX, srcOffY+startY,
534                                              width, 1, tdata);
535             setDataElements(dstX, dstY + startY, width, 1, tdata);
536         }
537     }
538 
539     /**
540      * Stores an array of data elements into the specified rectangular
541      * region.
542      * An ArrayIndexOutOfBounds exception will be thrown at runtime
543      * if the pixel coordinates are out of bounds.
544      * A ClassCastException will be thrown if the input object is non null
545      * and references anything other than an array of transferType.
546      * The data elements in the
547      * data array are assumed to be packed.  That is, a data element
548      * for the nth band at location (x2, y2) would be found at:
549      * <pre>
550      *      inData[((y2-y)*w + (x2-x))*numDataElements + n]
551      * </pre>
552      * @param x        The X coordinate of the upper left pixel location.
553      * @param y        The Y coordinate of the upper left pixel location.
554      * @param w        Width of the pixel rectangle.
555      * @param h        Height of the pixel rectangle.
556      * @param inData   An object reference to an array of type defined by
557      *                 getTransferType() and length w*h*getNumDataElements()
558      *                 containing the pixel data to place between x,y and
559      *                 x+h, y+h.
560      */
561     public void setDataElements(int x, int y, int w, int h, Object obj) {
562         if ((x < this.minX) || (y < this.minY) ||
563             (x + w > this.maxX) || (y + h > this.maxY)) {
564             throw new ArrayIndexOutOfBoundsException
565                 ("Coordinate out of bounds!");
566         }
567         short inData[] = (short[])obj;
568         int yoff = (y-minY)*scanlineStride +
569                    (x-minX)*pixelStride;
570         int xoff;
571         int off = 0;
572         int xstart;
573         int ystart;
574 
575         for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
576             xoff = yoff;
577             for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
578                 for (int c = 0; c < numDataElements; c++) {
579                     data[dataOffsets[c] + xoff] = (short) inData[off++];
580                 }
581             }
582         }
583 
584         markDirty();
585     }
586 
587     /**
588      * Stores a short integer array of data elements into the
589      * specified rectangular region.
590      * An ArrayIndexOutOfBounds exception will be thrown at runtime
591      * if the pixel coordinates are out of bounds.
592      * The data elements in the
593      * data array are assumed to be packed.  That is, a data element
594      * at location (x2, y2) would be found at:
595      * <pre>
596      *      inData[((y2-y)*w + (x2-x))]
597      * </pre>
598      * @param x        The X coordinate of the upper left pixel location.
599      * @param y        The Y coordinate of the upper left pixel location.
600      * @param w        Width of the pixel rectangle.
601      * @param h        Height of the pixel rectangle.
602      * @param band     The band to set.
603      * @param inData   The data elements to be stored.
604      */
605     public void putShortData(int x, int y, int w, int h,
606                              int band, short[] inData) {
607         // Bounds check for 'band' will be performed automatically
608         if ((x < this.minX) || (y < this.minY) ||
609             (x + w > this.maxX) || (y + h > this.maxY)) {
610             throw new ArrayIndexOutOfBoundsException
611                 ("Coordinate out of bounds!");
612         }
613         int yoff =  (y-minY)*scanlineStride +
614                     (x-minX)*pixelStride + dataOffsets[band];
615         int xoff;
616         int off = 0;
617         int xstart;
618         int ystart;
619 
620         if (pixelStride == 1) {
621             if (scanlineStride == w) {
622                 System.arraycopy(inData, 0, data, yoff, w*h);
623             }
624             else {
625                 for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
626                     System.arraycopy(inData, off, data, yoff, w);
627                     off += w;
628                 }
629             }
630         }
631         else {
632             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
633                 xoff = yoff;
634                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
635                     data[xoff] = inData[off++];
636                 }
637             }
638         }
639 
640         markDirty();
641     }
642 
643     /**
644      * Stores a short integer array of data elements into the
645      * specified rectangular region.
646      * An ArrayIndexOutOfBounds exception will be thrown at runtime
647      * if the pixel coordinates are out of bounds.
648      * The data elements in the
649      * data array are assumed to be packed.  That is, a data element
650      * for the nth band at location (x2, y2) would be found at:
651      * <pre>
652      *      inData[((y2-y)*w + (x2-x))*numDataElements + n]
653      * </pre>
654      * @param x        The X coordinate of the upper left pixel location.
655      * @param y        The Y coordinate of the upper left pixel location.
656      * @param w        Width of the pixel rectangle.
657      * @param h        Height of the pixel rectangle.
658      * @param inData   The data elements to be stored.
659      */
660     public void putShortData(int x, int y, int w, int h, short[] inData) {
661         if ((x < this.minX) || (y < this.minY) ||
662             (x + w > this.maxX) || (y + h > this.maxY)) {
663             throw new ArrayIndexOutOfBoundsException
664                 ("Coordinate out of bounds!");
665         }
666         int yoff = (y-minY)*scanlineStride +
667                    (x-minX)*pixelStride;
668         int xoff;
669         int off = 0;
670         int xstart;
671         int ystart;
672 
673         for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
674             xoff = yoff;
675             for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
676                 for (int c = 0; c < numDataElements; c++) {
677                     data[dataOffsets[c] + xoff] = inData[off++];
678                 }
679             }
680         }
681 
682         markDirty();
683     }
684 
685     /**
686      * Creates a subraster given a region of the raster.  The x and y
687      * coordinates specify the horizontal and vertical offsets
688      * from the upper-left corner of this raster to the upper-left corner
689      * of the subraster.  A subset of the bands of the parent Raster may
690      * be specified.  If this is null, then all the bands are present in the
691      * subRaster. A translation to the subRaster may also be specified.
692      * Note that the subraster will reference the same
693      * band objects as the parent raster, but using different offsets.
694      * @param x               X offset.
695      * @param y               Y offset.
696      * @param width           Width (in pixels) of the subraster.
697      * @param height          Height (in pixels) of the subraster.
698      * @param x0              Translated X origin of the subraster.
699      * @param y0              Translated Y origin of the subraster.
700      * @param bandList        Array of band indices.
701      * @exception RasterFormatException
702      *            if the specified bounding box is outside of the parent raster.
703      */
704     public Raster createChild (int x, int y,
705                                int width, int height,
706                                int x0, int y0, int[] bandList) {
707         WritableRaster newRaster = createWritableChild(x, y,
708                                                        width, height,
709                                                        x0, y0,
710                                                        bandList);
711         return (Raster) newRaster;
712     }
713 
714     /**
715      * Creates a Writable subRaster given a region of the Raster. The x and y
716      * coordinates specify the horizontal and vertical offsets
717      * from the upper-left corner of this Raster to the upper-left corner
718      * of the subRaster.  A subset of the bands of the parent Raster may
719      * be specified.  If this is null, then all the bands are present in the
720      * subRaster. A translation to the subRaster may also be specified.
721      * Note that the subRaster will reference the same
722      * DataBuffers as the parent Raster, but using different offsets.
723      * @param x               X offset.
724      * @param y               Y offset.
725      * @param width           Width (in pixels) of the subraster.
726      * @param height          Height (in pixels) of the subraster.
727      * @param x0              Translated X origin of the subraster.
728      * @param y0              Translated Y origin of the subraster.
729      * @param bandList        Array of band indices.
730      * @exception RasterFormatException
731      *            if the specified bounding box is outside of the parent Raster.
732      */
733     public WritableRaster createWritableChild(int x, int y,
734                                               int width, int height,
735                                               int x0, int y0,
736                                               int[] bandList) {
737         if (x < this.minX) {
738             throw new RasterFormatException("x lies outside the raster");
739         }
740         if (y < this.minY) {
741             throw new RasterFormatException("y lies outside the raster");
742         }
743         if ((x+width < x) || (x+width > this.minX + this.width)) {
744             throw new RasterFormatException("(x + width) is outside of Raster");
745         }
746         if ((y+height < y) || (y+height > this.minY + this.height)) {
747             throw new RasterFormatException("(y + height) is outside of Raster");
748         }
749 
750         SampleModel sm;
751 
752         if (bandList != null)
753             sm = sampleModel.createSubsetSampleModel(bandList);
754         else
755             sm = sampleModel;
756 
757         int deltaX = x0 - x;
758         int deltaY = y0 - y;
759 
760         return new ShortComponentRaster(sm,
761                                        dataBuffer,
762                                        new Rectangle(x0, y0, width, height),
763                                        new Point(sampleModelTranslateX+deltaX,
764                                                  sampleModelTranslateY+deltaY),
765                                        this);
766     }
767 
768     /**
769      * Creates a Raster with the same layout but using a different
770      * width and height, and with new zeroed data arrays.
771      */
772     public WritableRaster createCompatibleWritableRaster(int w, int h) {
773         if (w <= 0 || h <=0) {
774             throw new RasterFormatException("negative "+
775                                           ((w <= 0) ? "width" : "height"));
776         }
777 
778         SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
779 
780         return new ShortComponentRaster(sm, new Point(0, 0));
781     }
782 
783     /**
784      * Creates a Raster with the same layout and the same
785      * width and height, and with new zeroed data arrays.  If
786      * the Raster is a subRaster, this will call
787      * createCompatibleRaster(width, height).
788      */
789     public WritableRaster createCompatibleWritableRaster() {
790         return createCompatibleWritableRaster(width,height);
791     }
792 
793     /**
794      * Verify that the layout parameters are consistent with the data.
795      *
796      * The method verifies whether scanline stride and pixel stride do not
797      * cause an integer overflow during calculation of a position of the pixel
798      * in data buffer. It also verifies whether the data buffer has enough data
799      *  to correspond the raster layout attributes.
800      *
801      * @throws RasterFormatException if an integer overflow is detected,
802      * or if data buffer has not enough capacity.
803      */
804     protected final void verify() {
805         /* Need to re-verify the dimensions since a sample model may be
806          * specified to the constructor
807          */
808         if (width <= 0 || height <= 0 ||
809             height > (Integer.MAX_VALUE / width))
810         {
811             throw new RasterFormatException("Invalid raster dimension");
812         }
813 
814         for (int i = 0; i < dataOffsets.length; i++) {
815             if (dataOffsets[i] < 0) {
816                 throw new RasterFormatException("Data offsets for band " + i
817                             + "(" + dataOffsets[i]
818                             + ") must be >= 0");
819             }
820         }
821 
822         // we can be sure that width and height are greater than 0
823         if (scanlineStride < 0 ||
824             scanlineStride > (Integer.MAX_VALUE / height) ||
825             scanlineStride > data.length)
826         {
827             // integer overflow
828             throw new RasterFormatException("Incorrect scanline stride: "
829                     + scanlineStride);
830         }
831         int lastScanOffset = (height - 1) * scanlineStride;
832 
833         if (pixelStride < 0 ||
834             pixelStride > (Integer.MAX_VALUE / width) ||
835             pixelStride > data.length)
836         {
837             // integer overflow
838             throw new RasterFormatException("Incorrect pixel stride: "
839                     + pixelStride);
840         }
841         int lastPixelOffset = (width - 1) * pixelStride;
842 
843         if (lastPixelOffset > (Integer.MAX_VALUE - lastScanOffset)) {
844             // integer overflow
845             throw new RasterFormatException("Incorrect raster attributes");
846         }
847         lastPixelOffset += lastScanOffset;
848 
849         int index;
850         int maxIndex = 0;
851         for (int i = 0; i < numDataElements; i++) {
852             if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) {
853                 throw new RasterFormatException("Incorrect band offset: "
854                             + dataOffsets[i]);
855             }
856 
857             index = lastPixelOffset + dataOffsets[i];
858 
859             if (index > maxIndex) {
860                 maxIndex = index;
861             }
862         }
863         if (data.length <= maxIndex) {
864             throw new RasterFormatException("Data array too small (should be > "
865                     + maxIndex + " )");
866         }
867     }
868 
869     public String toString() {
870         return new String ("ShortComponentRaster: width = "+width
871                            +" height = " + height
872                            +" #numDataElements "+numDataElements);
873                            // +" xOff = "+xOffset+" yOff = "+yOffset);
874     }
875 
876 }