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