1 /*
2  * Copyright (c) 1997, 2018, 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.BandedSampleModel;
32 import java.awt.image.DataBufferUShort;
33 import java.awt.Rectangle;
34 import java.awt.Point;
35 
36 /**
37  * This class defines a Raster with pixels consisting of multiple 16-bit
38  * samples stored in separate arrays for each band.  Operations on
39  * sets of pixels are performed on a given band of each pixel
40  * in the set before moving on to the next band.  The arrays used
41  * for storage may be distinct or shared between some or all of
42  * the bands.
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. This class requires a BandedSampleModel.
46  *
47  */
48 public class ShortBandedRaster extends SunWritableRaster {
49 
50     /** Data offsets for each band of image data. */
51     int[]         dataOffsets;
52 
53     /** Scanline stride of the image data contained in this Raster. */
54     int           scanlineStride;
55 
56     /** The image data array. */
57     short[][]     data;
58 
59     /** A cached copy of minX + width for use in bounds checks. */
60     private int maxX;
61 
62     /** A cached copy of minY + height for use in bounds checks. */
63     private int maxY;
64 
65     /**
66      * Constructs a ShortBandedRaster with the given SampleModel.
67      * The Raster's upper left corner is origin and it is the same
68      * size as the SampleModel.  A DataBuffer large enough to describe the
69      * Raster is automatically created.  SampleModel must be of type
70      * BandedSampleModel.
71      * @param sampleModel     The SampleModel that specifies the layout.
72      * @param origin          The Point that specified the origin.
73      */
ShortBandedRaster(SampleModel sampleModel, Point origin)74     public ShortBandedRaster(SampleModel sampleModel, Point origin) {
75         this(sampleModel,
76              (DataBufferUShort) sampleModel.createDataBuffer(),
77              new Rectangle(origin.x,
78                            origin.y,
79                            sampleModel.getWidth(),
80                            sampleModel.getHeight()),
81              origin,
82              null);
83     }
84 
85     /**
86      * Constructs a ShortBandedRaster with the given SampleModel
87      * and DataBuffer.  The Raster's upper left corner is origin and
88      * it is the same size as the SampleModel.  The DataBuffer is not
89      * initialized and must be a DataBufferUShort compatible with SampleModel.
90      * SampleModel must be of type BandedSampleModel.
91      * @param sampleModel     The SampleModel that specifies the layout.
92      * @param dataBuffer      The DataBufferUShort that contains the image data.
93      * @param origin          The Point that specifies the origin.
94      */
ShortBandedRaster(SampleModel sampleModel, DataBufferUShort dataBuffer, Point origin)95     public ShortBandedRaster(SampleModel sampleModel,
96                              DataBufferUShort dataBuffer,
97                              Point origin)
98     {
99         this(sampleModel, dataBuffer,
100              new Rectangle(origin.x, origin.y,
101                            sampleModel.getWidth(),
102                            sampleModel.getHeight()),
103              origin, null);
104     }
105 
106     /**
107      * Constructs a ShortBandedRaster with the given SampleModel,
108      * DataBuffer, and parent.  DataBuffer must be a DataBufferUShort and
109      * SampleModel must be of type BandedSampleModel.
110      * When translated into the base Raster's
111      * coordinate system, aRegion must be contained by the base Raster.
112      * Origin is the coordinate in the new Raster's coordinate system of
113      * the origin of the base Raster.  (The base Raster is the Raster's
114      * ancestor which has no parent.)
115      *
116      * Note that this constructor should generally be called by other
117      * constructors or create methods, it should not be used directly.
118      * @param sampleModel     The SampleModel that specifies the layout.
119      * @param dataBuffer      The DataBufferUShort that contains the image data.
120      * @param aRegion         The Rectangle that specifies the image area.
121      * @param origin          The Point that specifies the origin.
122      * @param parent          The parent (if any) of this raster.
123      */
ShortBandedRaster(SampleModel sampleModel, DataBufferUShort dataBuffer, Rectangle aRegion, Point origin, ShortBandedRaster parent)124     public ShortBandedRaster(SampleModel sampleModel,
125                              DataBufferUShort dataBuffer,
126                              Rectangle aRegion,
127                              Point origin,
128                              ShortBandedRaster parent)
129     {
130         super(sampleModel, dataBuffer, aRegion, origin, parent);
131         this.maxX = minX + width;
132         this.maxY = minY + height;
133 
134         if (sampleModel instanceof BandedSampleModel) {
135             BandedSampleModel bsm = (BandedSampleModel)sampleModel;
136             this.scanlineStride = bsm.getScanlineStride();
137             int[] bankIndices = bsm.getBankIndices();
138             int[] bandOffsets = bsm.getBandOffsets();
139             int[] dOffsets = dataBuffer.getOffsets();
140             dataOffsets = new int[bankIndices.length];
141             data = new short[bankIndices.length][];
142             int xOffset = aRegion.x - origin.x;
143             int yOffset = aRegion.y - origin.y;
144             for (int i = 0; i < bankIndices.length; i++) {
145                data[i] = stealData(dataBuffer, bankIndices[i]);
146                dataOffsets[i] = dOffsets[bankIndices[i]] +
147                    xOffset + yOffset*scanlineStride + bandOffsets[i];
148             }
149         } else {
150             throw new RasterFormatException("ShortBandedRasters must have "+
151                 "BandedSampleModels");
152         }
153         verify();
154     }
155 
156     /**
157      * Returns a copy of the data offsets array. For each band the data offset
158      * is the index into the band's data array, of the first sample of the
159      * band.
160      */
getDataOffsets()161     public int[] getDataOffsets() {
162         return dataOffsets.clone();
163     }
164 
165     /**
166      * Returns the data offset for the specified band.  The data offset
167      * is the index into the band's data array
168      * in which the first sample of the first scanline is stored.
169      * @param band The band whose offset is returned.
170      */
getDataOffset(int band)171     public int getDataOffset(int band) {
172         return dataOffsets[band];
173     }
174 
175     /**
176      * Returns the scanline stride -- the number of data array elements between
177      * a given sample and the sample in the same column
178      * of the next row in the same band.
179      */
getScanlineStride()180     public int getScanlineStride() {
181         return scanlineStride;
182     }
183 
184     /**
185      * Returns the pixel stride, which is always equal to one for
186      * a Raster with a BandedSampleModel.
187      */
getPixelStride()188     public int getPixelStride() {
189         return 1;
190     }
191 
192     /**
193      * Returns a reference to the entire data array.
194      */
getDataStorage()195     public short[][] getDataStorage() {
196         return data;
197     }
198 
199     /**
200      * Returns a reference to the specific band data array.
201      */
getDataStorage(int band)202     public short[] getDataStorage(int band) {
203         return data[band];
204     }
205 
206     /**
207      * Returns the data elements for all bands at the specified
208      * location.
209      * An ArrayIndexOutOfBounds exception will be thrown at runtime
210      * if the pixel coordinate is out of bounds.
211      * A ClassCastException will be thrown if the input object is non null
212      * and references anything other than an array of transferType.
213      * @param x        The X coordinate of the pixel location.
214      * @param y        The Y coordinate of the pixel location.
215      * @param obj      An object reference to an array of type defined by
216      *                 getTransferType() and length getNumDataElements().
217      *                 If null an array of appropriate type and size will be
218      *                 allocated.
219      * @return         An object reference to an array of type defined by
220      *                 getTransferType() with the request pixel data.
221      */
getDataElements(int x, int y, Object obj)222     public Object getDataElements(int x, int y, Object obj) {
223         if ((x < this.minX) || (y < this.minY) ||
224             (x >= this.maxX) || (y >= this.maxY)) {
225             throw new ArrayIndexOutOfBoundsException
226                 ("Coordinate out of bounds!");
227         }
228         short[] outData;
229         if (obj == null) {
230             outData = new short[numDataElements];
231         } else {
232             outData = (short[])obj;
233         }
234 
235         int off = (y-minY)*scanlineStride + (x-minX);
236 
237         for (int band = 0; band < numDataElements; band++) {
238             outData[band] = data[band][dataOffsets[band] + off];
239         }
240 
241         return outData;
242     }
243 
244     /**
245      * Returns an array  of data elements from the specified rectangular
246      * region.
247      * An ArrayIndexOutOfBounds exception will be thrown at runtime
248      * if the pixel coordinates are out of bounds.
249      * <pre>
250      *       short[] bandData = (short[])Raster.getDataElements(x, y, w, h, null);
251      *       int numDataElements = Raster.getnumDataElements();
252      *       short[] pixel = new short[numDataElements];
253      *       // To find a data element at location (x2, y2)
254      *       System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
255      *                        pixel, 0, numDataElements);
256      * </pre>
257      * @param x        The X coordinate of the upper left pixel location.
258      * @param y        The Y coordinate of the upper left pixel location.
259      * @param w        Width of the pixel rectangle.
260      * @param h        Height of the pixel rectangle.
261      * @param obj      An object reference to an array of type defined by
262      *                 getTransferType() and length w*h*getNumDataElements().
263      *                 If null an array of appropriate type and size will be
264      *                 allocated.
265      * @return         An object reference to an array of type defined by
266      *                 getTransferType() with the request pixel data.
267      */
getDataElements(int x, int y, int w, int h, Object obj)268     public Object getDataElements(int x, int y, int w, int h, Object obj) {
269         if ((x < this.minX) || (y < this.minY) ||
270             (x + w > this.maxX) || (y + h > this.maxY)) {
271             throw new ArrayIndexOutOfBoundsException
272                 ("Coordinate out of bounds!");
273         }
274         short[] outData;
275         if (obj == null) {
276             outData = new short[numDataElements*w*h];
277         } else {
278             outData = (short[])obj;
279         }
280         int yoff = (y-minY)*scanlineStride + (x-minX);
281 
282         for (int c = 0; c < numDataElements; c++) {
283             int off = c;
284             short[] bank = data[c];
285             int dataOffset = dataOffsets[c];
286 
287             int yoff2 = yoff;
288             for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) {
289                 int xoff = dataOffset + yoff2;
290                 for (int xstart=0; xstart < w; xstart++) {
291                     outData[off] = bank[xoff++];
292                     off += numDataElements;
293                 }
294             }
295         }
296 
297         return outData;
298     }
299 
300     /**
301      * Returns a short array  of data elements from the specified rectangular
302      * region for the specified band.
303      * An ArrayIndexOutOfBounds exception will be thrown at runtime
304      * if the pixel coordinates are out of bounds.
305      * <pre>
306      *       short[] bandData = Raster.getShortData(x, y, w, h, null);
307      *       // To find the data element at location (x2, y2)
308      *       short bandElement = bandData[((y2-y)*w + (x2-x))];
309      * </pre>
310      * @param x        The X coordinate of the upper left pixel location.
311      * @param y        The Y coordinate of the upper left pixel location.
312      * @param w        Width of the pixel rectangle.
313      * @param h        Height of the pixel rectangle.
314      * @param band     The band to return.
315      * @param outData  If non-null, data elements for all bands
316      *                 at the specified location are returned in this array.
317      * @return         Data array with data elements for all bands.
318      */
getShortData(int x, int y, int w, int h, int band, short[] outData)319     public short[] getShortData(int x, int y, int w, int h,
320                                       int band, short[] outData) {
321         // Bounds check for 'band' will be performed automatically
322         if ((x < this.minX) || (y < this.minY) ||
323             (x + w > this.maxX) || (y + h > this.maxY)) {
324             throw new ArrayIndexOutOfBoundsException
325                 ("Coordinate out of bounds!");
326         }
327         if (outData == null) {
328             outData = new short[scanlineStride*h];
329         }
330         int yoff = (y-minY)*scanlineStride + (x-minX) + dataOffsets[band];
331 
332         if (scanlineStride == w) {
333             System.arraycopy(data[band], yoff, outData, 0, w*h);
334         } else {
335             int off = 0;
336             for (int ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
337                 System.arraycopy(data[band], yoff, outData, off, w);
338                 off += w;
339             }
340         }
341 
342         return outData;
343     }
344 
345     /**
346      * Returns a short array  of data elements from the specified rectangular
347      * region.
348      * An ArrayIndexOutOfBounds exception will be thrown at runtime
349      * if the pixel coordinates are out of bounds.
350      * <pre>
351      *       short[] bandData = Raster.getShortData(x, y, w, h, null);
352      *       int numDataElements = Raster.getnumDataElements();
353      *       short[] pixel = new short[numDataElements];
354      *       // To find a data element at location (x2, y2)
355      *       System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
356      *                        pixel, 0, numDataElements);
357      * </pre>
358      * @param x        The X coordinate of the upper left pixel location.
359      * @param y        The Y coordinate of the upper left pixel location.
360      * @param w        Width of the pixel rectangle.
361      * @param h        Height of the pixel rectangle.
362      * @param outData  If non-null, data elements for all bands
363      *                 at the specified location are returned in this array.
364      * @return         Data array with data elements for all bands.
365      */
getShortData(int x, int y, int w, int h, short[] outData)366     public short[] getShortData(int x, int y, int w, int h,
367                                      short[] outData) {
368         if ((x < this.minX) || (y < this.minY) ||
369             (x + w > this.maxX) || (y + h > this.maxY)) {
370             throw new ArrayIndexOutOfBoundsException
371                 ("Coordinate out of bounds!");
372         }
373         if (outData == null) {
374             outData = new short[numDataElements*scanlineStride*h];
375         }
376         int yoff = (y-minY)*scanlineStride + (x-minX);
377 
378         for (int c = 0; c < numDataElements; c++) {
379             int off = c;
380             short[] bank = data[c];
381             int dataOffset = dataOffsets[c];
382 
383             int yoff2 = yoff;
384             for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) {
385                 int xoff = dataOffset + yoff2;
386                 for (int xstart=0; xstart < w; xstart++) {
387                     outData[off] = bank[xoff++];
388                     off += numDataElements;
389                 }
390             }
391         }
392 
393         return outData;
394     }
395 
396     /**
397      * Stores the data element for all bands at the specified location.
398      * An ArrayIndexOutOfBounds exception will be thrown at runtime
399      * if the pixel coordinate is out of bounds.
400      * A ClassCastException will be thrown if the input object is non null
401      * and references anything other than an array of transferType.
402      * @param x        The X coordinate of the pixel location.
403      * @param y        The Y coordinate of the pixel location.
404      * @param obj      An object reference to an array of type defined by
405      *                 getTransferType() and length getNumDataElements()
406      *                 containing the pixel data to place at x,y.
407      */
setDataElements(int x, int y, Object obj)408     public void setDataElements(int x, int y, Object obj) {
409         if ((x < this.minX) || (y < this.minY) ||
410             (x >= this.maxX) || (y >= this.maxY)) {
411             throw new ArrayIndexOutOfBoundsException
412                 ("Coordinate out of bounds!");
413         }
414         short[] inData = (short[])obj;
415         int off = (y-minY)*scanlineStride + (x-minX);
416         for (int i = 0; i < numDataElements; i++) {
417             data[i][dataOffsets[i] + off] = inData[i];
418         }
419 
420         markDirty();
421     }
422 
423     /**
424      * Stores the Raster data at the specified location.
425      * An ArrayIndexOutOfBounds exception will be thrown at runtime
426      * if the pixel coordinates are out of bounds.
427      * @param x          The X coordinate of the pixel location.
428      * @param y          The Y coordinate of the pixel location.
429      * @param inRaster   Raster of data to place at x,y location.
430      */
setDataElements(int x, int y, Raster inRaster)431     public void setDataElements(int x, int y, Raster inRaster) {
432         int dstOffX = x + inRaster.getMinX();
433         int dstOffY = y + inRaster.getMinY();
434         int width  = inRaster.getWidth();
435         int height = inRaster.getHeight();
436         if ((dstOffX < this.minX) || (dstOffY < this.minY) ||
437             (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) {
438             throw new ArrayIndexOutOfBoundsException
439                 ("Coordinate out of bounds!");
440         }
441 
442         setDataElements(dstOffX, dstOffY, width, height, inRaster);
443     }
444 
445     /**
446      * Stores the Raster data at the specified location.
447      * @param dstX The absolute X coordinate of the destination pixel
448      * that will receive a copy of the upper-left pixel of the
449      * inRaster
450      * @param dstY The absolute Y coordinate of the destination pixel
451      * that will receive a copy of the upper-left pixel of the
452      * inRaster
453      * @param width      The number of pixels to store horizontally
454      * @param height     The number of pixels to store vertically
455      * @param inRaster   Raster of data to place at x,y location.
456      */
setDataElements(int dstX, int dstY, int width, int height, Raster inRaster)457     private void setDataElements(int dstX, int dstY,
458                                  int width, int height,
459                                  Raster inRaster) {
460         // Assume bounds checking has been performed previously
461         if (width <= 0 || height <= 0) {
462             return;
463         }
464 
465         // Write inRaster (minX, minY) to (dstX, dstY)
466 
467         int srcOffX = inRaster.getMinX();
468         int srcOffY = inRaster.getMinY();
469         Object tdata = null;
470 
471 //      // REMIND: Do something faster!
472 //      if (inRaster instanceof ShortBandedRaster) {
473 //      }
474 
475         for (int startY=0; startY < height; startY++) {
476             // Grab one scanline at a time
477             tdata = inRaster.getDataElements(srcOffX, srcOffY+startY,
478                                              width, 1, tdata);
479             setDataElements(dstX, dstY + startY, width, 1, tdata);
480         }
481     }
482 
483     /**
484      * Stores an array of data elements into the specified rectangular
485      * region.
486      * An ArrayIndexOutOfBounds exception will be thrown at runtime
487      * if the pixel coordinates are out of bounds.
488      * A ClassCastException will be thrown if the input object is non null
489      * and references anything other than an array of transferType.
490      * The data elements in the
491      * data array are assumed to be packed.  That is, a data element
492      * for the nth band at location (x2, y2) would be found at:
493      * <pre>
494      *      inData[((y2-y)*w + (x2-x))*numDataElements + n]
495      * </pre>
496      * @param x        The X coordinate of the upper left pixel location.
497      * @param y        The Y coordinate of the upper left pixel location.
498      * @param w        Width of the pixel rectangle.
499      * @param h        Height of the pixel rectangle.
500      * @param obj      An object reference to an array of type defined by
501      *                 getTransferType() and length w*h*getNumDataElements()
502      *                 containing the pixel data to place between x,y and
503      *                 x+h, y+h.
504      */
setDataElements(int x, int y, int w, int h, Object obj)505     public void setDataElements(int x, int y, int w, int h, Object obj) {
506         if ((x < this.minX) || (y < this.minY) ||
507             (x + w > this.maxX) || (y + h > this.maxY)) {
508             throw new ArrayIndexOutOfBoundsException
509                 ("Coordinate out of bounds!");
510         }
511         short[] inData = (short[])obj;
512         int yoff = (y-minY)*scanlineStride + (x-minX);
513 
514         for (int c = 0; c < numDataElements; c++) {
515             int off = c;
516             short[] bank = data[c];
517             int dataOffset = dataOffsets[c];
518 
519             int yoff2 = yoff;
520             for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) {
521                 int xoff = dataOffset + yoff2;
522                 for (int xstart=0; xstart < w; xstart++) {
523                     bank[xoff++] = inData[off];
524                     off += numDataElements;
525                 }
526             }
527         }
528 
529         markDirty();
530     }
531 
532     /**
533      * Stores a short array of data elements into the specified
534      * rectangular region for the specified band.
535      * An ArrayIndexOutOfBounds exception will be thrown at runtime
536      * if the pixel coordinates are out of bounds.
537      * The data elements in the
538      * data array are assumed to be packed.  That is, a data element
539      * at location (x2, y2) would be found at:
540      * <pre>
541      *      inData[((y2-y)*w + (x2-x))]
542      * </pre>
543      * @param x        The X coordinate of the upper left pixel location.
544      * @param y        The Y coordinate of the upper left pixel location.
545      * @param w        Width of the pixel rectangle.
546      * @param h        Height of the pixel rectangle.
547      * @param band     The band to set.
548      * @param inData   The data elements to be stored.
549      */
putShortData(int x, int y, int w, int h, int band, short[] inData)550     public void putShortData(int x, int y, int w, int h,
551                                    int band, short[] inData) {
552         // Bounds check for 'band' will be performed automatically
553         if ((x < this.minX) || (y < this.minY) ||
554             (x + w > this.maxX) || (y + h > this.maxY)) {
555             throw new ArrayIndexOutOfBoundsException
556                 ("Coordinate out of bounds!");
557         }
558         int yoff = (y-minY)*scanlineStride + (x-minX) + dataOffsets[band];
559         int xoff;
560         int off = 0;
561         int xstart;
562         int ystart;
563 
564         if (scanlineStride == w) {
565             System.arraycopy(inData, 0, data[band], yoff, w*h);
566         } else {
567             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
568                 System.arraycopy(inData, off, data[band], yoff, w);
569                 off += w;
570             }
571         }
572 
573         markDirty();
574     }
575 
576     /**
577      * Stores a short integer array of data elements into the specified
578      * rectangular region.
579      * An ArrayIndexOutOfBounds exception will be thrown at runtime
580      * if the pixel coordinates are out of bounds.
581      * The data elements in the
582      * data array are assumed to be packed.  That is, a data element
583      * for the nth band at location (x2, y2) would be found at:
584      * <pre>
585      *      inData[((y2-y)*w + (x2-x))*numDataElements + n]
586      * </pre>
587      * @param x        The X coordinate of the upper left pixel location.
588      * @param y        The Y coordinate of the upper left pixel location.
589      * @param w        Width of the pixel rectangle.
590      * @param h        Height of the pixel rectangle.
591      * @param inData   The data elements to be stored.
592      */
putShortData(int x, int y, int w, int h, short[] inData)593     public void putShortData(int x, int y, int w, int h, short[] inData) {
594         if ((x < this.minX) || (y < this.minY) ||
595             (x + w > this.maxX) || (y + h > this.maxY)) {
596             throw new ArrayIndexOutOfBoundsException
597                 ("Coordinate out of bounds!");
598         }
599         int yoff = (y-minY)*scanlineStride + (x-minX);
600 
601         for (int c = 0; c < numDataElements; c++) {
602             int off = c;
603             short[] bank = data[c];
604             int dataOffset = dataOffsets[c];
605 
606             int yoff2 = yoff;
607             for (int ystart=0; ystart < h; ystart++, yoff2 += scanlineStride) {
608                 int xoff = dataOffset + yoff2;
609                 for (int xstart=0; xstart < w; xstart++) {
610                     bank[xoff++] = inData[off];
611                     off += numDataElements;
612                 }
613             }
614         }
615 
616         markDirty();
617     }
618 
619     /**
620      * Creates a Writable subRaster given a region of the Raster.  The x and y
621      * coordinates specify the horizontal and vertical offsets
622      * from the upper-left corner of this Raster to the upper-left corner
623      * of the subRaster.  A subset of the bands of the parent Raster may
624      * be specified.  If this is null, then all the bands are present in the
625      * subRaster. A translation to the subRaster may also be specified.
626      * Note that the subRaster will reference the same
627      * DataBuffers as the parent Raster, but using different offsets.
628      * @param x               X offset.
629      * @param y               Y offset.
630      * @param width           Width (in pixels) of the subraster.
631      * @param height          Height (in pixels) of the subraster.
632      * @param x0              Translated X origin of the subraster.
633      * @param y0              Translated Y origin of the subraster.
634      * @param bandList        Array of band indices.
635      * @exception RasterFormatException
636      *            if the specified bounding box is outside of the parent Raster.
637      */
createWritableChild(int x, int y, int width, int height, int x0, int y0, int[] bandList)638     public WritableRaster createWritableChild(int x, int y,
639                                               int width, int height,
640                                               int x0, int y0,
641                                               int[] bandList) {
642 
643         if (x < this.minX) {
644             throw new RasterFormatException("x lies outside raster");
645         }
646         if (y < this.minY) {
647             throw new RasterFormatException("y lies outside raster");
648         }
649         if ((x+width < x) || (x+width > this.minX + this.width)) {
650             throw new RasterFormatException("(x + width) is outside of Raster");
651         }
652         if ((y+height < y) || (y+height > this.minY + this.height)) {
653             throw new RasterFormatException("(y + height) is outside of Raster");
654         }
655 
656         SampleModel sm;
657 
658         if (bandList != null)
659             sm = sampleModel.createSubsetSampleModel(bandList);
660         else
661             sm = sampleModel;
662 
663         int deltaX = x0 - x;
664         int deltaY = y0 - y;
665 
666         return new ShortBandedRaster(sm,
667                                      (DataBufferUShort) dataBuffer,
668                                      new Rectangle(x0, y0, width, height),
669                                      new Point(sampleModelTranslateX+deltaX,
670                                                sampleModelTranslateY+deltaY),
671                                      this);
672 
673     }
674 
675     /**
676      * Creates a subraster given a region of the raster.  The x and y
677      * coordinates specify the horizontal and vertical offsets
678      * from the upper-left corner of this raster to the upper-left corner
679      * of the subraster.  A subset of the bands of the parent Raster may
680      * be specified.  If this is null, then all the bands are present in the
681      * subRaster. A translation to the subRaster may also be specified.
682      * Note that the subraster will reference the same
683      * DataBuffers as the parent raster, but using different offsets.
684      * @param x               X offset.
685      * @param y               Y offset.
686      * @param width           Width (in pixels) of the subraster.
687      * @param height          Height (in pixels) of the subraster.
688      * @param x0              Translated X origin of the subraster.
689      * @param y0              Translated Y origin of the subraster.
690      * @param bandList        Array of band indices.
691      * @exception RasterFormatException
692      *            if the specified bounding box is outside of the parent raster.
693      */
createChild(int x, int y, int width, int height, int x0, int y0, int[] bandList)694     public Raster createChild (int x, int y,
695                                int width, int height,
696                                int x0, int y0,
697                                int[] bandList) {
698         return createWritableChild(x, y, width, height, x0, y0, bandList);
699     }
700 
701     /**
702      * Creates a Raster with the same layout but using a different
703      * width and height, and with new zeroed data arrays.
704      */
createCompatibleWritableRaster(int w, int h)705     public WritableRaster createCompatibleWritableRaster(int w, int h) {
706         if (w <= 0 || h <=0) {
707             throw new RasterFormatException("negative "+
708                                             ((w <= 0) ? "width" : "height"));
709         }
710 
711         SampleModel sm = sampleModel.createCompatibleSampleModel(w,h);
712 
713         return new ShortBandedRaster(sm, new Point(0,0));
714     }
715 
716     /**
717      * Creates a Raster with the same layout and the same
718      * width and height, and with new zeroed data arrays.  If
719      * the Raster is a subRaster, this will call
720      * createCompatibleRaster(width, height).
721      */
createCompatibleWritableRaster()722     public WritableRaster createCompatibleWritableRaster() {
723        return createCompatibleWritableRaster(width,height);
724     }
725 
726     /**
727      * Verify that the layout parameters are consistent with the data.
728      * Verifies whether the data buffer has enough data for the raster,
729      * taking into account offsets, after ensuring all offsets are >=0.
730      * @throws RasterFormatException if a problem is detected.
731      */
verify()732     private void verify() {
733 
734         /* Need to re-verify the dimensions since a sample model may be
735          * specified to the constructor
736          */
737         if (width <= 0 || height <= 0 ||
738             height > (Integer.MAX_VALUE / width))
739         {
740             throw new RasterFormatException("Invalid raster dimension");
741         }
742 
743         if (scanlineStride < 0 ||
744             scanlineStride > (Integer.MAX_VALUE / height))
745         {
746             // integer overflow
747             throw new RasterFormatException("Incorrect scanline stride: "
748                     + scanlineStride);
749         }
750 
751         if ((long)minX - sampleModelTranslateX < 0 ||
752             (long)minY - sampleModelTranslateY < 0) {
753 
754             throw new RasterFormatException("Incorrect origin/translate: (" +
755                     minX + ", " + minY + ") / (" +
756                     sampleModelTranslateX + ", " + sampleModelTranslateY + ")");
757         }
758 
759         if (height > 1 || minY - sampleModelTranslateY > 0) {
760             // buffer should contain at least one scanline
761             for (int i = 0; i < data.length; i++) {
762                 if (scanlineStride > data[i].length) {
763                     throw new RasterFormatException("Incorrect scanline stride: "
764                         + scanlineStride);
765                 }
766             }
767         }
768 
769         // Make sure data for Raster is in a legal range
770         for (int i=0; i < dataOffsets.length; i++) {
771             if (dataOffsets[i] < 0) {
772                 throw new RasterFormatException("Data offsets for band "+i+
773                                                 "("+dataOffsets[i]+
774                                                 ") must be >= 0");
775             }
776         }
777 
778         int lastScanOffset = (height - 1) * scanlineStride;
779         if ((width - 1) > (Integer.MAX_VALUE - lastScanOffset)) {
780             throw new RasterFormatException("Invalid raster dimension");
781         }
782         int lastPixelOffset = lastScanOffset + (width - 1);
783 
784         int maxIndex = 0;
785         int index;
786 
787         for (int i=0; i < numDataElements; i++) {
788             if (dataOffsets[i] > (Integer.MAX_VALUE - lastPixelOffset)) {
789                 throw new RasterFormatException("Invalid raster dimension");
790             }
791             index = lastPixelOffset + dataOffsets[i];
792             if (index > maxIndex) {
793                 maxIndex = index;
794             }
795         }
796         for (int i=0; i < numDataElements; i++) {
797             if (data[i].length <= maxIndex) {
798                 throw new RasterFormatException("Data array too small " +
799                       "(should be > "+ maxIndex+" )");
800             }
801         }
802     }
803 
toString()804     public String toString() {
805         return new String ("ShortBandedRaster: width = "+width+" height = "
806                            + height
807                            +" #numBands " + numBands
808                            +" #dataElements "+numDataElements);
809 
810     }
811 
812 }
813