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