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