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