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