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