1 /*
   2  * Copyright (c) 1998, 2007, Oracle and/or its affiliates. All rights reserved.
   3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
   4  *
   5  * This code is free software; you can redistribute it and/or modify it
   6  * under the terms of the GNU General Public License version 2 only, as
   7  * published by the Free Software Foundation.  Oracle designates this
   8  * particular file as subject to the "Classpath" exception as provided
   9  * by Oracle in the LICENSE file that accompanied this code.
  10  *
  11  * This code is distributed in the hope that it will be useful, but WITHOUT
  12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
  13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
  14  * version 2 for more details (a copy is included in the LICENSE file that
  15  * accompanied this code).
  16  *
  17  * You should have received a copy of the GNU General Public License version
  18  * 2 along with this work; if not, write to the Free Software Foundation,
  19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  20  *
  21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  22  * or visit www.oracle.com if you need additional information or have any
  23  * questions.
  24  */
  25 
  26 package sun.awt.image;
  27 import java.awt.image.Raster;
  28 import java.awt.image.WritableRaster;
  29 import java.awt.image.RasterFormatException;
  30 import java.awt.image.SampleModel;
  31 import java.awt.image.ComponentSampleModel;
  32 import java.awt.image.PixelInterleavedSampleModel;
  33 import java.awt.image.SinglePixelPackedSampleModel;
  34 import java.awt.image.DataBuffer;
  35 import java.awt.image.DataBufferByte;
  36 import java.awt.Rectangle;
  37 import java.awt.Point;
  38 
  39 /**
  40  * This class defines a Raster with pixels consisting of one or more
  41  * 8-bit data elements stored in close proximity to each other in a
  42  * single byte array.
  43  * <p>
  44  * The bit precision per data element is that of the data type (that
  45  * is, the bit precision for this Raster is 8).  There is only one
  46  * pixel stride and one scanline stride for all bands.  This type of
  47  * Raster can be used with a ComponentColorModel if there are multiple
  48  * bands, or an IndexColorModel if there is only one band.
  49  *
  50  */
  51 public class ByteInterleavedRaster extends ByteComponentRaster {
  52 
  53     /** True if the data offsets range from 0 to (pixelStride - 1) in order. */
  54     boolean inOrder;
  55 
  56     /**
  57      * The DataBuffer offset, minus sampleModelTranslateX*pixelStride,
  58      * minus sampleModelTranslateY*scanlineStride, used to calculate
  59      * pixel offsets.
  60      */
  61     int dbOffset;
  62     int dbOffsetPacked;
  63 
  64     /** True if a SinglePixelPackedSampleModel is being used. */
  65     boolean packed = false;
  66 
  67     /** If packed == true, the SampleModel's bit masks. */
  68     int[] bitMasks;
  69 
  70     /** If packed == true, the SampleModel's bit offsets. */
  71     int[] bitOffsets;
  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     /**
  80      * Constructs a ByteInterleavedRaster with the given SampleModel.
  81      * The Raster's upper left corner is origin and it is the same
  82      * size as the SampleModel.  A DataBuffer large enough to describe the
  83      * Raster is automatically created.  SampleModel must be of type
  84      * SinglePixelPackedSampleModel or InterleavedSampleModel.
  85      * @param sampleModel     The SampleModel that specifies the layout.
  86      * @param origin          The Point that specified the origin.
  87      */
  88     public ByteInterleavedRaster(SampleModel sampleModel, Point origin) {
  89         this(sampleModel,
  90              sampleModel.createDataBuffer(),
  91              new Rectangle(origin.x,
  92                            origin.y,
  93                            sampleModel.getWidth(),
  94                            sampleModel.getHeight()),
  95              origin,
  96              null);
  97     }
  98 
  99     /**
 100      * Constructs a ByteInterleavedRaster with the given SampleModel
 101      * and DataBuffer.  The Raster's upper left corner is origin and
 102      * it is the same size as the SampleModel.  The DataBuffer is not
 103      * initialized and must be a DataBufferByte compatible with SampleModel.
 104      * SampleModel must be of type SinglePixelPackedSampleModel
 105      * or InterleavedSampleModel.
 106      * @param sampleModel     The SampleModel that specifies the layout.
 107      * @param dataBuffer      The DataBufferShort that contains the image data.
 108      * @param origin          The Point that specifies the origin.
 109      */
 110     public ByteInterleavedRaster(SampleModel sampleModel,
 111                                   DataBuffer dataBuffer,
 112                                   Point origin) {
 113         this(sampleModel,
 114              dataBuffer,
 115              new Rectangle(origin.x,
 116                            origin.y,
 117                            sampleModel.getWidth(),
 118                            sampleModel.getHeight()),
 119              origin,
 120              null);
 121     }
 122 
 123     /*** Analyzes a ComponentSampleModel to determine if it can function
 124      * as a PixelInterleavedSampleModel.  In order to do so, it must use
 125      * only bank 0 of its DataBuffer, and the data offsets must span a range
 126      * of less than pixelStride.
 127      *
 128      * <p> These properties are trivially true for a 1-banded SampleModel.
 129      */
 130     private boolean isInterleaved(ComponentSampleModel sm) {
 131         // Analyze ComponentSampleModel to determine if it has the
 132         // properties of a PixelInterleavedSampleModel
 133 
 134         int numBands = sampleModel.getNumBands();
 135         if (numBands == 1) {
 136             return true;
 137         }
 138 
 139         // Determine banks used
 140         int[] bankIndices = sm.getBankIndices();
 141         for (int i = 0; i < numBands; i++) {
 142             if (bankIndices[i] != 0) {
 143                 return false;
 144             }
 145         }
 146 
 147         // Determine range of band offsets
 148         int[] bandOffsets = sm.getBandOffsets();
 149         int minOffset = bandOffsets[0];
 150         int maxOffset = minOffset;
 151         for (int i = 1; i < numBands; i++) {
 152             int offset = bandOffsets[i];
 153             if (offset < minOffset) {
 154                 minOffset = offset;
 155             }
 156             if (offset > maxOffset) {
 157                 maxOffset = offset;
 158             }
 159         }
 160         if (maxOffset - minOffset >= sm.getPixelStride()) {
 161             return false;
 162         }
 163 
 164         return true;
 165     }
 166 
 167     /**
 168      * Constructs a ByteInterleavedRaster with the given SampleModel,
 169      * DataBuffer, and parent.  DataBuffer must be a DataBufferByte and
 170      * SampleModel must be of type SinglePixelPackedSampleModel
 171      * or InterleavedSampleModel.
 172      * When translated into the base Raster's
 173      * coordinate system, aRegion must be contained by the base Raster.
 174      * Origin is the coordinate in the new Raster's coordinate system of
 175      * the origin of the base Raster.  (The base Raster is the Raster's
 176      * ancestor which has no parent.)
 177      *
 178      * Note that this constructor should generally be called by other
 179      * constructors or create methods, it should not be used directly.
 180      * @param sampleModel     The SampleModel that specifies the layout.
 181      * @param dataBuffer      The DataBufferShort that contains the image data.
 182      * @param aRegion         The Rectangle that specifies the image area.
 183      * @param origin          The Point that specifies the origin.
 184      * @param parent          The parent (if any) of this raster.
 185      */
 186     public ByteInterleavedRaster(SampleModel sampleModel,
 187                                   DataBuffer dataBuffer,
 188                                   Rectangle aRegion,
 189                                   Point origin,
 190                                   ByteInterleavedRaster parent) {
 191         super(sampleModel, dataBuffer, aRegion, origin, parent);
 192         this.maxX = minX + width;
 193         this.maxY = minY + height;
 194 
 195         if (!(dataBuffer instanceof DataBufferByte)) {
 196             throw new RasterFormatException("ByteInterleavedRasters must have " +
 197                                             "byte DataBuffers");
 198         }
 199 
 200         DataBufferByte dbb = (DataBufferByte)dataBuffer;
 201         this.data = stealData(dbb, 0);
 202 
 203         int xOffset = aRegion.x - origin.x;
 204         int yOffset = aRegion.y - origin.y;
 205         if (sampleModel instanceof PixelInterleavedSampleModel ||
 206             (sampleModel instanceof ComponentSampleModel &&
 207              isInterleaved((ComponentSampleModel)sampleModel))) {
 208             ComponentSampleModel csm = (ComponentSampleModel)sampleModel;
 209             this.scanlineStride = csm.getScanlineStride();
 210             this.pixelStride = csm.getPixelStride();
 211             this.dataOffsets = csm.getBandOffsets();
 212             for (int i = 0; i < getNumDataElements(); i++) {
 213                 dataOffsets[i] += xOffset*pixelStride+yOffset*scanlineStride;
 214             }
 215         } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
 216             SinglePixelPackedSampleModel sppsm =
 217                     (SinglePixelPackedSampleModel)sampleModel;
 218             this.packed = true;
 219             this.bitMasks = sppsm.getBitMasks();
 220             this.bitOffsets = sppsm.getBitOffsets();
 221             this.scanlineStride = sppsm.getScanlineStride();
 222             this.pixelStride = 1;
 223             this.dataOffsets = new int[1];
 224             this.dataOffsets[0] = dbb.getOffset();
 225             dataOffsets[0] += xOffset*pixelStride+yOffset*scanlineStride;
 226         } else {
 227             throw new RasterFormatException("ByteInterleavedRasters must " +
 228               "have PixelInterleavedSampleModel, SinglePixelPackedSampleModel"+
 229               " or interleaved ComponentSampleModel.  Sample model is " +
 230               sampleModel);
 231         }
 232         this.bandOffset = this.dataOffsets[0];
 233 
 234         this.dbOffsetPacked = dataBuffer.getOffset() -
 235             sampleModelTranslateY*scanlineStride -
 236             sampleModelTranslateX*pixelStride;
 237         this.dbOffset = dbOffsetPacked -
 238             (xOffset*pixelStride+yOffset*scanlineStride);
 239 
 240         // Set inOrder to true if the data elements are in order and
 241         // have no gaps between them
 242         this.inOrder = false;
 243         if (numDataElements == pixelStride) {
 244             inOrder = true;
 245             for (int i = 1; i < numDataElements; i++) {
 246                 if (dataOffsets[i] - dataOffsets[0] != i) {
 247                     inOrder = false;
 248                     break;
 249                 }
 250             }
 251         }
 252 
 253         verify();
 254     }
 255 
 256     /**
 257      * Returns a copy of the data offsets array. For each band the data offset
 258      * is the index into the band's data array, of the first sample of the
 259      * band.
 260      */
 261     public int[] getDataOffsets() {
 262         return (int[]) dataOffsets.clone();
 263     }
 264 
 265     /**
 266      * Returns the data offset for the specified band.  The data offset
 267      * is the index into the data array
 268      * in which the first sample of the first scanline is stored.
 269      * @param band  The band whose offset is returned.
 270      */
 271     public int getDataOffset(int band) {
 272         return dataOffsets[band];
 273     }
 274 
 275     /**
 276      * Returns the scanline stride -- the number of data array elements between
 277      * a given sample and the sample in the same column of the next row in the
 278      * same band.
 279      */
 280     public int getScanlineStride() {
 281         return scanlineStride;
 282     }
 283 
 284     /**
 285      * Returns pixel stride -- the number of data array elements between two
 286      * samples for the same band on the same scanline.
 287      */
 288     public int getPixelStride() {
 289         return pixelStride;
 290     }
 291 
 292     /**
 293      * Returns a reference to the data array.
 294      */
 295     public byte[] getDataStorage() {
 296         return data;
 297     }
 298 
 299     /**
 300      * Returns the data elements for all bands at the specified
 301      * location.
 302      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 303      * if the pixel coordinate is out of bounds.
 304      * A ClassCastException will be thrown if the input object is non null
 305      * and references anything other than an array of transferType.
 306      * @param x        The X coordinate of the pixel location.
 307      * @param y        The Y coordinate of the pixel location.
 308      * @param outData  An object reference to an array of type defined by
 309      *                 getTransferType() and length getNumDataElements().
 310      *                 If null an array of appropriate type and size will be
 311      *                 allocated.
 312      * @return         An object reference to an array of type defined by
 313      *                 getTransferType() with the request pixel data.
 314      */
 315     public Object getDataElements(int x, int y, Object obj) {
 316         if ((x < this.minX) || (y < this.minY) ||
 317             (x >= this.maxX) || (y >= this.maxY)) {
 318             throw new ArrayIndexOutOfBoundsException
 319                 ("Coordinate out of bounds!");
 320         }
 321         byte outData[];
 322         if (obj == null) {
 323             outData = new byte[numDataElements];
 324         } else {
 325             outData = (byte[])obj;
 326         }
 327         int off = (y-minY)*scanlineStride +
 328                   (x-minX)*pixelStride;
 329 
 330         for (int band = 0; band < numDataElements; band++) {
 331             outData[band] = data[dataOffsets[band] + off];
 332         }
 333 
 334         return outData;
 335     }
 336 
 337     /**
 338      * Returns an array of data elements from the specified rectangular
 339      * region.
 340      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 341      * if the pixel coordinates are out of bounds.
 342      * A ClassCastException will be thrown if the input object is non null
 343      * and references anything other than an array of transferType.
 344      * <pre>
 345      *       byte[] bandData = (byte[])raster.getDataElements(x, y, w, h, null);
 346      *       int numDataElements = raster.getNumDataElements();
 347      *       byte[] pixel = new byte[numDataElements];
 348      *       // To find a data element at location (x2, y2)
 349      *       System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
 350      *                        pixel, 0, numDataElements);
 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 width    Width of the pixel rectangle.
 355      * @param height   Height of the pixel rectangle.
 356      * @param outData  An object reference to an array of type defined by
 357      *                 getTransferType() and length w*h*getNumDataElements().
 358      *                 If null an array of appropriate type and size will be
 359      *                 allocated.
 360      * @return         An object reference to an array of type defined by
 361      *                 getTransferType() with the request pixel data.
 362      */
 363     public Object getDataElements(int x, int y, int w, int h, Object obj) {
 364         return getByteData(x, y, w, h, (byte[])obj);
 365     }
 366 
 367     /**
 368      * Returns a byte array of data elements from the specified rectangular
 369      * region for the specified band.
 370      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 371      * if the pixel coordinates are out of bounds.
 372      * <pre>
 373      *       byte[] bandData = raster.getByteData(x, y, w, h, null);
 374      *       // To find the data element at location (x2, y2)
 375      *       byte bandElement = bandData[((y2-y)*w + (x2-x))];
 376      * </pre>
 377      * @param x        The X coordinate of the upper left pixel location.
 378      * @param y        The Y coordinate of the upper left pixel location.
 379      * @param width    Width of the pixel rectangle.
 380      * @param height   Height of the pixel rectangle.
 381      * @param band     The band to return.
 382      * @param outData  If non-null, data elements for all bands
 383      *                 at the specified location are returned in this array.
 384      * @return         Data array with data elements for all bands.
 385      */
 386     public byte[] getByteData(int x, int y, int w, int h,
 387                               int band, byte[] outData) {
 388         // Bounds check for 'band' will be performed automatically
 389         if ((x < this.minX) || (y < this.minY) ||
 390             (x + w > this.maxX) || (y + h > this.maxY)) {
 391             throw new ArrayIndexOutOfBoundsException
 392                 ("Coordinate out of bounds!");
 393         }
 394         if (outData == null) {
 395             outData = new byte[w*h];
 396         }
 397         int yoff = (y-minY)*scanlineStride +
 398                    (x-minX)*pixelStride + dataOffsets[band];
 399         int xoff;
 400         int off = 0;
 401         int xstart;
 402         int ystart;
 403 
 404         if (pixelStride == 1) {
 405             if (scanlineStride == w) {
 406                 System.arraycopy(data, yoff, outData, 0, w*h);
 407             } else {
 408                 for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 409                     System.arraycopy(data, yoff, outData, off, w);
 410                     off += w;
 411                 }
 412             }
 413         } else {
 414             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 415                 xoff = yoff;
 416                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 417                     outData[off++] = data[xoff];
 418                 }
 419             }
 420         }
 421 
 422         return outData;
 423     }
 424 
 425     /**
 426      * Returns a byte array of data elements from the specified rectangular
 427      * region.
 428      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 429      * if the pixel coordinates are out of bounds.
 430      * <pre>
 431      *       byte[] bandData = raster.getByteData(x, y, w, h, null);
 432      *       int numDataElements = raster.getnumDataElements();
 433      *       byte[] pixel = new byte[numDataElements];
 434      *       // To find a data element at location (x2, y2)
 435      *       System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
 436      *                        pixel, 0, numDataElements);
 437      * </pre>
 438      * @param x        The X coordinate of the upper left pixel location.
 439      * @param y        The Y coordinate of the upper left pixel location.
 440      * @param width    Width of the pixel rectangle.
 441      * @param height   Height of the pixel rectangle.
 442      * @param outData  If non-null, data elements for all bands
 443      *                 at the specified location are returned in this array.
 444      * @return         Data array with data elements for all bands.
 445      */
 446     public byte[] getByteData(int x, int y, int w, int h, byte[] outData) {
 447         if ((x < this.minX) || (y < this.minY) ||
 448             (x + w > this.maxX) || (y + h > this.maxY)) {
 449             throw new ArrayIndexOutOfBoundsException
 450                 ("Coordinate out of bounds!");
 451         }
 452         if (outData == null) {
 453             outData = new byte[numDataElements*w*h];
 454         }
 455         int yoff = (y-minY)*scanlineStride +
 456                    (x-minX)*pixelStride;
 457         int xoff;
 458         int off = 0;
 459         int xstart;
 460         int ystart;
 461 
 462         if (inOrder) {
 463             yoff += dataOffsets[0];
 464             int rowBytes = w*pixelStride;
 465             if (scanlineStride == rowBytes) {
 466                 System.arraycopy(data, yoff, outData, off, rowBytes*h);
 467             } else {
 468                 for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 469                     System.arraycopy(data, yoff, outData, off, rowBytes);
 470                     off += rowBytes;
 471                 }
 472             }
 473         } else if (numDataElements == 1) {
 474             yoff += dataOffsets[0];
 475             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 476                 xoff = yoff;
 477                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 478                     outData[off++] = data[xoff];
 479                 }
 480             }
 481         } else if (numDataElements == 2) {
 482             yoff += dataOffsets[0];
 483             int d1 = dataOffsets[1] - dataOffsets[0];
 484             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 485                 xoff = yoff;
 486                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 487                     outData[off++] = data[xoff];
 488                     outData[off++] = data[xoff + d1];
 489                 }
 490             }
 491         } else if (numDataElements == 3) {
 492             yoff += dataOffsets[0];
 493             int d1 = dataOffsets[1] - dataOffsets[0];
 494             int d2 = dataOffsets[2] - dataOffsets[0];
 495             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 496                 xoff = yoff;
 497                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 498                     outData[off++] = data[xoff];
 499                     outData[off++] = data[xoff + d1];
 500                     outData[off++] = data[xoff + d2];
 501                 }
 502             }
 503         } else if (numDataElements == 4) {
 504             yoff += dataOffsets[0];
 505             int d1 = dataOffsets[1] - dataOffsets[0];
 506             int d2 = dataOffsets[2] - dataOffsets[0];
 507             int d3 = dataOffsets[3] - dataOffsets[0];
 508             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 509                 xoff = yoff;
 510                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 511                     outData[off++] = data[xoff];
 512                     outData[off++] = data[xoff + d1];
 513                     outData[off++] = data[xoff + d2];
 514                     outData[off++] = data[xoff + d3];
 515                 }
 516             }
 517         } else {
 518             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 519                 xoff = yoff;
 520                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 521                     for (int c = 0; c < numDataElements; c++) {
 522                         outData[off++] = data[dataOffsets[c] + xoff];
 523                     }
 524                 }
 525             }
 526         }
 527 
 528         return outData;
 529     }
 530 
 531     /**
 532      * Stores the data elements for all bands at the specified location.
 533      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 534      * if the pixel coordinate is out of bounds.
 535      * A ClassCastException will be thrown if the input object is non null
 536      * and references anything other than an array of transferType.
 537      * @param x        The X coordinate of the pixel location.
 538      * @param y        The Y coordinate of the pixel location.
 539      * @param inData   An object reference to an array of type defined by
 540      *                 getTransferType() and length getNumDataElements()
 541      *                 containing the pixel data to place at x,y.
 542      */
 543     public void setDataElements(int x, int y, Object obj) {
 544         if ((x < this.minX) || (y < this.minY) ||
 545             (x >= this.maxX) || (y >= this.maxY)) {
 546             throw new ArrayIndexOutOfBoundsException
 547                 ("Coordinate out of bounds!");
 548         }
 549         byte inData[] = (byte[])obj;
 550         int off = (y-minY)*scanlineStride +
 551                   (x-minX)*pixelStride;
 552 
 553         for (int i = 0; i < numDataElements; i++) {
 554             data[dataOffsets[i] + off] = inData[i];
 555         }
 556 
 557         markDirty();
 558     }
 559 
 560     /**
 561      * Stores the Raster data at the specified location.
 562      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 563      * if the pixel coordinates are out of bounds.
 564      * @param x          The X coordinate of the pixel location.
 565      * @param y          The Y coordinate of the pixel location.
 566      * @param inRaster   Raster of data to place at x,y location.
 567      */
 568     public void setDataElements(int x, int y, Raster inRaster) {
 569         int srcOffX = inRaster.getMinX();
 570         int srcOffY = inRaster.getMinY();
 571         int dstOffX = x + srcOffX;
 572         int dstOffY = y + srcOffY;
 573         int width  = inRaster.getWidth();
 574         int height = inRaster.getHeight();
 575         if ((dstOffX < this.minX) || (dstOffY < this.minY) ||
 576             (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) {
 577             throw new ArrayIndexOutOfBoundsException
 578                 ("Coordinate out of bounds!");
 579         }
 580 
 581         setDataElements(dstOffX, dstOffY, srcOffX, srcOffY,
 582                         width, height, inRaster);
 583     }
 584 
 585     /**
 586      * Stores the Raster data at the specified location.
 587      * @param dstX The absolute X coordinate of the destination pixel
 588      * that will receive a copy of the upper-left pixel of the
 589      * inRaster
 590      * @param dstY The absolute Y coordinate of the destination pixel
 591      * that will receive a copy of the upper-left pixel of the
 592      * inRaster
 593      * @param srcX The absolute X coordinate of the upper-left source
 594      * pixel that will be copied into this Raster
 595      * @param srcY The absolute Y coordinate of the upper-left source
 596      * pixel that will be copied into this Raster
 597      * @param width      The number of pixels to store horizontally
 598      * @param height     The number of pixels to store vertically
 599      * @param inRaster   Raster of data to place at x,y location.
 600      */
 601     private void setDataElements(int dstX, int dstY,
 602                                  int srcX, int srcY,
 603                                  int width, int height,
 604                                  Raster inRaster) {
 605         // Assume bounds checking has been performed previously
 606         if (width <= 0 || height <= 0) {
 607             return;
 608         }
 609 
 610         // Write inRaster (minX, minY) to (dstX, dstY)
 611 
 612         int srcOffX = inRaster.getMinX();
 613         int srcOffY = inRaster.getMinY();
 614         Object tdata = null;
 615 
 616         if (inRaster instanceof ByteInterleavedRaster) {
 617             ByteInterleavedRaster bct = (ByteInterleavedRaster) inRaster;
 618             byte[] bdata = bct.getDataStorage();
 619             // copy whole scanlines
 620             if (inOrder && bct.inOrder && pixelStride == bct.pixelStride) {
 621                 int toff = bct.getDataOffset(0);
 622                 int tss  = bct.getScanlineStride();
 623                 int tps  = bct.getPixelStride();
 624 
 625                 int srcOffset = toff +
 626                     (srcY - srcOffY) * tss +
 627                     (srcX - srcOffX) * tps;
 628                 int dstOffset = dataOffsets[0] +
 629                     (dstY - minY) * scanlineStride +
 630                     (dstX - minX) * pixelStride;
 631 
 632                 int nbytes = width*pixelStride;
 633                 for (int tmpY=0; tmpY < height; tmpY++) {
 634                     System.arraycopy(bdata, srcOffset,
 635                                      data, dstOffset, nbytes);
 636                     srcOffset += tss;
 637                     dstOffset += scanlineStride;
 638                 }
 639                 markDirty();
 640                 return;
 641             }
 642         }
 643 
 644         for (int startY=0; startY < height; startY++) {
 645             // Grab one scanline at a time
 646             tdata = inRaster.getDataElements(srcOffX, srcOffY+startY,
 647                                              width, 1, tdata);
 648             setDataElements(dstX, dstY + startY, width, 1, tdata);
 649         }
 650     }
 651 
 652     /**
 653      * Stores an array of data elements into the specified rectangular
 654      * region.
 655      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 656      * if the pixel coordinates are out of bounds.
 657      * A ClassCastException will be thrown if the input object is non null
 658      * and references anything other than an array of transferType.
 659      * The data elements in the
 660      * data array are assumed to be packed.  That is, a data element
 661      * for the nth band at location (x2, y2) would be found at:
 662      * <pre>
 663      *      inData[((y2-y)*w + (x2-x))*numDataElements + n]
 664      * </pre>
 665      * @param x        The X coordinate of the upper left pixel location.
 666      * @param y        The Y coordinate of the upper left pixel location.
 667      * @param w        Width of the pixel rectangle.
 668      * @param h        Height of the pixel rectangle.
 669      * @param inData   An object reference to an array of type defined by
 670      *                 getTransferType() and length w*h*getNumDataElements()
 671      *                 containing the pixel data to place between x,y and
 672      *                 x+h, y+h.
 673      */
 674     public void setDataElements(int x, int y, int w, int h, Object obj) {
 675         putByteData(x, y, w, h, (byte[])obj);
 676     }
 677 
 678     /**
 679      * Stores a byte array of data elements into the specified rectangular
 680      * region for the specified band.
 681      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 682      * if the pixel coordinates are out of bounds.
 683      * The data elements in the
 684      * data array are assumed to be packed.  That is, a data element
 685      * at location (x2, y2) would be found at:
 686      * <pre>
 687      *      inData[((y2-y)*w + (x2-x)) + n]
 688      * </pre>
 689      * @param x        The X coordinate of the upper left pixel location.
 690      * @param y        The Y coordinate of the upper left pixel location.
 691      * @param w        Width of the pixel rectangle.
 692      * @param h        Height of the pixel rectangle.
 693      * @param band     The band to set.
 694      * @param inData   The data elements to be stored.
 695      */
 696     public void putByteData(int x, int y, int w, int h,
 697                             int band, byte[] inData) {
 698         // Bounds check for 'band' will be performed automatically
 699         if ((x < this.minX) || (y < this.minY) ||
 700             (x + w > this.maxX) || (y + h > this.maxY)) {
 701             throw new ArrayIndexOutOfBoundsException
 702                 ("Coordinate out of bounds!");
 703         }
 704         int yoff = (y-minY)*scanlineStride +
 705                    (x-minX)*pixelStride + dataOffsets[band];
 706         int xoff;
 707         int off = 0;
 708         int xstart;
 709         int ystart;
 710 
 711         if (pixelStride == 1) {
 712             if (scanlineStride == w) {
 713                 System.arraycopy(inData, 0, data, yoff, w*h);
 714             }
 715             else {
 716                 for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 717                     System.arraycopy(inData, off, data, yoff, w);
 718                     off += w;
 719                 }
 720             }
 721         }
 722         else {
 723             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 724                 xoff = yoff;
 725                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 726                     data[xoff] = inData[off++];
 727                 }
 728             }
 729         }
 730 
 731         markDirty();
 732     }
 733 
 734     /**
 735      * Stores a byte array of data elements into the specified rectangular
 736      * region.
 737      * An ArrayIndexOutOfBounds exception will be thrown at runtime
 738      * if the pixel coordinates are out of bounds.
 739      * The data elements in the
 740      * data array are assumed to be packed.  That is, a data element
 741      * for the nth band at location (x2, y2) would be found at:
 742      * <pre>
 743      *      inData[((y2-y)*w + (x2-x))*numDataElements + n]
 744      * </pre>
 745      * @param x        The X coordinate of the upper left pixel location.
 746      * @param y        The Y coordinate of the upper left pixel location.
 747      * @param w        Width of the pixel rectangle.
 748      * @param h        Height of the pixel rectangle.
 749      * @param inData   The data elements to be stored.
 750      */
 751     public void putByteData(int x, int y, int w, int h, byte[] inData) {
 752         if ((x < this.minX) || (y < this.minY) ||
 753             (x + w > this.maxX) || (y + h > this.maxY)) {
 754             throw new ArrayIndexOutOfBoundsException
 755                 ("Coordinate out of bounds!");
 756         }
 757         int yoff = (y-minY)*scanlineStride +
 758                    (x-minX)*pixelStride;
 759 
 760         int xoff;
 761         int off = 0;
 762         int xstart;
 763         int ystart;
 764 
 765         if (inOrder) {
 766             yoff += dataOffsets[0];
 767             int rowBytes = w*pixelStride;
 768             if (rowBytes == scanlineStride) {
 769                 System.arraycopy(inData, 0, data, yoff, rowBytes*h);
 770             } else {
 771                 for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 772                     System.arraycopy(inData, off, data, yoff, rowBytes);
 773                     off += rowBytes;
 774                 }
 775             }
 776         } else if (numDataElements == 1) {
 777             yoff += dataOffsets[0];
 778             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 779                 xoff = yoff;
 780                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 781                     data[xoff] = inData[off++];
 782                 }
 783             }
 784         } else if (numDataElements == 2) {
 785             yoff += dataOffsets[0];
 786             int d1 = dataOffsets[1] - dataOffsets[0];
 787             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 788                 xoff = yoff;
 789                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 790                     data[xoff] = inData[off++];
 791                     data[xoff + d1] = inData[off++];
 792                 }
 793             }
 794         } else if (numDataElements == 3) {
 795             yoff += dataOffsets[0];
 796             int d1 = dataOffsets[1] - dataOffsets[0];
 797             int d2 = dataOffsets[2] - dataOffsets[0];
 798             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 799                 xoff = yoff;
 800                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 801                     data[xoff] = inData[off++];
 802                     data[xoff + d1] = inData[off++];
 803                     data[xoff + d2] = inData[off++];
 804                 }
 805             }
 806         } else if (numDataElements == 4) {
 807             yoff += dataOffsets[0];
 808             int d1 = dataOffsets[1] - dataOffsets[0];
 809             int d2 = dataOffsets[2] - dataOffsets[0];
 810             int d3 = dataOffsets[3] - dataOffsets[0];
 811             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 812                 xoff = yoff;
 813                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 814                     data[xoff] = inData[off++];
 815                     data[xoff + d1] = inData[off++];
 816                     data[xoff + d2] = inData[off++];
 817                     data[xoff + d3] = inData[off++];
 818                 }
 819             }
 820         } else {
 821             for (ystart=0; ystart < h; ystart++, yoff += scanlineStride) {
 822                 xoff = yoff;
 823                 for (xstart=0; xstart < w; xstart++, xoff += pixelStride) {
 824                     for (int c = 0; c < numDataElements; c++) {
 825                         data[dataOffsets[c] + xoff] = inData[off++];
 826                     }
 827                 }
 828             }
 829         }
 830 
 831         markDirty();
 832     }
 833 
 834     public int getSample(int x, int y, int b) {
 835         if ((x < this.minX) || (y < this.minY) ||
 836             (x >= this.maxX) || (y >= this.maxY)) {
 837             throw new ArrayIndexOutOfBoundsException
 838                 ("Coordinate out of bounds!");
 839         }
 840         if (packed) {
 841             int offset = y*scanlineStride + x + dbOffsetPacked;
 842             byte sample = data[offset];
 843             return (sample & bitMasks[b]) >>> bitOffsets[b];
 844         } else {
 845             int offset = y*scanlineStride + x*pixelStride + dbOffset;
 846             return data[offset + dataOffsets[b]] & 0xff;
 847         }
 848     }
 849 
 850     public void setSample(int x, int y, int b, int s) {
 851         if ((x < this.minX) || (y < this.minY) ||
 852             (x >= this.maxX) || (y >= this.maxY)) {
 853             throw new ArrayIndexOutOfBoundsException
 854                 ("Coordinate out of bounds!");
 855         }
 856         if (packed) {
 857             int offset = y*scanlineStride + x + dbOffsetPacked;
 858             int bitMask = bitMasks[b];
 859 
 860             byte value = data[offset];
 861             value &= ~bitMask;
 862             value |= (s << bitOffsets[b]) & bitMask;
 863             data[offset] = value;
 864         } else {
 865             int offset = y*scanlineStride + x*pixelStride + dbOffset;
 866             data[offset + dataOffsets[b]] = (byte)s;
 867         }
 868 
 869         markDirty();
 870     }
 871 
 872     public int[] getSamples(int x, int y, int w, int h, int b,
 873                             int[] iArray) {
 874         if ((x < this.minX) || (y < this.minY) ||
 875             (x + w > this.maxX) || (y + h > this.maxY)) {
 876             throw new ArrayIndexOutOfBoundsException
 877                 ("Coordinate out of bounds!");
 878         }
 879         int samples[];
 880         if (iArray != null) {
 881             samples = iArray;
 882         } else {
 883             samples = new int [w*h];
 884         }
 885 
 886         int lineOffset = y*scanlineStride + x*pixelStride;
 887         int dstOffset = 0;
 888 
 889         if (packed) {
 890             lineOffset += dbOffsetPacked;
 891             int bitMask = bitMasks[b];
 892             int bitOffset = bitOffsets[b];
 893 
 894             for (int j = 0; j < h; j++) {
 895                 int sampleOffset = lineOffset;
 896                 for (int i = 0; i < w; i++) {
 897                     int value = data[sampleOffset++];
 898                     samples[dstOffset++] = ((value & bitMask) >>> bitOffset);
 899                 }
 900                 lineOffset += scanlineStride;
 901             }
 902         } else {
 903             lineOffset += dbOffset + dataOffsets[b];
 904             for (int j = 0; j < h; j++) {
 905                 int sampleOffset = lineOffset;
 906                 for (int i = 0; i < w; i++) {
 907                     samples[dstOffset++] = data[sampleOffset] & 0xff;
 908                     sampleOffset += pixelStride;
 909                 }
 910                 lineOffset += scanlineStride;
 911             }
 912         }
 913 
 914         return samples;
 915     }
 916 
 917     public void setSamples(int x, int y, int w, int h, int b, int iArray[]) {
 918         if ((x < this.minX) || (y < this.minY) ||
 919             (x + w > this.maxX) || (y + h > this.maxY)) {
 920             throw new ArrayIndexOutOfBoundsException
 921                 ("Coordinate out of bounds!");
 922         }
 923         int lineOffset = y*scanlineStride + x*pixelStride;
 924         int srcOffset = 0;
 925 
 926         if (packed) {
 927             lineOffset += dbOffsetPacked;
 928             int bitMask = bitMasks[b];
 929 
 930             for (int j = 0; j < h; j++) {
 931                 int sampleOffset = lineOffset;
 932                 for (int i = 0; i < w; i++) {
 933                     byte value = data[sampleOffset];
 934                     value &= ~bitMask;
 935                     int sample = iArray[srcOffset++];
 936                     value |= (sample << bitOffsets[b]) & bitMask;
 937                     data[sampleOffset++] = value;
 938                 }
 939                 lineOffset += scanlineStride;
 940             }
 941         } else {
 942             lineOffset += dbOffset + dataOffsets[b];
 943             for (int i = 0; i < h; i++) {
 944                 int sampleOffset = lineOffset;
 945                 for (int j = 0; j < w; j++) {
 946                     data[sampleOffset] = (byte)iArray[srcOffset++];
 947                     sampleOffset += pixelStride;
 948                 }
 949                 lineOffset += scanlineStride;
 950             }
 951         }
 952 
 953         markDirty();
 954     }
 955 
 956     public int[] getPixels(int x, int y, int w, int h, int[] iArray) {
 957         if ((x < this.minX) || (y < this.minY) ||
 958             (x + w > this.maxX) || (y + h > this.maxY)) {
 959             throw new ArrayIndexOutOfBoundsException
 960                 ("Coordinate out of bounds!");
 961         }
 962         int pixels[];
 963         if (iArray != null) {
 964             pixels = iArray;
 965         } else {
 966             pixels = new int[w*h*numBands];
 967         }
 968 
 969         int lineOffset = y*scanlineStride + x*pixelStride;
 970         int dstOffset = 0;
 971 
 972         if (packed) {
 973             lineOffset += dbOffsetPacked;
 974             for (int j = 0; j < h; j++) {
 975                 for (int i = 0; i < w; i++) {
 976                     int value = data[lineOffset + i];
 977                     for (int k = 0; k < numBands; k++) {
 978                         pixels[dstOffset++] =
 979                             (value & bitMasks[k]) >>> bitOffsets[k];
 980                     }
 981                 }
 982                 lineOffset += scanlineStride;
 983             }
 984         } else {
 985             lineOffset += dbOffset;
 986             int d0 = dataOffsets[0];
 987 
 988             if (numBands == 1) {
 989                 for (int j = 0; j < h; j++) {
 990                     int pixelOffset = lineOffset + d0;
 991                     for (int i = 0; i < w; i++) {
 992                         pixels[dstOffset++] = data[pixelOffset] & 0xff;
 993                         pixelOffset += pixelStride;
 994                     }
 995                     lineOffset += scanlineStride;
 996                 }
 997             } else if (numBands == 2) {
 998                 int d1 = dataOffsets[1] - d0;
 999                 for (int j = 0; j < h; j++) {
1000                     int pixelOffset = lineOffset + d0;
1001                     for (int i = 0; i < w; i++) {
1002                         pixels[dstOffset++] = data[pixelOffset] & 0xff;
1003                         pixels[dstOffset++] = data[pixelOffset + d1] & 0xff;
1004                         pixelOffset += pixelStride;
1005                     }
1006                     lineOffset += scanlineStride;
1007                 }
1008             } else if (numBands == 3) {
1009                 int d1 = dataOffsets[1] - d0;
1010                 int d2 = dataOffsets[2] - d0;
1011                 for (int j = 0; j < h; j++) {
1012                     int pixelOffset = lineOffset + d0;
1013                     for (int i = 0; i < w; i++) {
1014                         pixels[dstOffset++] = data[pixelOffset] & 0xff;
1015                         pixels[dstOffset++] = data[pixelOffset + d1] & 0xff;
1016                         pixels[dstOffset++] = data[pixelOffset + d2] & 0xff;
1017                         pixelOffset += pixelStride;
1018                     }
1019                     lineOffset += scanlineStride;
1020                 }
1021             } else if (numBands == 4) {
1022                 int d1 = dataOffsets[1] - d0;
1023                 int d2 = dataOffsets[2] - d0;
1024                 int d3 = dataOffsets[3] - d0;
1025                 for (int j = 0; j < h; j++) {
1026                     int pixelOffset = lineOffset + d0;
1027                     for (int i = 0; i < w; i++) {
1028                         pixels[dstOffset++] = data[pixelOffset] & 0xff;
1029                         pixels[dstOffset++] = data[pixelOffset + d1] & 0xff;
1030                         pixels[dstOffset++] = data[pixelOffset + d2] & 0xff;
1031                         pixels[dstOffset++] = data[pixelOffset + d3] & 0xff;
1032                         pixelOffset += pixelStride;
1033                     }
1034                     lineOffset += scanlineStride;
1035                 }
1036             } else {
1037                 for (int j = 0; j < h; j++) {
1038                     int pixelOffset = lineOffset;
1039                     for (int i = 0; i < w; i++) {
1040                         for (int k = 0; k < numBands; k++) {
1041                             pixels[dstOffset++] =
1042                                 data[pixelOffset + dataOffsets[k]] & 0xff;
1043                         }
1044                         pixelOffset += pixelStride;
1045                     }
1046                     lineOffset += scanlineStride;
1047                 }
1048             }
1049         }
1050 
1051         return pixels;
1052     }
1053 
1054     public void setPixels(int x, int y, int w, int h, int[] iArray) {
1055         if ((x < this.minX) || (y < this.minY) ||
1056             (x + w > this.maxX) || (y + h > this.maxY)) {
1057             throw new ArrayIndexOutOfBoundsException
1058                 ("Coordinate out of bounds!");
1059         }
1060         int lineOffset = y*scanlineStride + x*pixelStride;
1061         int srcOffset = 0;
1062 
1063         if (packed) {
1064             lineOffset += dbOffsetPacked;
1065             for (int j = 0; j < h; j++) {
1066                 for (int i = 0; i < w; i++) {
1067                     int value = 0;
1068                     for (int k = 0; k < numBands; k++) {
1069                         int srcValue = iArray[srcOffset++];
1070                         value |= ((srcValue << bitOffsets[k])
1071                                   & bitMasks[k]);
1072                     }
1073                     data[lineOffset + i] = (byte)value;
1074                 }
1075                 lineOffset += scanlineStride;
1076             }
1077         } else {
1078             lineOffset += dbOffset;
1079             int d0 = dataOffsets[0];
1080 
1081             if (numBands == 1) {
1082                 for (int j = 0; j < h; j++) {
1083                     int pixelOffset = lineOffset + d0;
1084                     for (int i = 0; i < w; i++) {
1085                         data[pixelOffset] = (byte)iArray[srcOffset++];
1086                         pixelOffset += pixelStride;
1087                     }
1088                     lineOffset += scanlineStride;
1089                 }
1090             } else if (numBands == 2) {
1091                 int d1 = dataOffsets[1] - d0;
1092                 for (int j = 0; j < h; j++) {
1093                     int pixelOffset = lineOffset + d0;
1094                     for (int i = 0; i < w; i++) {
1095                         data[pixelOffset] = (byte)iArray[srcOffset++];
1096                         data[pixelOffset + d1] = (byte)iArray[srcOffset++];
1097                         pixelOffset += pixelStride;
1098                     }
1099                     lineOffset += scanlineStride;
1100                 }
1101             } else if (numBands == 3) {
1102                 int d1 = dataOffsets[1] - d0;
1103                 int d2 = dataOffsets[2] - d0;
1104                 for (int j = 0; j < h; j++) {
1105                     int pixelOffset = lineOffset + d0;
1106                     for (int i = 0; i < w; i++) {
1107                         data[pixelOffset] = (byte)iArray[srcOffset++];
1108                         data[pixelOffset + d1] = (byte)iArray[srcOffset++];
1109                         data[pixelOffset + d2] = (byte)iArray[srcOffset++];
1110                         pixelOffset += pixelStride;
1111                     }
1112                     lineOffset += scanlineStride;
1113                 }
1114             } else if (numBands == 4) {
1115                 int d1 = dataOffsets[1] - d0;
1116                 int d2 = dataOffsets[2] - d0;
1117                 int d3 = dataOffsets[3] - d0;
1118                 for (int j = 0; j < h; j++) {
1119                     int pixelOffset = lineOffset + d0;
1120                     for (int i = 0; i < w; i++) {
1121                         data[pixelOffset] = (byte)iArray[srcOffset++];
1122                         data[pixelOffset + d1] = (byte)iArray[srcOffset++];
1123                         data[pixelOffset + d2] = (byte)iArray[srcOffset++];
1124                         data[pixelOffset + d3] = (byte)iArray[srcOffset++];
1125                         pixelOffset += pixelStride;
1126                     }
1127                     lineOffset += scanlineStride;
1128                 }
1129             } else {
1130                 for (int j = 0; j < h; j++) {
1131                     int pixelOffset = lineOffset;
1132                     for (int i = 0; i < w; i++) {
1133                         for (int k = 0; k < numBands; k++) {
1134                             data[pixelOffset + dataOffsets[k]] =
1135                                 (byte)iArray[srcOffset++];
1136                         }
1137                         pixelOffset += pixelStride;
1138                     }
1139                     lineOffset += scanlineStride;
1140                 }
1141             }
1142         }
1143 
1144         markDirty();
1145     }
1146 
1147     public void setRect(int dx, int dy, Raster srcRaster) {
1148         if (!(srcRaster instanceof ByteInterleavedRaster)) {
1149             super.setRect(dx, dy, srcRaster);
1150             return;
1151         }
1152 
1153         int width  = srcRaster.getWidth();
1154         int height = srcRaster.getHeight();
1155         int srcOffX = srcRaster.getMinX();
1156         int srcOffY = srcRaster.getMinY();
1157         int dstOffX = dx+srcOffX;
1158         int dstOffY = dy+srcOffY;
1159 
1160         // Clip to this raster
1161         if (dstOffX < this.minX) {
1162             int skipX = minX - dstOffX;
1163             width -= skipX;
1164             srcOffX += skipX;
1165             dstOffX = this.minX;
1166         }
1167         if (dstOffY < this.minY) {
1168             int skipY = this.minY - dstOffY;
1169             height -= skipY;
1170             srcOffY += skipY;
1171             dstOffY = this.minY;
1172         }
1173         if (dstOffX+width > this.maxX) {
1174             width = this.maxX - dstOffX;
1175         }
1176         if (dstOffY+height > this.maxY) {
1177             height = this.maxY - dstOffY;
1178         }
1179 
1180         setDataElements(dstOffX, dstOffY,
1181                         srcOffX, srcOffY,
1182                         width, height, srcRaster);
1183     }
1184 
1185 
1186     /**
1187      * Creates a subraster given a region of the raster.  The x and y
1188      * coordinates specify the horizontal and vertical offsets
1189      * from the upper-left corner of this raster to the upper-left corner
1190      * of the subraster.  A subset of the bands of the parent Raster may
1191      * be specified.  If this is null, then all the bands are present in the
1192      * subRaster. A translation to the subRaster may also be specified.
1193      * Note that the subraster will reference the same
1194      * DataBuffer as the parent raster, but using different offsets.
1195      * @param x               X offset.
1196      * @param y               Y offset.
1197      * @param width           Width (in pixels) of the subraster.
1198      * @param height          Height (in pixels) of the subraster.
1199      * @param x0              Translated X origin of the subraster.
1200      * @param y0              Translated Y origin of the subraster.
1201      * @param bandList        Array of band indices.
1202      * @exception RasterFormatException
1203      *            if the specified bounding box is outside of the parent raster.
1204      */
1205     public Raster createChild(int x, int y,
1206                               int width, int height,
1207                               int x0, int y0, int[] bandList) {
1208         WritableRaster newRaster = createWritableChild(x, y,
1209                                                        width, height,
1210                                                        x0, y0,
1211                                                        bandList);
1212         return (Raster) newRaster;
1213     }
1214 
1215     /**
1216      * Creates a Writable subRaster given a region of the Raster. The x and y
1217      * coordinates specify the horizontal and vertical offsets
1218      * from the upper-left corner of this Raster to the upper-left corner
1219      * of the subRaster.  A subset of the bands of the parent Raster may
1220      * be specified.  If this is null, then all the bands are present in the
1221      * subRaster. A translation to the subRaster may also be specified.
1222      * Note that the subRaster will reference the same
1223      * DataBuffer as the parent Raster, but using different offsets.
1224      * @param x               X offset.
1225      * @param y               Y offset.
1226      * @param width           Width (in pixels) of the subraster.
1227      * @param height          Height (in pixels) of the subraster.
1228      * @param x0              Translated X origin of the subraster.
1229      * @param y0              Translated Y origin of the subraster.
1230      * @param bandList        Array of band indices.
1231      * @exception RasterFormatException
1232      *            if the specified bounding box is outside of the parent Raster.
1233      */
1234     public WritableRaster createWritableChild(int x, int y,
1235                                               int width, int height,
1236                                               int x0, int y0,
1237                                               int[] bandList) {
1238         if (x < this.minX) {
1239             throw new RasterFormatException("x lies outside the raster");
1240         }
1241         if (y < this.minY) {
1242             throw new RasterFormatException("y lies outside the raster");
1243         }
1244         if ((x+width < x) || (x+width > this.minX + this.width)) {
1245             throw new RasterFormatException("(x + width) is outside of Raster");
1246         }
1247         if ((y+height < y) || (y+height > this.minY + this.height)) {
1248             throw new RasterFormatException("(y + height) is outside of Raster");
1249         }
1250 
1251         SampleModel sm;
1252 
1253         if (bandList != null)
1254             sm = sampleModel.createSubsetSampleModel(bandList);
1255         else
1256             sm = sampleModel;
1257 
1258         int deltaX = x0 - x;
1259         int deltaY = y0 - y;
1260 
1261         return new ByteInterleavedRaster(sm,
1262                                        dataBuffer,
1263                                        new Rectangle(x0, y0, width, height),
1264                                        new Point(sampleModelTranslateX+deltaX,
1265                                                  sampleModelTranslateY+deltaY),
1266                                        this);
1267     }
1268 
1269     /**
1270      * Creates a Raster with the same layout but using a different
1271      * width and height, and with new zeroed data arrays.
1272      */
1273     public WritableRaster createCompatibleWritableRaster(int w, int h) {
1274         if (w <= 0 || h <=0) {
1275             throw new RasterFormatException("negative "+
1276                                           ((w <= 0) ? "width" : "height"));
1277         }
1278 
1279         SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
1280 
1281         return new ByteInterleavedRaster(sm, new Point(0,0));
1282 
1283     }
1284 
1285     /**
1286      * Creates a Raster with the same layout and the same
1287      * width and height, and with new zeroed data arrays.  If
1288      * the Raster is a subRaster, this will call
1289      * createCompatibleRaster(width, height).
1290      */
1291     public WritableRaster createCompatibleWritableRaster() {
1292         return createCompatibleWritableRaster(width,height);
1293     }
1294 
1295     public String toString() {
1296         return new String ("ByteInterleavedRaster: width = "+width+" height = "
1297                            + height
1298                            +" #numDataElements "+numDataElements
1299                            //  +" xOff = "+xOffset+" yOff = "+yOffset
1300                            +" dataOff[0] = "+dataOffsets[0]);
1301     }
1302 
1303 //    /**
1304 //     * For debugging...  prints a region of a one-band ByteInterleavedRaster
1305 //     */
1306 //    public void print(int x, int y, int w, int h) {
1307 //        // REMIND:  Only works for 1 band!
1308 //        System.out.println(this);
1309 //        int offset = dataOffsets[0] + y*scanlineStride + x*pixelStride;
1310 //        int off;
1311 //        for (int yoff=0; yoff < h; yoff++, offset += scanlineStride) {
1312 //            off = offset;
1313 //            System.out.print("Line "+(y+yoff)+": ");
1314 //            for (int xoff = 0; xoff < w; xoff++, off+= pixelStride) {
1315 //                String s = Integer.toHexString(data[off]);
1316 //                if (s.length() == 8) {
1317 //                    s = s.substring(6,8);
1318 //                }
1319 //                System.out.print(s+" ");
1320 //            }
1321 //            System.out.println("");
1322 //        }
1323 //    }
1324 }