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