~ubuntu-branches/ubuntu/trusty/monodevelop/trusty-proposed

« back to all changes in this revision

Viewing changes to external/ikvm/openjdk/sun/awt/image/BytePackedRaster.java

  • Committer: Package Import Robot
  • Author(s): Jo Shields
  • Date: 2013-05-12 09:46:03 UTC
  • mto: This revision was merged to the branch mainline in revision 29.
  • Revision ID: package-import@ubuntu.com-20130512094603-mad323bzcxvmcam0
Tags: upstream-4.0.5+dfsg
ImportĀ upstreamĀ versionĀ 4.0.5+dfsg

Show diffs side-by-side

added added

removed removed

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