View Javadoc
1   /*
2    * Copyright (c) 1997, 2013, 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.MultiPixelPackedSampleModel;
32  import java.awt.image.DataBuffer;
33  import java.awt.image.DataBufferByte;
34  import java.awt.Rectangle;
35  import java.awt.Point;
36  
37  /**
38   * This class is useful for describing 1, 2, or 4 bit image data
39   * elements.  This raster has one band whose pixels are packed
40   * together into individual bytes in a single byte array.  This type
41   * of raster can be used with an IndexColorModel. This raster uses a
42   * MultiPixelPackedSampleModel.
43   *
44   */
45  public class BytePackedRaster extends SunWritableRaster {
46  
47      /** The data bit offset for each pixel. */
48      int           dataBitOffset;
49  
50      /** Scanline stride of the image data contained in this Raster. */
51      int           scanlineStride;
52  
53      /**
54       * The bit stride of a pixel, equal to the total number of bits
55       * required to store a pixel.
56       */
57      int           pixelBitStride;
58  
59      /** The bit mask for extracting the pixel. */
60      int           bitMask;
61  
62      /** The image data array. */
63      byte[]        data;
64  
65      /** 8 minus the pixel bit stride. */
66      int shiftOffset;
67  
68      int type;
69  
70      /** A cached copy of minX + width for use in bounds checks. */
71      private int maxX;
72  
73      /** A cached copy of minY + height for use in bounds checks. */
74      private int maxY;
75  
76      static private native void initIDs();
77      static {
78          /* ensure that the necessary native libraries are loaded */
79          NativeLibLoader.loadLibraries();
80          initIDs();
81      }
82  
83      /**
84       * Constructs a BytePackedRaster with the given SampleModel.
85       * The Raster's upper left corner is origin and it is the same
86       * size as the SampleModel.  A DataBuffer large enough to describe the
87       * Raster is automatically created.  SampleModel must be of type
88       * MultiPixelPackedSampleModel.
89       * @param sampleModel     The SampleModel that specifies the layout.
90       * @param origin          The Point that specified the origin.
91       */
92      public BytePackedRaster(SampleModel sampleModel,
93                              Point origin) {
94          this(sampleModel,
95               sampleModel.createDataBuffer(),
96               new Rectangle(origin.x,
97                             origin.y,
98                             sampleModel.getWidth(),
99                             sampleModel.getHeight()),
100              origin,
101              null);
102     }
103 
104     /**
105      * Constructs a BytePackedRaster with the given SampleModel
106      * and DataBuffer.  The Raster's upper left corner is origin and
107      * it is the same size as the SampleModel.  The DataBuffer is not
108      * initialized and must be a DataBufferByte compatible with SampleModel.
109      * SampleModel must be of type MultiPixelPackedSampleModel.
110      * @param sampleModel     The SampleModel that specifies the layout.
111      * @param dataBuffer      The DataBufferShort that contains the image data.
112      * @param origin          The Point that specifies the origin.
113      */
114     public BytePackedRaster(SampleModel sampleModel,
115                             DataBuffer dataBuffer,
116                             Point origin) {
117         this(sampleModel,
118              dataBuffer,
119              new Rectangle(origin.x,
120                            origin.y,
121                            sampleModel.getWidth(),
122                            sampleModel.getHeight()),
123              origin,
124              null);
125     }
126 
127     /**
128      * Constructs a BytePackedRaster with the given SampleModel,
129      * DataBuffer, and parent.  DataBuffer must be a DataBufferByte and
130      * SampleModel must be of type MultiPixelPackedSampleModel.
131      * When translated into the base Raster's
132      * coordinate system, aRegion must be contained by the base Raster.
133      * Origin is the coordinate in the new Raster's coordinate system of
134      * the origin of the base Raster.  (The base Raster is the Raster's
135      * ancestor which has no parent.)
136      *
137      * Note that this constructor should generally be called by other
138      * constructors or create methods, it should not be used directly.
139      * @param sampleModel     The SampleModel that specifies the layout.
140      * @param dataBuffer      The DataBufferShort that contains the image data.
141      * @param aRegion         The Rectangle that specifies the image area.
142      * @param origin          The Point that specifies the origin.
143      * @param parent          The parent (if any) of this raster.
144      *
145      * @exception RasterFormatException if the parameters do not conform
146      * to requirements of this Raster type.
147      */
148     public BytePackedRaster(SampleModel sampleModel,
149                             DataBuffer dataBuffer,
150                             Rectangle aRegion,
151                             Point origin,
152                             BytePackedRaster parent){
153         super(sampleModel,dataBuffer,aRegion,origin, parent);
154         this.maxX = minX + width;
155         this.maxY = minY + height;
156 
157         if (!(dataBuffer instanceof DataBufferByte)) {
158            throw new RasterFormatException("BytePackedRasters must have" +
159                 "byte DataBuffers");
160         }
161         DataBufferByte dbb = (DataBufferByte)dataBuffer;
162         this.data = stealData(dbb, 0);
163         if (dbb.getNumBanks() != 1) {
164             throw new
165                 RasterFormatException("DataBuffer for BytePackedRasters"+
166                                       " must only have 1 bank.");
167         }
168         int dbOffset = dbb.getOffset();
169 
170         if (sampleModel instanceof MultiPixelPackedSampleModel) {
171             MultiPixelPackedSampleModel mppsm =
172                 (MultiPixelPackedSampleModel)sampleModel;
173             this.type = IntegerComponentRaster.TYPE_BYTE_BINARY_SAMPLES;
174             pixelBitStride = mppsm.getPixelBitStride();
175             if (pixelBitStride != 1 &&
176                 pixelBitStride != 2 &&
177                 pixelBitStride != 4) {
178                 throw new RasterFormatException
179                   ("BytePackedRasters must have a bit depth of 1, 2, or 4");
180             }
181             scanlineStride = mppsm.getScanlineStride();
182             dataBitOffset = mppsm.getDataBitOffset() + dbOffset*8;
183             int xOffset = aRegion.x - origin.x;
184             int yOffset = aRegion.y - origin.y;
185             dataBitOffset += xOffset*pixelBitStride + yOffset*scanlineStride*8;
186             bitMask = (1 << pixelBitStride) -1;
187             shiftOffset = 8 - pixelBitStride;
188         } else {
189             throw new RasterFormatException("BytePackedRasters must have"+
190                 "MultiPixelPackedSampleModel");
191         }
192         verify(false);
193     }
194 
195     /**
196      * Returns the data bit offset for the Raster.  The data
197      * bit offset is the bit index into the data array element
198      * corresponding to the first sample of the first scanline.
199      */
200     public int getDataBitOffset() {
201         return dataBitOffset;
202     }
203 
204     /**
205      * Returns the scanline stride -- the number of data array elements between
206      * a given sample and the sample in the same column
207      * of the next row.
208      */
209     public int getScanlineStride() {
210         return scanlineStride;
211     }
212 
213     /**
214      * Returns pixel bit stride -- the number of bits between two
215      * samples on the same scanline.
216      */
217     public int getPixelBitStride() {
218         return pixelBitStride;
219     }
220 
221     /**
222      * Returns a reference to the entire data array.
223      */
224     public byte[] getDataStorage() {
225         return data;
226     }
227 
228     /**
229      * Returns the data element at the specified
230      * location.
231      * An ArrayIndexOutOfBounds exception will be thrown at runtime
232      * if the pixel coordinate is out of bounds.
233      * A ClassCastException will be thrown if the input object is non null
234      * and references anything other than an array of transferType.
235      * @param x        The X coordinate of the pixel location.
236      * @param y        The Y coordinate of the pixel location.
237      * @param outData  An object reference to an array of type defined by
238      *                 getTransferType() and length getNumDataElements().
239      *                 If null an array of appropriate type and size will be
240      *                 allocated.
241      * @return         An object reference to an array of type defined by
242      *                 getTransferType() with the request pixel data.
243      */
244     public Object getDataElements(int x, int y, Object obj) {
245         if ((x < this.minX) || (y < this.minY) ||
246             (x >= this.maxX) || (y >= this.maxY)) {
247             throw new ArrayIndexOutOfBoundsException
248                 ("Coordinate out of bounds!");
249         }
250         byte outData[];
251         if (obj == null) {
252             outData = new byte[numDataElements];
253         } else {
254             outData = (byte[])obj;
255         }
256         int bitnum = dataBitOffset + (x-minX) * pixelBitStride;
257         // Fix 4184283
258         int element = data[(y-minY) * scanlineStride + (bitnum >> 3)] & 0xff;
259         int shift = shiftOffset - (bitnum & 7);
260         outData[0] = (byte)((element >> shift) & bitMask);
261         return outData;
262     }
263 
264     /**
265      * Returns the pixel data for the specified rectangle of pixels in a
266      * primitive array of type TransferType.
267      * For image data supported by the Java 2D API, this
268      * will be one of DataBuffer.TYPE_BYTE, DataBuffer.TYPE_USHORT, or
269      * DataBuffer.TYPE_INT.  Data may be returned in a packed format,
270      * thus increasing efficiency for data transfers.
271      *
272      * An ArrayIndexOutOfBoundsException may be thrown
273      * if the coordinates are not in bounds.
274      * A ClassCastException will be thrown if the input object is non null
275      * and references anything other than an array of TransferType.
276      * @see java.awt.image.SampleModel#getDataElements(int, int, int, int, Object, DataBuffer)
277      * @param x        The X coordinate of the upper left pixel location.
278      * @param y        The Y coordinate of the upper left pixel location.
279      * @param w        Width of the pixel rectangle.
280      * @param h        Height of the pixel rectangle.
281      * @param outData  An object reference to an array of type defined by
282      *                 getTransferType() and length w*h*getNumDataElements().
283      *                 If null, an array of appropriate type and size will be
284      *                 allocated.
285      * @return         An object reference to an array of type defined by
286      *                 getTransferType() with the requested pixel data.
287      */
288     public Object getDataElements(int x, int y, int w, int h,
289                                   Object outData) {
290         return getByteData(x, y, w, h, (byte[])outData);
291     }
292 
293     /**
294      * Returns an array  of data elements from the specified rectangular
295      * region.
296      *
297      * An ArrayIndexOutOfBounds exception will be thrown at runtime
298      * if the pixel coordinates are 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      * <pre>
302      *       byte[] bandData = (byte[])raster.getPixelData(x, y, w, h, null);
303      *       int pixel;
304      *       // To find a data element at location (x2, y2)
305      *       pixel = bandData[((y2-y)*w + (x2-x))];
306      * </pre>
307      * @param x        The X coordinate of the upper left pixel location.
308      * @param y        The Y coordinate of the upper left pixel location.
309      * @param width    Width of the pixel rectangle.
310      * @param height   Height of the pixel rectangle.
311      * @param outData  An object reference to an array of type defined by
312      *                 getTransferType() and length w*h*getNumDataElements().
313      *                 If null an array of appropriate type and size will be
314      *                 allocated.
315      * @return         An object reference to an array of type defined by
316      *                 getTransferType() with the request pixel data.
317      */
318     public Object getPixelData(int x, int y, int w, int h, Object obj) {
319         if ((x < this.minX) || (y < this.minY) ||
320             (x + w > this.maxX) || (y + h > this.maxY)) {
321             throw new ArrayIndexOutOfBoundsException
322                 ("Coordinate out of bounds!");
323         }
324         byte outData[];
325         if (obj == null) {
326             outData = new byte[numDataElements*w*h];
327         } else {
328             outData = (byte[])obj;
329         }
330         int pixbits = pixelBitStride;
331         int scanbit = dataBitOffset + (x-minX) * pixbits;
332         int index = (y-minY) * scanlineStride;
333         int outindex = 0;
334         byte data[] = this.data;
335 
336         for (int j = 0; j < h; j++) {
337             int bitnum = scanbit;
338             for (int i = 0; i < w; i++) {
339                 int shift = shiftOffset - (bitnum & 7);
340                 outData[outindex++] =
341                     (byte)(bitMask & (data[index + (bitnum >> 3)] >> shift));
342                 bitnum += pixbits;
343             }
344             index += scanlineStride;
345         }
346         return outData;
347     }
348 
349     /**
350      * Returns a byte array containing the specified data elements
351      * from the data array.  The band index will be ignored.
352      * An ArrayIndexOutOfBounds exception will be thrown at runtime
353      * if the pixel coordinates are out of bounds.
354      * <pre>
355      *       byte[] byteData = getByteData(x, y, band, w, h, null);
356      *       // To find a data element at location (x2, y2)
357      *       byte element = byteData[(y2-y)*w + (x2-x)];
358      * </pre>
359      * @param x        The X coordinate of the upper left pixel location.
360      * @param y        The Y coordinate of the upper left pixel location.
361      * @param width    Width of the pixel rectangle.
362      * @param height   Height of the pixel rectangle.
363      * @param band     The band to return, is ignored.
364      * @param outData  If non-null, data elements
365      *                 at the specified locations are returned in this array.
366      * @return         Byte array with data elements.
367      */
368     public byte[] getByteData(int x, int y, int w, int h,
369                               int band, byte[] outData) {
370         return getByteData(x, y, w, h, outData);
371     }
372 
373     /**
374      * Returns a byte array containing the specified data elements
375      * from the data array.
376      * An ArrayIndexOutOfBounds exception will be thrown at runtime
377      * if the pixel coordinates are out of bounds.
378      * <pre>
379      *       byte[] byteData = raster.getByteData(x, y, w, h, null);
380      *       byte pixel;
381      *       // To find a data element at location (x2, y2)
382      *       pixel = byteData[((y2-y)*w + (x2-x))];
383      * </pre>
384      * @param x        The X coordinate of the upper left pixel location.
385      * @param y        The Y coordinate of the upper left pixel location.
386      * @param width    Width of the pixel rectangle.
387      * @param height   Height of the pixel rectangle.
388      * @param outData  If non-null, data elements
389      *                 at the specified locations are returned in this array.
390      * @return         Byte array with data elements.
391      */
392     public byte[] getByteData(int x, int y, int w, int h, byte[] outData) {
393         if ((x < this.minX) || (y < this.minY) ||
394             (x + w > this.maxX) || (y + h > this.maxY)) {
395             throw new ArrayIndexOutOfBoundsException
396                 ("Coordinate out of bounds!");
397         }
398         if (outData == null) {
399             outData = new byte[w * h];
400         }
401         int pixbits = pixelBitStride;
402         int scanbit = dataBitOffset + (x-minX) * pixbits;
403         int index = (y-minY) * scanlineStride;
404         int outindex = 0;
405         byte data[] = this.data;
406 
407         for (int j = 0; j < h; j++) {
408             int bitnum = scanbit;
409             int element;
410 
411             // Process initial portion of scanline
412             int i = 0;
413             while ((i < w) && ((bitnum & 7) != 0)) {
414                 int shift = shiftOffset - (bitnum & 7);
415                 outData[outindex++] =
416                     (byte)(bitMask & (data[index + (bitnum >> 3)] >> shift));
417                 bitnum += pixbits;
418                 i++;
419             }
420 
421             // Process central portion of scanline 8 pixels at a time
422             int inIndex = index + (bitnum >> 3);
423             switch (pixbits) {
424             case 1:
425                 for (; i < w - 7; i += 8) {
426                     element = data[inIndex++];
427                     outData[outindex++] = (byte)((element >> 7) & 1);
428                     outData[outindex++] = (byte)((element >> 6) & 1);
429                     outData[outindex++] = (byte)((element >> 5) & 1);
430                     outData[outindex++] = (byte)((element >> 4) & 1);
431                     outData[outindex++] = (byte)((element >> 3) & 1);
432                     outData[outindex++] = (byte)((element >> 2) & 1);
433                     outData[outindex++] = (byte)((element >> 1) & 1);
434                     outData[outindex++] = (byte)(element & 1);
435                     bitnum += 8;
436                 }
437                 break;
438 
439             case 2:
440                 for (; i < w - 7; i += 8) {
441                     element = data[inIndex++];
442                     outData[outindex++] = (byte)((element >> 6) & 3);
443                     outData[outindex++] = (byte)((element >> 4) & 3);
444                     outData[outindex++] = (byte)((element >> 2) & 3);
445                     outData[outindex++] = (byte)(element & 3);
446 
447                     element = data[inIndex++];
448                     outData[outindex++] = (byte)((element >> 6) & 3);
449                     outData[outindex++] = (byte)((element >> 4) & 3);
450                     outData[outindex++] = (byte)((element >> 2) & 3);
451                     outData[outindex++] = (byte)(element & 3);
452 
453                     bitnum += 16;
454                 }
455                 break;
456 
457             case 4:
458                 for (; i < w - 7; i += 8) {
459                     element = data[inIndex++];
460                     outData[outindex++] = (byte)((element >> 4) & 0xf);
461                     outData[outindex++] = (byte)(element & 0xf);
462 
463                     element = data[inIndex++];
464                     outData[outindex++] = (byte)((element >> 4) & 0xf);
465                     outData[outindex++] = (byte)(element & 0xf);
466 
467                     element = data[inIndex++];
468                     outData[outindex++] = (byte)((element >> 4) & 0xf);
469                     outData[outindex++] = (byte)(element & 0xf);
470 
471                     element = data[inIndex++];
472                     outData[outindex++] = (byte)((element >> 4) & 0xf);
473                     outData[outindex++] = (byte)(element & 0xf);
474 
475                     bitnum += 32;
476                 }
477                 break;
478             }
479 
480             // Process final portion of scanline
481             for (; i < w; i++) {
482                 int shift = shiftOffset - (bitnum & 7);
483                 outData[outindex++] =
484                     (byte) (bitMask & (data[index + (bitnum >> 3)] >> shift));
485                 bitnum += pixbits;
486             }
487 
488             index += scanlineStride;
489         }
490 
491         return outData;
492     }
493 
494     /**
495      * Stores the data elements at the specified location.
496      * An ArrayIndexOutOfBounds exception will be thrown at runtime
497      * if the pixel coordinate is out of bounds.
498      * A ClassCastException will be thrown if the input object is non null
499      * and references anything other than an array of transferType.
500      * @param x        The X coordinate of the pixel location.
501      * @param y        The Y coordinate of the pixel location.
502      * @param inData   An object reference to an array of type defined by
503      *                 getTransferType() and length getNumDataElements()
504      *                 containing the pixel data to place at x,y.
505      */
506     public void setDataElements(int x, int y, Object obj) {
507         if ((x < this.minX) || (y < this.minY) ||
508             (x >= this.maxX) || (y >= this.maxY)) {
509             throw new ArrayIndexOutOfBoundsException
510                 ("Coordinate out of bounds!");
511         }
512         byte inData[] = (byte[])obj;
513         int bitnum = dataBitOffset + (x-minX) * pixelBitStride;
514         int index = (y-minY) * scanlineStride + (bitnum >> 3);
515         int shift = shiftOffset - (bitnum & 7);
516 
517         byte element = data[index];
518         element &= ~(bitMask << shift);
519         element |= (inData[0] & bitMask) << shift;
520         data[index] = element;
521 
522         markDirty();
523     }
524 
525     /**
526      * Stores the Raster data at the specified location.
527      * An ArrayIndexOutOfBounds exception will be thrown at runtime
528      * if the pixel coordinates are out of bounds.
529      * @param x          The X coordinate of the pixel location.
530      * @param y          The Y coordinate of the pixel location.
531      * @param inRaster   Raster of data to place at x,y location.
532      */
533     public void setDataElements(int x, int y, Raster inRaster) {
534         // Check if we can use fast code
535         if (!(inRaster instanceof BytePackedRaster) ||
536             ((BytePackedRaster)inRaster).pixelBitStride != pixelBitStride) {
537             super.setDataElements(x, y, inRaster);
538             return;
539         }
540 
541         int srcOffX = inRaster.getMinX();
542         int srcOffY = inRaster.getMinY();
543         int dstOffX = srcOffX + x;
544         int dstOffY = srcOffY + y;
545         int width = inRaster.getWidth();
546         int height = inRaster.getHeight();
547         if ((dstOffX < this.minX) || (dstOffY < this.minY) ||
548             (dstOffX + width > this.maxX) || (dstOffY + height > this.maxY)) {
549             throw new ArrayIndexOutOfBoundsException
550                 ("Coordinate out of bounds!");
551         }
552         setDataElements(dstOffX, dstOffY,
553                         srcOffX, srcOffY,
554                         width, height,
555                         (BytePackedRaster)inRaster);
556     }
557 
558     /**
559      * Stores the Raster data at the specified location.
560      * @param dstX The absolute X coordinate of the destination pixel
561      * that will receive a copy of the upper-left pixel of the
562      * inRaster
563      * @param dstY The absolute Y coordinate of the destination pixel
564      * that will receive a copy of the upper-left pixel of the
565      * inRaster
566      * @param srcX The absolute X coordinate of the upper-left source
567      * pixel that will be copied into this Raster
568      * @param srcY The absolute Y coordinate of the upper-left source
569      * pixel that will be copied into this Raster
570      * @param width      The number of pixels to store horizontally
571      * @param height     The number of pixels to store vertically
572      * @param inRaster   BytePackedRaster of data to place at x,y location.
573      */
574     private void setDataElements(int dstX, int dstY,
575                                  int srcX, int srcY,
576                                  int width, int height,
577                                  BytePackedRaster inRaster) {
578         // Assume bounds checking has been performed previously
579         if (width <= 0 || height <= 0) {
580             return;
581         }
582 
583         byte[] inData = inRaster.data;
584         byte[] outData = this.data;
585 
586         int inscan = inRaster.scanlineStride;
587         int outscan = this.scanlineStride;
588         int inbit = inRaster.dataBitOffset +
589                       8 * (srcY - inRaster.minY) * inscan +
590                       (srcX - inRaster.minX) * inRaster.pixelBitStride;
591         int outbit = (this.dataBitOffset +
592                       8 * (dstY - minY) * outscan +
593                       (dstX - minX) * this.pixelBitStride);
594         int copybits = width * pixelBitStride;
595 
596         // Check whether the same bit alignment is present in both
597         // Rasters; if so, we can copy whole bytes using
598         // System.arraycopy.  If not, we must do a "funnel shift"
599         // where adjacent bytes contribute to each destination byte.
600         if ((inbit & 7) == (outbit & 7)) {
601             // copy is bit aligned
602             int bitpos = outbit & 7;
603             if (bitpos != 0) {
604                 int bits = 8 - bitpos;
605                 // Copy partial bytes on left
606                 int inbyte = inbit >> 3;
607                 int outbyte = outbit >> 3;
608                 int mask = 0xff >> bitpos;
609                 if (copybits < bits) {
610                     // Fix bug 4399076: previously had '8 - copybits' instead
611                     // of 'bits - copybits'.
612                     //
613                     // Prior to the this expression, 'mask' has its rightmost
614                     // 'bits' bits set to '1'.  We want it to have a total
615                     // of 'copybits' bits set, therefore we want to introduce
616                     // 'bits - copybits' zeroes on the right.
617                     mask &= 0xff << (bits - copybits);
618                     bits = copybits;
619                 }
620                 for (int j = 0; j < height; j++) {
621                     int element = outData[outbyte];
622                     element &= ~mask;
623                     element |= (inData[inbyte] & mask);
624                     outData[outbyte] = (byte) element;
625                     inbyte += inscan;
626                     outbyte += outscan;
627                 }
628                 inbit += bits;
629                 outbit += bits;
630                 copybits -= bits;
631             }
632             if (copybits >= 8) {
633                 // Copy whole bytes
634                 int inbyte = inbit >> 3;
635                 int outbyte = outbit >> 3;
636                 int copybytes = copybits >> 3;
637                 if (copybytes == inscan && inscan == outscan) {
638                     System.arraycopy(inData, inbyte,
639                                      outData, outbyte,
640                                      inscan * height);
641                 } else {
642                     for (int j = 0; j < height; j++) {
643                         System.arraycopy(inData, inbyte,
644                                          outData, outbyte,
645                                          copybytes);
646                         inbyte += inscan;
647                         outbyte += outscan;
648                     }
649                 }
650 
651                 int bits = copybytes*8;
652                 inbit += bits;
653                 outbit += bits;
654                 copybits -= bits;
655             }
656             if (copybits > 0) {
657                 // Copy partial bytes on right
658                 int inbyte = inbit >> 3;
659                 int outbyte = outbit >> 3;
660                 int mask = (0xff00 >> copybits) & 0xff;
661                 for (int j = 0; j < height; j++) {
662                     int element = outData[outbyte];
663                     element &= ~mask;
664                     element |= (inData[inbyte] & mask);
665                     outData[outbyte] = (byte) element;
666                     inbyte += inscan;
667                     outbyte += outscan;
668                 }
669             }
670         } else {
671             // Unaligned case, see RFE #4284166
672             // Note that the code in that RFE is not correct
673 
674             // Insert bits into the first byte of the output
675             // if either the starting bit position is not zero or
676             // we are writing fewer than 8 bits in total
677             int bitpos = outbit & 7;
678             if (bitpos != 0 || copybits < 8) {
679                 int bits = 8 - bitpos;
680                 int inbyte = inbit >> 3;
681                 int outbyte = outbit >> 3;
682 
683                 int lshift = inbit & 7;
684                 int rshift = 8 - lshift;
685                 int mask = 0xff >> bitpos;
686                 if (copybits < bits) {
687                     // Fix mask if we're only writing a partial byte
688                     mask &= 0xff << (bits - copybits);
689                     bits = copybits;
690                 }
691                 int lastByte = inData.length - 1;
692                 for (int j = 0; j < height; j++) {
693                     // Read two bytes from the source if possible
694                     // Don't worry about going over a scanline boundary
695                     // since any extra bits won't get used anyway
696                     byte inData0 = inData[inbyte];
697                     byte inData1 = (byte)0;
698                     if (inbyte < lastByte) {
699                         inData1 = inData[inbyte + 1];
700                     }
701 
702                     // Insert the new bits into the output
703                     int element = outData[outbyte];
704                     element &= ~mask;
705                     element |= (((inData0 << lshift) |
706                                  ((inData1 & 0xff) >> rshift))
707                                 >> bitpos) & mask;
708                     outData[outbyte] = (byte)element;
709                     inbyte += inscan;
710                     outbyte += outscan;
711                 }
712 
713                 inbit += bits;
714                 outbit += bits;
715                 copybits -= bits;
716             }
717 
718             // Now we have outbit & 7 == 0 so we can write
719             // complete bytes for a while
720 
721             // Make sure we have work to do in the central loop
722             // to avoid reading past the end of the scanline
723             if (copybits >= 8) {
724                 int inbyte = inbit >> 3;
725                 int outbyte = outbit >> 3;
726                 int copybytes = copybits >> 3;
727                 int lshift = inbit & 7;
728                 int rshift = 8 - lshift;
729 
730                 for (int j = 0; j < height; j++) {
731                     int ibyte = inbyte + j*inscan;
732                     int obyte = outbyte + j*outscan;
733 
734                     int inData0 = inData[ibyte];
735                     // Combine adjacent bytes while 8 or more bits left
736                     for (int i = 0; i < copybytes; i++) {
737                         int inData1 = inData[ibyte + 1];
738                         int val = (inData0 << lshift) |
739                             ((inData1 & 0xff) >> rshift);
740                         outData[obyte] = (byte)val;
741                         inData0 = inData1;
742 
743                         ++ibyte;
744                         ++obyte;
745                     }
746                 }
747 
748                 int bits = copybytes*8;
749                 inbit += bits;
750                 outbit += bits;
751                 copybits -= bits;
752             }
753 
754             // Finish last byte
755             if (copybits > 0) {
756                 int inbyte = inbit >> 3;
757                 int outbyte = outbit >> 3;
758                 int mask = (0xff00 >> copybits) & 0xff;
759                 int lshift = inbit & 7;
760                 int rshift = 8 - lshift;
761 
762                 int lastByte = inData.length - 1;
763                 for (int j = 0; j < height; j++) {
764                     byte inData0 = inData[inbyte];
765                     byte inData1 = (byte)0;
766                     if (inbyte < lastByte) {
767                         inData1 = inData[inbyte + 1];
768                     }
769 
770                     // Insert the new bits into the output
771                     int element = outData[outbyte];
772                     element &= ~mask;
773                     element |= ((inData0 << lshift) |
774                                 ((inData1 & 0xff) >> rshift)) & mask;
775                     outData[outbyte] = (byte)element;
776 
777                     inbyte += inscan;
778                     outbyte += outscan;
779                 }
780             }
781         }
782 
783         markDirty();
784     }
785 
786     /**
787      * Copies pixels from Raster srcRaster to this WritableRaster.
788      * For each (x, y) address in srcRaster, the corresponding pixel
789      * is copied to address (x+dx, y+dy) in this WritableRaster,
790      * unless (x+dx, y+dy) falls outside the bounds of this raster.
791      * srcRaster must have the same number of bands as this WritableRaster.
792      * The copy is a simple copy of source samples to the corresponding
793      * destination samples.  For details, see
794      * {@link WritableRaster#setRect(Raster)}.
795      *
796      * @param dx        The X translation factor from src space to dst space
797      *                  of the copy.
798      * @param dy        The Y translation factor from src space to dst space
799      *                  of the copy.
800      * @param srcRaster The Raster from which to copy pixels.
801      */
802     public void setRect(int dx, int dy, Raster srcRaster) {
803         // Check if we can use fast code
804         if (!(srcRaster instanceof BytePackedRaster) ||
805             ((BytePackedRaster)srcRaster).pixelBitStride != pixelBitStride) {
806             super.setRect(dx, dy, srcRaster);
807             return;
808         }
809 
810         int width  = srcRaster.getWidth();
811         int height = srcRaster.getHeight();
812         int srcOffX = srcRaster.getMinX();
813         int srcOffY = srcRaster.getMinY();
814         int dstOffX = dx+srcOffX;
815         int dstOffY = dy+srcOffY;
816 
817         // Clip to this raster
818         if (dstOffX < this.minX) {
819             int skipX = this.minX - dstOffX;
820             width -= skipX;
821             srcOffX += skipX;
822             dstOffX = this.minX;
823         }
824         if (dstOffY < this.minY) {
825             int skipY = this.minY - dstOffY;
826             height -= skipY;
827             srcOffY += skipY;
828             dstOffY = this.minY;
829         }
830         if (dstOffX+width > this.maxX) {
831             width = this.maxX - dstOffX;
832         }
833         if (dstOffY+height > this.maxY) {
834             height = this.maxY - dstOffY;
835         }
836 
837         setDataElements(dstOffX, dstOffY,
838                         srcOffX, srcOffY,
839                         width, height,
840                         (BytePackedRaster)srcRaster);
841     }
842 
843     /**
844      * Stores an array of data elements into the specified rectangular
845      * region.
846      * An ArrayIndexOutOfBounds exception will be thrown at runtime
847      * if the pixel coordinates are out of bounds.
848      * A ClassCastException will be thrown if the input object is non null
849      * and references anything other than an array of transferType.
850      * The data elements in the
851      * data array are assumed to be packed.  That is, a data element
852      * at location (x2, y2) would be found at:
853      * <pre>
854      *      inData[((y2-y)*w + (x2-x))]
855      * </pre>
856      * @param x        The X coordinate of the upper left pixel location.
857      * @param y        The Y coordinate of the upper left pixel location.
858      * @param w        Width of the pixel rectangle.
859      * @param h        Height of the pixel rectangle.
860      * @param inData   An object reference to an array of type defined by
861      *                 getTransferType() and length w*h*getNumDataElements()
862      *                 containing the pixel data to place between x,y and
863      *                 x+h, y+h.
864      */
865     public void setDataElements(int x, int y, int w, int h, Object obj) {
866         putByteData(x, y, w, h, (byte[])obj);
867     }
868 
869     /**
870      * Stores a byte array of data elements into the specified rectangular
871      * region.  The band index will be ignored.
872      * An ArrayIndexOutOfBounds exception will be thrown at runtime
873      * if the pixel coordinates are out of bounds.
874      * The data elements in the
875      * data array are assumed to be packed.  That is, a data element
876      * at location (x2, y2) would be found at:
877      * <pre>
878      *      inData[((y2-y)*w + (x2-x))]
879      * </pre>
880      * @param x        The X coordinate of the upper left pixel location.
881      * @param y        The Y coordinate of the upper left pixel location.
882      * @param w        Width of the pixel rectangle.
883      * @param h        Height of the pixel rectangle.
884      * @param band     The band to set, is ignored.
885      * @param inData   The data elements to be stored.
886      */
887     public void putByteData(int x, int y, int w, int h,
888                             int band, byte[] inData) {
889         putByteData(x, y, w, h, inData);
890     }
891 
892     /**
893      * Stores a byte array of data elements into the specified rectangular
894      * region.
895      * An ArrayIndexOutOfBounds exception will be thrown at runtime
896      * if the pixel coordinates are out of bounds.
897      * The data elements in the
898      * data array are assumed to be packed.  That is, a data element
899      * at location (x2, y2) would be found at:
900      * <pre>
901      *      inData[((y2-y)*w + (x2-x))]
902      * </pre>
903      * @param x        The X coordinate of the upper left pixel location.
904      * @param y        The Y coordinate of the upper left pixel location.
905      * @param w        Width of the pixel rectangle.
906      * @param h        Height of the pixel rectangle.
907      * @param inData   The data elements to be stored.
908      */
909     public void putByteData(int x, int y, int w, int h, byte[] inData) {
910         if ((x < this.minX) || (y < this.minY) ||
911             (x + w > this.maxX) || (y + h > this.maxY)) {
912             throw new ArrayIndexOutOfBoundsException
913                 ("Coordinate out of bounds!");
914         }
915         if (w == 0 || h == 0) {
916             return;
917         }
918 
919         int pixbits = pixelBitStride;
920         int scanbit = dataBitOffset + (x - minX) * pixbits;
921         int index = (y - minY) * scanlineStride;
922         int outindex = 0;
923         byte data[] = this.data;
924         for (int j = 0; j < h; j++) {
925             int bitnum = scanbit;
926             int element;
927 
928             // Process initial portion of scanline
929             int i = 0;
930             while ((i < w) && ((bitnum & 7) != 0)) {
931                 int shift = shiftOffset - (bitnum & 7);
932                 element = data[index + (bitnum >> 3)];
933                 element &= ~(bitMask << shift);
934                 element |= (inData[outindex++] & bitMask) << shift;
935                 data[index + (bitnum >> 3)] = (byte)element;
936 
937                 bitnum += pixbits;
938                 i++;
939             }
940 
941             // Process central portion of scanline 8 pixels at a time
942             int inIndex = index + (bitnum >> 3);
943             switch (pixbits) {
944             case 1:
945                 for (; i < w - 7; i += 8) {
946                     element = (inData[outindex++] & 1) << 7;
947                     element |= (inData[outindex++] & 1) << 6;
948                     element |= (inData[outindex++] & 1) << 5;
949                     element |= (inData[outindex++] & 1) << 4;
950                     element |= (inData[outindex++] & 1) << 3;
951                     element |= (inData[outindex++] & 1) << 2;
952                     element |= (inData[outindex++] & 1) << 1;
953                     element |= (inData[outindex++] & 1);
954 
955                     data[inIndex++] = (byte)element;
956 
957                     bitnum += 8;
958                 }
959                 break;
960 
961             case 2:
962                 for (; i < w - 7; i += 8) {
963                     element = (inData[outindex++] & 3) << 6;
964                     element |= (inData[outindex++] & 3) << 4;
965                     element |= (inData[outindex++] & 3) << 2;
966                     element |= (inData[outindex++] & 3);
967                     data[inIndex++] = (byte)element;
968 
969                     element = (inData[outindex++] & 3) << 6;
970                     element |= (inData[outindex++] & 3) << 4;
971                     element |= (inData[outindex++] & 3) << 2;
972                     element |= (inData[outindex++] & 3);
973                     data[inIndex++] = (byte)element;
974 
975                     bitnum += 16;
976                 }
977                 break;
978 
979             case 4:
980                 for (; i < w - 7; i += 8) {
981                     element = (inData[outindex++] & 0xf) << 4;
982                     element |= (inData[outindex++] & 0xf);
983                     data[inIndex++] = (byte)element;
984 
985                     element = (inData[outindex++] & 0xf) << 4;
986                     element |= (inData[outindex++] & 0xf);
987                     data[inIndex++] = (byte)element;
988 
989                     element = (inData[outindex++] & 0xf) << 4;
990                     element |= (inData[outindex++] & 0xf);
991                     data[inIndex++] = (byte)element;
992 
993                     element = (inData[outindex++] & 0xf) << 4;
994                     element |= (inData[outindex++] & 0xf);
995                     data[inIndex++] = (byte)element;
996 
997                     bitnum += 32;
998                 }
999                 break;
1000             }
1001 
1002             // Process final portion of scanline
1003             for (; i < w; i++) {
1004                 int shift = shiftOffset - (bitnum & 7);
1005 
1006                 element = data[index + (bitnum >> 3)];
1007                 element &= ~(bitMask << shift);
1008                 element |= (inData[outindex++] & bitMask) << shift;
1009                 data[index + (bitnum >> 3)] = (byte)element;
1010 
1011                 bitnum += pixbits;
1012             }
1013 
1014             index += scanlineStride;
1015         }
1016 
1017         markDirty();
1018     }
1019 
1020     /**
1021      * Returns an int array containing all samples for a rectangle of pixels,
1022      * one sample per array element.
1023      * An ArrayIndexOutOfBoundsException may be thrown
1024      * if the coordinates are not in bounds.
1025      * @param x,&nbsp;y   the coordinates of the upper-left pixel location
1026      * @param w      Width of the pixel rectangle
1027      * @param h      Height of the pixel rectangle
1028      * @param iArray An optionally pre-allocated int array
1029      * @return the samples for the specified rectangle of pixels.
1030      */
1031     public int[] getPixels(int x, int y, int w, int h, int iArray[]) {
1032         if ((x < this.minX) || (y < this.minY) ||
1033             (x + w > this.maxX) || (y + h > this.maxY)) {
1034             throw new ArrayIndexOutOfBoundsException
1035                 ("Coordinate out of bounds!");
1036         }
1037         if (iArray == null) {
1038             iArray = new int[w * h];
1039         }
1040         int pixbits = pixelBitStride;
1041         int scanbit = dataBitOffset + (x-minX) * pixbits;
1042         int index = (y-minY) * scanlineStride;
1043         int outindex = 0;
1044         byte data[] = this.data;
1045 
1046         for (int j = 0; j < h; j++) {
1047             int bitnum = scanbit;
1048             int element;
1049 
1050             // Process initial portion of scanline
1051             int i = 0;
1052             while ((i < w) && ((bitnum & 7) != 0)) {
1053                 int shift = shiftOffset - (bitnum & 7);
1054                 iArray[outindex++] =
1055                     bitMask & (data[index + (bitnum >> 3)] >> shift);
1056                 bitnum += pixbits;
1057                 i++;
1058             }
1059 
1060             // Process central portion of scanline 8 pixels at a time
1061             int inIndex = index + (bitnum >> 3);
1062             switch (pixbits) {
1063             case 1:
1064                 for (; i < w - 7; i += 8) {
1065                     element = data[inIndex++];
1066                     iArray[outindex++] = (element >> 7) & 1;
1067                     iArray[outindex++] = (element >> 6) & 1;
1068                     iArray[outindex++] = (element >> 5) & 1;
1069                     iArray[outindex++] = (element >> 4) & 1;
1070                     iArray[outindex++] = (element >> 3) & 1;
1071                     iArray[outindex++] = (element >> 2) & 1;
1072                     iArray[outindex++] = (element >> 1) & 1;
1073                     iArray[outindex++] = element & 1;
1074                     bitnum += 8;
1075                 }
1076                 break;
1077 
1078             case 2:
1079                 for (; i < w - 7; i += 8) {
1080                     element = data[inIndex++];
1081                     iArray[outindex++] = (element >> 6) & 3;
1082                     iArray[outindex++] = (element >> 4) & 3;
1083                     iArray[outindex++] = (element >> 2) & 3;
1084                     iArray[outindex++] = element & 3;
1085 
1086                     element = data[inIndex++];
1087                     iArray[outindex++] = (element >> 6) & 3;
1088                     iArray[outindex++] = (element >> 4) & 3;
1089                     iArray[outindex++] = (element >> 2) & 3;
1090                     iArray[outindex++] = element & 3;
1091 
1092                     bitnum += 16;
1093                 }
1094                 break;
1095 
1096             case 4:
1097                 for (; i < w - 7; i += 8) {
1098                     element = data[inIndex++];
1099                     iArray[outindex++] = (element >> 4) & 0xf;
1100                     iArray[outindex++] = element & 0xf;
1101 
1102                     element = data[inIndex++];
1103                     iArray[outindex++] = (element >> 4) & 0xf;
1104                     iArray[outindex++] = element & 0xf;
1105 
1106                     element = data[inIndex++];
1107                     iArray[outindex++] = (element >> 4) & 0xf;
1108                     iArray[outindex++] = element & 0xf;
1109 
1110                     element = data[inIndex++];
1111                     iArray[outindex++] = (element >> 4) & 0xf;
1112                     iArray[outindex++] = element & 0xf;
1113 
1114                     bitnum += 32;
1115                 }
1116                 break;
1117             }
1118 
1119             // Process final portion of scanline
1120             for (; i < w; i++) {
1121                 int shift = shiftOffset - (bitnum & 7);
1122                 iArray[outindex++] =
1123                     bitMask & (data[index + (bitnum >> 3)] >> shift);
1124                 bitnum += pixbits;
1125             }
1126 
1127             index += scanlineStride;
1128         }
1129 
1130         return iArray;
1131     }
1132 
1133     /**
1134      * Sets all samples for a rectangle of pixels from an int array containing
1135      * one sample per array element.
1136      * An ArrayIndexOutOfBoundsException may be thrown if the coordinates are
1137      * not in bounds.
1138      * @param x        The X coordinate of the upper left pixel location.
1139      * @param y        The Y coordinate of the upper left pixel location.
1140      * @param w        Width of the pixel rectangle.
1141      * @param h        Height of the pixel rectangle.
1142      * @param iArray   The input int pixel array.
1143      */
1144     public void setPixels(int x, int y, int w, int h, int iArray[]) {
1145         if ((x < this.minX) || (y < this.minY) ||
1146             (x + w > this.maxX) || (y + h > this.maxY)) {
1147             throw new ArrayIndexOutOfBoundsException
1148                 ("Coordinate out of bounds!");
1149         }
1150         int pixbits = pixelBitStride;
1151         int scanbit = dataBitOffset + (x - minX) * pixbits;
1152         int index = (y - minY) * scanlineStride;
1153         int outindex = 0;
1154         byte data[] = this.data;
1155         for (int j = 0; j < h; j++) {
1156             int bitnum = scanbit;
1157             int element;
1158 
1159             // Process initial portion of scanline
1160             int i = 0;
1161             while ((i < w) && ((bitnum & 7) != 0)) {
1162                 int shift = shiftOffset - (bitnum & 7);
1163                 element = data[index + (bitnum >> 3)];
1164                 element &= ~(bitMask << shift);
1165                 element |= (iArray[outindex++] & bitMask) << shift;
1166                 data[index + (bitnum >> 3)] = (byte)element;
1167 
1168                 bitnum += pixbits;
1169                 i++;
1170             }
1171 
1172             // Process central portion of scanline 8 pixels at a time
1173             int inIndex = index + (bitnum >> 3);
1174             switch (pixbits) {
1175             case 1:
1176                 for (; i < w - 7; i += 8) {
1177                     element = (iArray[outindex++] & 1) << 7;
1178                     element |= (iArray[outindex++] & 1) << 6;
1179                     element |= (iArray[outindex++] & 1) << 5;
1180                     element |= (iArray[outindex++] & 1) << 4;
1181                     element |= (iArray[outindex++] & 1) << 3;
1182                     element |= (iArray[outindex++] & 1) << 2;
1183                     element |= (iArray[outindex++] & 1) << 1;
1184                     element |= (iArray[outindex++] & 1);
1185                     data[inIndex++] = (byte)element;
1186 
1187                     bitnum += 8;
1188                 }
1189                 break;
1190 
1191             case 2:
1192                 for (; i < w - 7; i += 8) {
1193                     element = (iArray[outindex++] & 3) << 6;
1194                     element |= (iArray[outindex++] & 3) << 4;
1195                     element |= (iArray[outindex++] & 3) << 2;
1196                     element |= (iArray[outindex++] & 3);
1197                     data[inIndex++] = (byte)element;
1198 
1199                     element = (iArray[outindex++] & 3) << 6;
1200                     element |= (iArray[outindex++] & 3) << 4;
1201                     element |= (iArray[outindex++] & 3) << 2;
1202                     element |= (iArray[outindex++] & 3);
1203                     data[inIndex++] = (byte)element;
1204 
1205                     bitnum += 16;
1206                 }
1207                 break;
1208 
1209             case 4:
1210                 for (; i < w - 7; i += 8) {
1211                     element = (iArray[outindex++] & 0xf) << 4;
1212                     element |= (iArray[outindex++] & 0xf);
1213                     data[inIndex++] = (byte)element;
1214 
1215                     element = (iArray[outindex++] & 0xf) << 4;
1216                     element |= (iArray[outindex++] & 0xf);
1217                     data[inIndex++] = (byte)element;
1218 
1219                     element = (iArray[outindex++] & 0xf) << 4;
1220                     element |= (iArray[outindex++] & 0xf);
1221                     data[inIndex++] = (byte)element;
1222 
1223                     element = (iArray[outindex++] & 0xf) << 4;
1224                     element |= (iArray[outindex++] & 0xf);
1225                     data[inIndex++] = (byte)element;
1226 
1227                     bitnum += 32;
1228                 }
1229                 break;
1230             }
1231 
1232             // Process final portion of scanline
1233             for (; i < w; i++) {
1234                 int shift = shiftOffset - (bitnum & 7);
1235 
1236                 element = data[index + (bitnum >> 3)];
1237                 element &= ~(bitMask << shift);
1238                 element |= (iArray[outindex++] & bitMask) << shift;
1239                 data[index + (bitnum >> 3)] = (byte)element;
1240 
1241                 bitnum += pixbits;
1242             }
1243 
1244             index += scanlineStride;
1245         }
1246 
1247         markDirty();
1248     }
1249 
1250     /**
1251      * Creates a subraster given a region of the raster.  The x and y
1252      * coordinates specify the horizontal and vertical offsets
1253      * from the upper-left corner of this raster to the upper-left corner
1254      * of the subraster.  Note that the subraster will reference the same
1255      * DataBuffer as the parent raster, but using different offsets. The
1256      * bandList is ignored.
1257      * @param x               X offset.
1258      * @param y               Y offset.
1259      * @param width           Width (in pixels) of the subraster.
1260      * @param height          Height (in pixels) of the subraster.
1261      * @param x0              Translated X origin of the subraster.
1262      * @param y0              Translated Y origin of the subraster.
1263      * @param bandList        Array of band indices.
1264      * @exception RasterFormatException
1265      *            if the specified bounding box is outside of the parent raster.
1266      */
1267     public Raster createChild(int x, int y,
1268                               int width, int height,
1269                               int x0, int y0, int[] bandList) {
1270         WritableRaster newRaster = createWritableChild(x, y,
1271                                                        width, height,
1272                                                        x0, y0,
1273                                                        bandList);
1274         return (Raster) newRaster;
1275     }
1276 
1277     /**
1278      * Creates a Writable subRaster given a region of the Raster. The x and y
1279      * coordinates specify the horizontal and vertical offsets
1280      * from the upper-left corner of this Raster to the upper-left corner
1281      * of the subRaster.  The bandList is ignored.
1282      * A translation to the subRaster may also be specified.
1283      * Note that the subRaster will reference the same
1284      * DataBuffer as the parent Raster, but using different offsets.
1285      * @param x               X offset.
1286      * @param y               Y offset.
1287      * @param width           Width (in pixels) of the subraster.
1288      * @param height          Height (in pixels) of the subraster.
1289      * @param x0              Translated X origin of the subraster.
1290      * @param y0              Translated Y origin of the subraster.
1291      * @param bandList        Array of band indices.
1292      * @exception RasterFormatException
1293      *            if the specified bounding box is outside of the parent Raster.
1294      */
1295     public WritableRaster createWritableChild(int x, int y,
1296                                               int width, int height,
1297                                               int x0, int y0,
1298                                               int[] bandList) {
1299         if (x < this.minX) {
1300             throw new RasterFormatException("x lies outside the raster");
1301         }
1302         if (y < this.minY) {
1303             throw new RasterFormatException("y lies outside the raster");
1304         }
1305         if ((x+width < x) || (x+width > this.minX + this.width)) {
1306             throw new RasterFormatException("(x + width) is outside of Raster");
1307         }
1308         if ((y+height < y) || (y+height > this.minY + this.height)) {
1309             throw new RasterFormatException("(y + height) is outside of Raster");
1310         }
1311 
1312         SampleModel sm;
1313 
1314         if (bandList != null) {
1315             sm = sampleModel.createSubsetSampleModel(bandList);
1316         }
1317         else {
1318             sm = sampleModel;
1319         }
1320 
1321         int deltaX = x0 - x;
1322         int deltaY = y0 - y;
1323 
1324         return new BytePackedRaster(sm,
1325                                     dataBuffer,
1326                                     new Rectangle(x0, y0, width, height),
1327                                     new Point(sampleModelTranslateX+deltaX,
1328                                               sampleModelTranslateY+deltaY),
1329                                     this);
1330     }
1331 
1332     /**
1333      * Creates a raster with the same layout but using a different
1334      * width and height, and with new zeroed data arrays.
1335      */
1336     public WritableRaster createCompatibleWritableRaster(int w, int h) {
1337         if (w <= 0 || h <=0) {
1338             throw new RasterFormatException("negative "+
1339                                           ((w <= 0) ? "width" : "height"));
1340         }
1341 
1342         SampleModel sm = sampleModel.createCompatibleSampleModel(w,h);
1343 
1344         return new BytePackedRaster(sm, new Point(0,0));
1345     }
1346 
1347     /**
1348      * Creates a raster with the same layout and the same
1349      * width and height, and with new zeroed data arrays.
1350      */
1351     public WritableRaster createCompatibleWritableRaster () {
1352         return createCompatibleWritableRaster(width,height);
1353     }
1354 
1355     /**
1356      * Verify that the layout parameters are consistent with
1357      * the data.  If strictCheck
1358      * is false, this method will check for ArrayIndexOutOfBounds conditions.
1359      * If strictCheck is true, this method will check for additional error
1360      * conditions such as line wraparound (width of a line greater than
1361      * the scanline stride).
1362      * @return   String   Error string, if the layout is incompatible with
1363      *                    the data.  Otherwise returns null.
1364      */
1365     private void verify (boolean strictCheck) {
1366         // Make sure data for Raster is in a legal range
1367         if (dataBitOffset < 0) {
1368             throw new RasterFormatException("Data offsets must be >= 0");
1369         }
1370 
1371         /* Need to re-verify the dimensions since a sample model may be
1372          * specified to the constructor
1373          */
1374         if (width <= 0 || height <= 0 ||
1375             height > (Integer.MAX_VALUE / width))
1376         {
1377             throw new RasterFormatException("Invalid raster dimension");
1378         }
1379 
1380 
1381         /*
1382          * pixelBitstride was verified in constructor, so just make
1383          * sure that it is safe to multiply it by width.
1384          */
1385         if ((width - 1) > Integer.MAX_VALUE / pixelBitStride) {
1386             throw new RasterFormatException("Invalid raster dimension");
1387         }
1388 
1389         if (scanlineStride < 0 ||
1390             scanlineStride > (Integer.MAX_VALUE / height) ||
1391             scanlineStride > data.length)
1392         {
1393             throw new RasterFormatException("Invalid scanline stride");
1394         }
1395 
1396         int lastbit = (dataBitOffset
1397                        + (height-1) * scanlineStride * 8
1398                        + (width-1) * pixelBitStride
1399                        + pixelBitStride - 1);
1400         if (lastbit < 0 || lastbit / 8 >= data.length) {
1401             throw new RasterFormatException("raster dimensions overflow " +
1402                                             "array bounds");
1403         }
1404         if (strictCheck) {
1405             if (height > 1) {
1406                 lastbit = width * pixelBitStride - 1;
1407                 if (lastbit / 8 >= scanlineStride) {
1408                     throw new RasterFormatException("data for adjacent" +
1409                                                     " scanlines overlaps");
1410                 }
1411             }
1412         }
1413     }
1414 
1415     public String toString() {
1416         return new String ("BytePackedRaster: width = "+width+" height = "+height
1417                            +" #channels "+numBands
1418                            +" xOff = "+sampleModelTranslateX
1419                            +" yOff = "+sampleModelTranslateY);
1420     }
1421 }