1 /*
   2  * Copyright (c) 1997, 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 
  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      */
  74     public ShortBandedRaster(SampleModel sampleModel,
  75                              Point origin) {
  76         this(sampleModel,
  77              (DataBufferUShort)sampleModel.createDataBuffer(),
  78              new Rectangle(origin.x,
  79                            origin.y,
  80                            sampleModel.getWidth(),
  81                            sampleModel.getHeight()),
  82              origin,
  83              null);
  84     }
  85 
  86     /**
  87      * Constructs a ShortBandedRaster with the given SampleModel
  88      * and DataBuffer.  The Raster's upper left corner is origin and
  89      * it is the same size as the SampleModel.  The DataBuffer is not
  90      * initialized and must be a DataBufferUShort compatible with SampleModel.
  91      * SampleModel must be of type BandedSampleModel.
  92      * @param sampleModel     The SampleModel that specifies the layout.
  93      * @param dataBuffer      The DataBufferUShort that contains the image data.
  94      * @param origin          The Point that specifies the origin.
  95      */
  96     public ShortBandedRaster(SampleModel sampleModel,
  97                              DataBufferUShort dataBuffer,
  98                              Point origin) {
  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      */
 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      */
 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      */
 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      */
 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      */
 188     public int getPixelStride() {
 189         return 1;
 190     }
 191 
 192     /**
 193      * Returns a reference to the entire data array.
 194      */
 195     public short[][] getDataStorage() {
 196         return data;
 197     }
 198 
 199     /**
 200      * Returns a reference to the specific band data array.
 201      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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      */
 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 
 804     public String toString() {
 805         return new String ("ShortBandedRaster: width = "+width+" height = "
 806                            + height
 807                            +" #numBands " + numBands
 808                            +" #dataElements "+numDataElements);
 809 
 810     }
 811 
 812 }