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