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