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