1/*
2 * Copyright (c) 1997, 2017, 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
26package sun.awt.image;
27
28import java.awt.Point;
29import java.awt.Rectangle;
30import java.awt.image.DataBuffer;
31import java.awt.image.DataBufferByte;
32import java.awt.image.MultiPixelPackedSampleModel;
33import java.awt.image.Raster;
34import java.awt.image.RasterFormatException;
35import java.awt.image.SampleModel;
36import 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 */
46public 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
77    private static native void initIDs();
78    static {
79        /* ensure that the necessary native libraries are loaded */
80        NativeLibLoader.loadLibraries();
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     */
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     */
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     */
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     */
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     */
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     */
214    public int getPixelBitStride() {
215        return pixelBitStride;
216    }
217
218    /**
219     * Returns a reference to the entire data array.
220     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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     */
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
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