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