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