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.
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.
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).
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.
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
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;
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.
45
public class BytePackedRaster extends SunWritableRaster {
47
/** The data bit offset for each pixel. */
50
/** Scanline stride of the image data contained in this Raster. */
54
* The bit stride of a pixel, equal to the total number of bits
55
* required to store a pixel.
59
/** The bit mask for extracting the pixel. */
62
/** The image data array. */
65
/** 8 minus the pixel bit stride. */
70
/** A cached copy of minX + width for use in bounds checks. */
73
/** A cached copy of minY + height for use in bounds checks. */
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.
85
public BytePackedRaster(SampleModel sampleModel,
88
sampleModel.createDataBuffer(),
89
new Rectangle(origin.x,
91
sampleModel.getWidth(),
92
sampleModel.getHeight()),
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.
107
public BytePackedRaster(SampleModel sampleModel,
108
DataBuffer dataBuffer,
112
new Rectangle(origin.x,
114
sampleModel.getWidth(),
115
sampleModel.getHeight()),
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.)
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.
138
* @exception RasterFormatException if the parameters do not conform
139
* to requirements of this Raster type.
141
public BytePackedRaster(SampleModel sampleModel,
142
DataBuffer dataBuffer,
145
BytePackedRaster parent){
146
super(sampleModel,dataBuffer,aRegion,origin, parent);
147
this.maxX = minX + width;
148
this.maxY = minY + height;
150
if (!(dataBuffer instanceof DataBufferByte)) {
151
throw new RasterFormatException("BytePackedRasters must have" +
154
DataBufferByte dbb = (DataBufferByte)dataBuffer;
155
this.data = stealData(dbb, 0);
156
if (dbb.getNumBanks() != 1) {
158
RasterFormatException("DataBuffer for BytePackedRasters"+
159
" must only have 1 bank.");
161
int dbOffset = dbb.getOffset();
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");
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;
182
throw new RasterFormatException("BytePackedRasters must have"+
183
"MultiPixelPackedSampleModel");
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.
193
public int getDataBitOffset() {
194
return dataBitOffset;
198
* Returns the scanline stride -- the number of data array elements between
199
* a given sample and the sample in the same column
202
public int getScanlineStride() {
203
return scanlineStride;
207
* Returns pixel bit stride -- the number of bits between two
208
* samples on the same scanline.
210
public int getPixelBitStride() {
211
return pixelBitStride;
215
* Returns a reference to the entire data array.
217
public byte[] getDataStorage() {
222
* Returns the data element at the specified
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
234
* @return An object reference to an array of type defined by
235
* getTransferType() with the request pixel data.
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!");
245
outData = new byte[numDataElements];
247
outData = (byte[])obj;
249
int bitnum = dataBitOffset + (x-minX) * pixelBitStride;
251
int element = data[(y-minY) * scanlineStride + (bitnum >> 3)] & 0xff;
252
int shift = shiftOffset - (bitnum & 7);
253
outData[0] = (byte)((element >> shift) & bitMask);
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.
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
278
* @return An object reference to an array of type defined by
279
* getTransferType() with the requested pixel data.
281
public Object getDataElements(int x, int y, int w, int h,
283
return getByteData(x, y, w, h, (byte[])outData);
287
* Returns an array of data elements from the specified rectangular
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.
295
* byte[] bandData = (byte[])raster.getPixelData(x, y, w, h, null);
297
* // To find a data element at location (x2, y2)
298
* pixel = bandData[((y2-y)*w + (x2-x))];
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
308
* @return An object reference to an array of type defined by
309
* getTransferType() with the request pixel data.
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!");
319
outData = new byte[numDataElements*w*h];
321
outData = (byte[])obj;
323
int pixbits = pixelBitStride;
324
int scanbit = dataBitOffset + (x-minX) * pixbits;
325
int index = (y-minY) * scanlineStride;
327
byte data[] = this.data;
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));
337
index += scanlineStride;
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.
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)];
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.
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);
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.
372
* byte[] byteData = raster.getByteData(x, y, w, h, null);
374
* // To find a data element at location (x2, y2)
375
* pixel = byteData[((y2-y)*w + (x2-x))];
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.
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!");
391
if (outData == null) {
392
outData = new byte[w * h];
394
int pixbits = pixelBitStride;
395
int scanbit = dataBitOffset + (x-minX) * pixbits;
396
int index = (y-minY) * scanlineStride;
398
byte data[] = this.data;
400
for (int j = 0; j < h; j++) {
401
int bitnum = scanbit;
404
// Process initial portion of scanline
406
while ((i < w) && ((bitnum & 7) != 0)) {
407
int shift = shiftOffset - (bitnum & 7);
408
outData[outindex++] =
409
(byte)(bitMask & (data[index + (bitnum >> 3)] >> shift));
414
// Process central portion of scanline 8 pixels at a time
415
int inIndex = index + (bitnum >> 3);
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);
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);
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);
451
for (; i < w - 7; i += 8) {
452
element = data[inIndex++];
453
outData[outindex++] = (byte)((element >> 4) & 0xf);
454
outData[outindex++] = (byte)(element & 0xf);
456
element = data[inIndex++];
457
outData[outindex++] = (byte)((element >> 4) & 0xf);
458
outData[outindex++] = (byte)(element & 0xf);
460
element = data[inIndex++];
461
outData[outindex++] = (byte)((element >> 4) & 0xf);
462
outData[outindex++] = (byte)(element & 0xf);
464
element = data[inIndex++];
465
outData[outindex++] = (byte)((element >> 4) & 0xf);
466
outData[outindex++] = (byte)(element & 0xf);
473
// Process final portion of scanline
475
int shift = shiftOffset - (bitnum & 7);
476
outData[outindex++] =
477
(byte) (bitMask & (data[index + (bitnum >> 3)] >> shift));
481
index += scanlineStride;
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.
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!");
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);
510
byte element = data[index];
511
element &= ~(bitMask << shift);
512
element |= (inData[0] & bitMask) << shift;
513
data[index] = element;
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.
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);
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!");
545
setDataElements(dstOffX, dstOffY,
548
(BytePackedRaster)inRaster);
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
556
* @param dstY The absolute Y coordinate of the destination pixel
557
* that will receive a copy of the upper-left pixel of the
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.
567
private void setDataElements(int dstX, int dstY,
569
int width, int height,
570
BytePackedRaster inRaster) {
571
// Assume bounds checking has been performed previously
572
if (width <= 0 || height <= 0) {
576
byte[] inData = inRaster.data;
577
byte[] outData = this.data;
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;
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;
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'.
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);
613
for (int j = 0; j < height; j++) {
614
int element = outData[outbyte];
616
element |= (inData[inbyte] & mask);
617
outData[outbyte] = (byte) element;
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,
635
for (int j = 0; j < height; j++) {
636
System.arraycopy(inData, inbyte,
644
int bits = copybytes*8;
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];
657
element |= (inData[inbyte] & mask);
658
outData[outbyte] = (byte) element;
664
// Unaligned case, see RFE #4284166
665
// Note that the code in that RFE is not correct
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;
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);
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];
695
// Insert the new bits into the output
696
int element = outData[outbyte];
698
element |= (((inData0 << lshift) |
699
((inData1 & 0xff) >> rshift))
701
outData[outbyte] = (byte)element;
711
// Now we have outbit & 7 == 0 so we can write
712
// complete bytes for a while
714
// Make sure we have work to do in the central loop
715
// to avoid reading past the end of the scanline
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;
723
for (int j = 0; j < height; j++) {
724
int ibyte = inbyte + j*inscan;
725
int obyte = outbyte + j*outscan;
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;
741
int bits = copybytes*8;
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;
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];
763
// Insert the new bits into the output
764
int element = outData[outbyte];
766
element |= ((inData0 << lshift) |
767
((inData1 & 0xff) >> rshift)) & mask;
768
outData[outbyte] = (byte)element;
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)}.
789
* @param dx The X translation factor from src space to dst space
791
* @param dy The Y translation factor from src space to dst space
793
* @param srcRaster The Raster from which to copy pixels.
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);
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;
810
// Clip to this raster
811
if (dstOffX < this.minX) {
812
int skipX = this.minX - dstOffX;
817
if (dstOffY < this.minY) {
818
int skipY = this.minY - dstOffY;
823
if (dstOffX+width > this.maxX) {
824
width = this.maxX - dstOffX;
826
if (dstOffY+height > this.maxY) {
827
height = this.maxY - dstOffY;
830
setDataElements(dstOffX, dstOffY,
833
(BytePackedRaster)srcRaster);
837
* Stores an array of data elements into the specified rectangular
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:
847
* inData[((y2-y)*w + (x2-x))]
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
858
public void setDataElements(int x, int y, int w, int h, Object obj) {
859
putByteData(x, y, w, h, (byte[])obj);
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:
871
* inData[((y2-y)*w + (x2-x))]
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.
880
public void putByteData(int x, int y, int w, int h,
881
int band, byte[] inData) {
882
putByteData(x, y, w, h, inData);
886
* Stores a byte array of data elements into the specified rectangular
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:
894
* inData[((y2-y)*w + (x2-x))]
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.
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!");
908
if (w == 0 || h == 0) {
912
int pixbits = pixelBitStride;
913
int scanbit = dataBitOffset + (x - minX) * pixbits;
914
int index = (y - minY) * scanlineStride;
916
byte data[] = this.data;
917
for (int j = 0; j < h; j++) {
918
int bitnum = scanbit;
921
// Process initial portion of scanline
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;
934
// Process central portion of scanline 8 pixels at a time
935
int inIndex = index + (bitnum >> 3);
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);
948
data[inIndex++] = (byte)element;
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;
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;
973
for (; i < w - 7; i += 8) {
974
element = (inData[outindex++] & 0xf) << 4;
975
element |= (inData[outindex++] & 0xf);
976
data[inIndex++] = (byte)element;
978
element = (inData[outindex++] & 0xf) << 4;
979
element |= (inData[outindex++] & 0xf);
980
data[inIndex++] = (byte)element;
982
element = (inData[outindex++] & 0xf) << 4;
983
element |= (inData[outindex++] & 0xf);
984
data[inIndex++] = (byte)element;
986
element = (inData[outindex++] & 0xf) << 4;
987
element |= (inData[outindex++] & 0xf);
988
data[inIndex++] = (byte)element;
995
// Process final portion of scanline
997
int shift = shiftOffset - (bitnum & 7);
999
element = data[index + (bitnum >> 3)];
1000
element &= ~(bitMask << shift);
1001
element |= (inData[outindex++] & bitMask) << shift;
1002
data[index + (bitnum >> 3)] = (byte)element;
1007
index += scanlineStride;
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, 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.
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!");
1030
if (iArray == null) {
1031
iArray = new int[w * h];
1033
int pixbits = pixelBitStride;
1034
int scanbit = dataBitOffset + (x-minX) * pixbits;
1035
int index = (y-minY) * scanlineStride;
1037
byte data[] = this.data;
1039
for (int j = 0; j < h; j++) {
1040
int bitnum = scanbit;
1043
// Process initial portion of scanline
1045
while ((i < w) && ((bitnum & 7) != 0)) {
1046
int shift = shiftOffset - (bitnum & 7);
1047
iArray[outindex++] =
1048
bitMask & (data[index + (bitnum >> 3)] >> shift);
1053
// Process central portion of scanline 8 pixels at a time
1054
int inIndex = index + (bitnum >> 3);
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;
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;
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;
1090
for (; i < w - 7; i += 8) {
1091
element = data[inIndex++];
1092
iArray[outindex++] = (element >> 4) & 0xf;
1093
iArray[outindex++] = element & 0xf;
1095
element = data[inIndex++];
1096
iArray[outindex++] = (element >> 4) & 0xf;
1097
iArray[outindex++] = element & 0xf;
1099
element = data[inIndex++];
1100
iArray[outindex++] = (element >> 4) & 0xf;
1101
iArray[outindex++] = element & 0xf;
1103
element = data[inIndex++];
1104
iArray[outindex++] = (element >> 4) & 0xf;
1105
iArray[outindex++] = element & 0xf;
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);
1120
index += scanlineStride;
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
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.
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!");
1143
int pixbits = pixelBitStride;
1144
int scanbit = dataBitOffset + (x - minX) * pixbits;
1145
int index = (y - minY) * scanlineStride;
1147
byte data[] = this.data;
1148
for (int j = 0; j < h; j++) {
1149
int bitnum = scanbit;
1152
// Process initial portion of scanline
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;
1165
// Process central portion of scanline 8 pixels at a time
1166
int inIndex = index + (bitnum >> 3);
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;
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;
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;
1203
for (; i < w - 7; i += 8) {
1204
element = (iArray[outindex++] & 0xf) << 4;
1205
element |= (iArray[outindex++] & 0xf);
1206
data[inIndex++] = (byte)element;
1208
element = (iArray[outindex++] & 0xf) << 4;
1209
element |= (iArray[outindex++] & 0xf);
1210
data[inIndex++] = (byte)element;
1212
element = (iArray[outindex++] & 0xf) << 4;
1213
element |= (iArray[outindex++] & 0xf);
1214
data[inIndex++] = (byte)element;
1216
element = (iArray[outindex++] & 0xf) << 4;
1217
element |= (iArray[outindex++] & 0xf);
1218
data[inIndex++] = (byte)element;
1225
// Process final portion of scanline
1226
for (; i < w; i++) {
1227
int shift = shiftOffset - (bitnum & 7);
1229
element = data[index + (bitnum >> 3)];
1230
element &= ~(bitMask << shift);
1231
element |= (iArray[outindex++] & bitMask) << shift;
1232
data[index + (bitnum >> 3)] = (byte)element;
1237
index += scanlineStride;
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.
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,
1267
return (Raster) newRaster;
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.
1288
public WritableRaster createWritableChild(int x, int y,
1289
int width, int height,
1292
if (x < this.minX) {
1293
throw new RasterFormatException("x lies outside the raster");
1295
if (y < this.minY) {
1296
throw new RasterFormatException("y lies outside the raster");
1298
if ((x+width < x) || (x+width > this.minX + this.width)) {
1299
throw new RasterFormatException("(x + width) is outside of Raster");
1301
if ((y+height < y) || (y+height > this.minY + this.height)) {
1302
throw new RasterFormatException("(y + height) is outside of Raster");
1307
if (bandList != null) {
1308
sm = sampleModel.createSubsetSampleModel(bandList);
1314
int deltaX = x0 - x;
1315
int deltaY = y0 - y;
1317
return new BytePackedRaster(sm,
1319
new Rectangle(x0, y0, width, height),
1320
new Point(sampleModelTranslateX+deltaX,
1321
sampleModelTranslateY+deltaY),
1326
* Creates a raster with the same layout but using a different
1327
* width and height, and with new zeroed data arrays.
1329
public WritableRaster createCompatibleWritableRaster(int w, int h) {
1330
if (w <= 0 || h <=0) {
1331
throw new RasterFormatException("negative "+
1332
((w <= 0) ? "width" : "height"));
1335
SampleModel sm = sampleModel.createCompatibleSampleModel(w,h);
1337
return new BytePackedRaster(sm, new Point(0,0));
1341
* Creates a raster with the same layout and the same
1342
* width and height, and with new zeroed data arrays.
1344
public WritableRaster createCompatibleWritableRaster () {
1345
return createCompatibleWritableRaster(width,height);
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.
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");
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 " +
1374
lastbit = width * pixelBitStride - 1;
1375
if (lastbit / 8 >= scanlineStride) {
1376
throw new RasterFormatException("data for adjacent" +
1377
" scanlines overlaps");
1383
public String toString() {
1384
return new String ("BytePackedRaster: width = "+width+" height = "+height
1385
+" #channels "+numBands
1386
+" xOff = "+sampleModelTranslateX
1387
+" yOff = "+sampleModelTranslateY);