001: /*
002: * Copyright 1997-2007 Sun Microsystems, Inc. All Rights Reserved.
003: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
004: *
005: * This code is free software; you can redistribute it and/or modify it
006: * under the terms of the GNU General Public License version 2 only, as
007: * published by the Free Software Foundation. Sun designates this
008: * particular file as subject to the "Classpath" exception as provided
009: * by Sun in the LICENSE file that accompanied this code.
010: *
011: * This code is distributed in the hope that it will be useful, but WITHOUT
012: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
013: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
014: * version 2 for more details (a copy is included in the LICENSE file that
015: * accompanied this code).
016: *
017: * You should have received a copy of the GNU General Public License version
018: * 2 along with this work; if not, write to the Free Software Foundation,
019: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
020: *
021: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
022: * CA 95054 USA or visit www.sun.com if you need additional information or
023: * have any questions.
024: */
025:
026: package sun.awt.image;
027:
028: import java.awt.image.Raster;
029: import java.awt.image.WritableRaster;
030: import java.awt.image.RasterFormatException;
031: import java.awt.image.SampleModel;
032: import java.awt.image.ComponentSampleModel;
033: import java.awt.image.SinglePixelPackedSampleModel;
034: import java.awt.image.DataBuffer;
035: import java.awt.image.DataBufferByte;
036: import java.awt.Rectangle;
037: import java.awt.Point;
038:
039: /**
040: * This class defines a Raster with pixels consisting of one or more 8-bit
041: * data elements stored in close proximity to each other in a single byte
042: * array.
043: * The bit precision per data element is that
044: * of the data type (that is, the bit precision for this Raster is 8).
045: * There is only one pixel stride and one scanline stride for all
046: * bands. This type of Raster can be used with a
047: * ComponentColorModel if there are multiple bands, or an
048: * IndexColorModel if there is only one band.
049: * <p>
050: * For example, 3-3-2 RGB image data can be represented by a
051: * ByteComponentRaster using a SinglePixelPackedSampleModel and
052: * a ComponentColorModel.
053: *
054: * @version 10 Feb 1997
055: */
056: public class ByteComponentRaster extends SunWritableRaster {
057:
058: /** private band offset for use by native code */
059: protected int bandOffset;
060:
061: /** Data offsets for each band of image data. */
062: protected int[] dataOffsets;
063:
064: /** Scanline stride of the image data contained in this Raster. */
065: protected int scanlineStride;
066:
067: /** Pixel stride of the image data contained in this Raster. */
068: protected int pixelStride;
069:
070: /** The image data array. */
071: protected byte[] data;
072:
073: int type;
074:
075: /** A cached copy of minX + width for use in bounds checks. */
076: private int maxX;
077:
078: /** A cached copy of minY + height for use in bounds checks. */
079: private int maxY;
080:
081: static private native void initIDs();
082:
083: static {
084: /* ensure that the necessary native libraries are loaded */
085: NativeLibLoader.loadLibraries();
086: initIDs();
087: }
088:
089: /**
090: * Constructs a ByteComponentRaster with the given SampleModel.
091: * The Raster's upper left corner is origin and it is the same
092: * size as the SampleModel. A DataBuffer large enough to describe the
093: * Raster is automatically created. SampleModel must be of type
094: * SinglePixelPackedSampleModel or ComponentSampleModel.
095: * @param sampleModel The SampleModel that specifies the layout.
096: * @param origin The Point that specified the origin.
097: */
098: public ByteComponentRaster(SampleModel sampleModel, Point origin) {
099: this (sampleModel, sampleModel.createDataBuffer(),
100: new Rectangle(origin.x, origin.y, sampleModel
101: .getWidth(), sampleModel.getHeight()), origin,
102: null);
103: }
104:
105: /**
106: * Constructs a ByteComponentRaster with the given SampleModel
107: * and DataBuffer. The Raster's upper left corner is origin and
108: * it is the same size as the SampleModel. The DataBuffer is not
109: * initialized and must be a DataBufferByte compatible with SampleModel.
110: * SampleModel must be of type SinglePixelPackedSampleModel
111: * or ComponentSampleModel.
112: * @param sampleModel The SampleModel that specifies the layout.
113: * @param dataBuffer The DataBufferShort that contains the image data.
114: * @param origin The Point that specifies the origin.
115: */
116: public ByteComponentRaster(SampleModel sampleModel,
117: DataBuffer dataBuffer, Point origin) {
118: this (sampleModel, dataBuffer, new Rectangle(origin.x, origin.y,
119: sampleModel.getWidth(), sampleModel.getHeight()),
120: origin, null);
121: }
122:
123: /**
124: * Constructs a ByteComponentRaster with the given SampleModel,
125: * DataBuffer, and parent. DataBuffer must be a DataBufferByte and
126: * SampleModel must be of type SinglePixelPackedSampleModel
127: * or ComponentSampleModel.
128: * When translated into the base Raster's
129: * coordinate system, aRegion must be contained by the base Raster.
130: * Origin is the coordinate in the new Raster's coordinate system of
131: * the origin of the base Raster. (The base Raster is the Raster's
132: * ancestor which has no parent.)
133: *
134: * Note that this constructor should generally be called by other
135: * constructors or create methods, it should not be used directly.
136: * @param sampleModel The SampleModel that specifies the layout.
137: * @param dataBuffer The DataBufferShort that contains the image data.
138: * @param aRegion The Rectangle that specifies the image area.
139: * @param origin The Point that specifies the origin.
140: * @param parent The parent (if any) of this raster.
141: */
142: public ByteComponentRaster(SampleModel sampleModel,
143: DataBuffer dataBuffer, Rectangle aRegion, Point origin,
144: ByteComponentRaster parent) {
145: super (sampleModel, dataBuffer, aRegion, origin, parent);
146: this .maxX = minX + width;
147: this .maxY = minY + height;
148:
149: if (!(dataBuffer instanceof DataBufferByte)) {
150: throw new RasterFormatException(
151: "ByteComponentRasters must have "
152: + "byte DataBuffers");
153: }
154:
155: DataBufferByte dbb = (DataBufferByte) dataBuffer;
156: this .data = stealData(dbb, 0);
157: if (dbb.getNumBanks() != 1) {
158: throw new RasterFormatException(
159: "DataBuffer for ByteComponentRasters"
160: + " must only have 1 bank.");
161: }
162: int dbOffset = dbb.getOffset();
163:
164: if (sampleModel instanceof ComponentSampleModel) {
165: ComponentSampleModel ism = (ComponentSampleModel) sampleModel;
166: this .type = IntegerComponentRaster.TYPE_BYTE_SAMPLES;
167: this .scanlineStride = ism.getScanlineStride();
168: this .pixelStride = ism.getPixelStride();
169: this .dataOffsets = ism.getBandOffsets();
170: int xOffset = aRegion.x - origin.x;
171: int yOffset = aRegion.y - origin.y;
172: for (int i = 0; i < getNumDataElements(); i++) {
173: dataOffsets[i] += dbOffset + xOffset * pixelStride
174: + yOffset * scanlineStride;
175: }
176: } else if (sampleModel instanceof SinglePixelPackedSampleModel) {
177: SinglePixelPackedSampleModel sppsm = (SinglePixelPackedSampleModel) sampleModel;
178: this .type = IntegerComponentRaster.TYPE_BYTE_PACKED_SAMPLES;
179: this .scanlineStride = sppsm.getScanlineStride();
180: this .pixelStride = 1;
181: this .dataOffsets = new int[1];
182: this .dataOffsets[0] = dbOffset;
183: int xOffset = aRegion.x - origin.x;
184: int yOffset = aRegion.y - origin.y;
185: dataOffsets[0] += xOffset * pixelStride + yOffset
186: * scanlineStride;
187: } else {
188: throw new RasterFormatException(
189: "IntegerComponentRasters must "
190: + "have ComponentSampleModel or SinglePixelPackedSampleModel");
191: }
192: this .bandOffset = this .dataOffsets[0];
193:
194: verify(false);
195: }
196:
197: /**
198: * Returns a copy of the data offsets array. For each band the data offset
199: * is the index into the band's data array, of the first sample of the
200: * band.
201: */
202: public int[] getDataOffsets() {
203: return (int[]) dataOffsets.clone();
204: }
205:
206: /**
207: * Returns the data offset for the specified band. The data offset
208: * is the index into the data array
209: * in which the first sample of the first scanline is stored.
210: * @param band The band whose offset is returned.
211: */
212: public int getDataOffset(int band) {
213: return dataOffsets[band];
214: }
215:
216: /**
217: * Returns the scanline stride -- the number of data array elements between
218: * a given sample and the sample in the same column of the next row in the
219: * same band.
220: */
221: public int getScanlineStride() {
222: return scanlineStride;
223: }
224:
225: /**
226: * Returns pixel stride -- the number of data array elements between two
227: * samples for the same band on the same scanline.
228: */
229: public int getPixelStride() {
230: return pixelStride;
231: }
232:
233: /**
234: * Returns a reference to the data array.
235: */
236: public byte[] getDataStorage() {
237: return data;
238: }
239:
240: /**
241: * Returns the data elements for all bands at the specified
242: * location.
243: * An ArrayIndexOutOfBounds exception will be thrown at runtime
244: * if the pixel coordinate is out of bounds.
245: * A ClassCastException will be thrown if the input object is non null
246: * and references anything other than an array of transferType.
247: * @param x The X coordinate of the pixel location.
248: * @param y The Y coordinate of the pixel location.
249: * @param outData An object reference to an array of type defined by
250: * getTransferType() and length getNumDataElements().
251: * If null an array of appropriate type and size will be
252: * allocated.
253: * @return An object reference to an array of type defined by
254: * getTransferType() with the request pixel data.
255: */
256: public Object getDataElements(int x, int y, Object obj) {
257: if ((x < this .minX) || (y < this .minY) || (x >= this .maxX)
258: || (y >= this .maxY)) {
259: throw new ArrayIndexOutOfBoundsException(
260: "Coordinate out of bounds!");
261: }
262: byte outData[];
263: if (obj == null) {
264: outData = new byte[numDataElements];
265: } else {
266: outData = (byte[]) obj;
267: }
268: int off = (y - minY) * scanlineStride + (x - minX)
269: * pixelStride;
270:
271: for (int band = 0; band < numDataElements; band++) {
272: outData[band] = data[dataOffsets[band] + off];
273: }
274:
275: return outData;
276: }
277:
278: /**
279: * Returns an array of data elements from the specified rectangular
280: * region.
281: * An ArrayIndexOutOfBounds exception will be thrown at runtime
282: * if the pixel coordinates are out of bounds.
283: * A ClassCastException will be thrown if the input object is non null
284: * and references anything other than an array of transferType.
285: * <pre>
286: * byte[] bandData = (byte[])raster.getDataElements(x, y, w, h, null);
287: * int numDataElements = raster.getNumDataElements();
288: * byte[] pixel = new byte[numDataElements];
289: * // To find a data element at location (x2, y2)
290: * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
291: * pixel, 0, numDataElements);
292: * </pre>
293: * @param x The X coordinate of the upper left pixel location.
294: * @param y The Y coordinate of the upper left pixel location.
295: * @param width Width of the pixel rectangle.
296: * @param height Height of the pixel rectangle.
297: * @param outData An object reference to an array of type defined by
298: * getTransferType() and length w*h*getNumDataElements().
299: * If null an array of appropriate type and size will be
300: * allocated.
301: * @return An object reference to an array of type defined by
302: * getTransferType() with the request pixel data.
303: */
304: public Object getDataElements(int x, int y, int w, int h, Object obj) {
305: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
306: || (y + h > this .maxY)) {
307: throw new ArrayIndexOutOfBoundsException(
308: "Coordinate out of bounds!");
309: }
310: byte outData[];
311: if (obj == null) {
312: outData = new byte[w * h * numDataElements];
313: } else {
314: outData = (byte[]) obj;
315: }
316:
317: int yoff = (y - minY) * scanlineStride + (x - minX)
318: * pixelStride;
319: int xoff;
320: int off = 0;
321: int xstart;
322: int ystart;
323:
324: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
325: xoff = yoff;
326: for (xstart = 0; xstart < w; xstart++, xoff += pixelStride) {
327: for (int c = 0; c < numDataElements; c++) {
328: outData[off++] = data[dataOffsets[c] + xoff];
329: }
330: }
331: }
332:
333: return outData;
334: }
335:
336: /**
337: * Returns a byte array of data elements from the specified rectangular
338: * region for the specified band.
339: * An ArrayIndexOutOfBounds exception will be thrown at runtime
340: * if the pixel coordinates are out of bounds.
341: * <pre>
342: * byte[] bandData = raster.getByteData(x, y, w, h, null);
343: * // To find the data element at location (x2, y2)
344: * byte bandElement = bandData[((y2-y)*w + (x2-x))];
345: * </pre>
346: * @param x The X coordinate of the upper left pixel location.
347: * @param y The Y coordinate of the upper left pixel location.
348: * @param width Width of the pixel rectangle.
349: * @param height Height of the pixel rectangle.
350: * @param band The band to return.
351: * @param outData If non-null, data elements for all bands
352: * at the specified location are returned in this array.
353: * @return Data array with data elements for all bands.
354: */
355: public byte[] getByteData(int x, int y, int w, int h, int band,
356: byte[] outData) {
357: // Bounds check for 'band' will be performed automatically
358: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
359: || (y + h > this .maxY)) {
360: throw new ArrayIndexOutOfBoundsException(
361: "Coordinate out of bounds!");
362: }
363: if (outData == null) {
364: outData = new byte[scanlineStride * h];
365: }
366: int yoff = (y - minY) * scanlineStride + (x - minX)
367: * pixelStride + dataOffsets[band];
368: int xoff;
369: int off = 0;
370: int xstart;
371: int ystart;
372:
373: if (pixelStride == 1) {
374: if (scanlineStride == w) {
375: System.arraycopy(data, yoff, outData, 0, w * h);
376: } else {
377: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
378: System.arraycopy(data, yoff, outData, off, w);
379: off += w;
380: }
381: }
382: } else {
383: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
384: xoff = yoff;
385: for (xstart = 0; xstart < w; xstart++, xoff += pixelStride) {
386: outData[off++] = data[xoff];
387: }
388: }
389: }
390:
391: return outData;
392: }
393:
394: /**
395: * Returns a byte array of data elements from the specified rectangular
396: * region.
397: * An ArrayIndexOutOfBounds exception will be thrown at runtime
398: * if the pixel coordinates are out of bounds.
399: * <pre>
400: * byte[] bandData = raster.getByteData(x, y, w, h, null);
401: * int numDataElements = raster.getnumDataElements();
402: * byte[] pixel = new byte[numDataElements];
403: * // To find a data element at location (x2, y2)
404: * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
405: * pixel, 0, numDataElements);
406: * </pre>
407: * @param x The X coordinate of the upper left pixel location.
408: * @param y The Y coordinate of the upper left pixel location.
409: * @param width Width of the pixel rectangle.
410: * @param height Height of the pixel rectangle.
411: * @param outData If non-null, data elements for all bands
412: * at the specified location are returned in this array.
413: * @return Data array with data elements for all bands.
414: */
415: public byte[] getByteData(int x, int y, int w, int h, byte[] outData) {
416: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
417: || (y + h > this .maxY)) {
418: throw new ArrayIndexOutOfBoundsException(
419: "Coordinate out of bounds!");
420: }
421: if (outData == null) {
422: outData = new byte[numDataElements * scanlineStride * h];
423: }
424: int yoff = (y - minY) * scanlineStride + (x - minX)
425: * pixelStride;
426: int xoff;
427: int off = 0;
428: int xstart;
429: int ystart;
430:
431: // REMIND: Should keep track if dataOffsets are in a nice order
432: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
433: xoff = yoff;
434: for (xstart = 0; xstart < w; xstart++, xoff += pixelStride) {
435: for (int c = 0; c < numDataElements; c++) {
436: outData[off++] = data[dataOffsets[c] + xoff];
437: }
438: }
439: }
440:
441: return outData;
442: }
443:
444: /**
445: * Stores the data elements for all bands at the specified location.
446: * An ArrayIndexOutOfBounds exception will be thrown at runtime
447: * if the pixel coordinate is out of bounds.
448: * A ClassCastException will be thrown if the input object is non null
449: * and references anything other than an array of transferType.
450: * @param x The X coordinate of the pixel location.
451: * @param y The Y coordinate of the pixel location.
452: * @param inData An object reference to an array of type defined by
453: * getTransferType() and length getNumDataElements()
454: * containing the pixel data to place at x,y.
455: */
456: public void setDataElements(int x, int y, Object obj) {
457: if ((x < this .minX) || (y < this .minY) || (x >= this .maxX)
458: || (y >= this .maxY)) {
459: throw new ArrayIndexOutOfBoundsException(
460: "Coordinate out of bounds!");
461: }
462: byte inData[] = (byte[]) obj;
463: int off = (y - minY) * scanlineStride + (x - minX)
464: * pixelStride;
465:
466: for (int i = 0; i < numDataElements; i++) {
467: data[dataOffsets[i] + off] = inData[i];
468: }
469:
470: markDirty();
471: }
472:
473: /**
474: * Stores the Raster data at the specified location.
475: * An ArrayIndexOutOfBounds exception will be thrown at runtime
476: * if the pixel coordinates are out of bounds.
477: * @param x The X coordinate of the pixel location.
478: * @param y The Y coordinate of the pixel location.
479: * @param inRaster Raster of data to place at x,y location.
480: */
481: public void setDataElements(int x, int y, Raster inRaster) {
482: int dstOffX = inRaster.getMinX() + x;
483: int dstOffY = inRaster.getMinY() + y;
484: int width = inRaster.getWidth();
485: int height = inRaster.getHeight();
486: if ((dstOffX < this .minX) || (dstOffY < this .minY)
487: || (dstOffX + width > this .maxX)
488: || (dstOffY + height > this .maxY)) {
489: throw new ArrayIndexOutOfBoundsException(
490: "Coordinate out of bounds!");
491: }
492:
493: setDataElements(dstOffX, dstOffY, width, height, inRaster);
494: }
495:
496: /**
497: * Stores the Raster data at the specified location.
498: * @param dstX The absolute X coordinate of the destination pixel
499: * that will receive a copy of the upper-left pixel of the
500: * inRaster
501: * @param dstY The absolute Y coordinate of the destination pixel
502: * that will receive a copy of the upper-left pixel of the
503: * inRaster
504: * @param width The number of pixels to store horizontally
505: * @param height The number of pixels to store vertically
506: * @param inRaster Raster of data to place at x,y location.
507: */
508: private void setDataElements(int dstX, int dstY, int width,
509: int height, Raster inRaster) {
510: // Assume bounds checking has been performed previously
511: if (width <= 0 || height <= 0) {
512: return;
513: }
514:
515: int srcOffX = inRaster.getMinX();
516: int srcOffY = inRaster.getMinY();
517: Object tdata = null;
518:
519: if (inRaster instanceof ByteComponentRaster) {
520: ByteComponentRaster bct = (ByteComponentRaster) inRaster;
521: byte[] bdata = bct.getDataStorage();
522: // REMIND: Do something faster!
523: if (numDataElements == 1) {
524: int toff = bct.getDataOffset(0);
525: int tss = bct.getScanlineStride();
526:
527: int srcOffset = toff;
528: int dstOffset = dataOffsets[0] + (dstY - minY)
529: * scanlineStride + (dstX - minX);
530:
531: if (pixelStride == bct.getPixelStride()) {
532: width *= pixelStride;
533: for (int tmpY = 0; tmpY < height; tmpY++) {
534: System.arraycopy(bdata, srcOffset, data,
535: dstOffset, width);
536: srcOffset += tss;
537: dstOffset += scanlineStride;
538: }
539: markDirty();
540: return;
541: }
542: }
543: }
544:
545: for (int startY = 0; startY < height; startY++) {
546: // Grab one scanline at a time
547: tdata = inRaster.getDataElements(srcOffX, srcOffY + startY,
548: width, 1, tdata);
549: setDataElements(dstX, dstY + startY, width, 1, tdata);
550: }
551: }
552:
553: /**
554: * Stores an array of data elements into the specified rectangular
555: * region.
556: * An ArrayIndexOutOfBounds exception will be thrown at runtime
557: * if the pixel coordinates are out of bounds.
558: * A ClassCastException will be thrown if the input object is non null
559: * and references anything other than an array of transferType.
560: * The data elements in the
561: * data array are assumed to be packed. That is, a data element
562: * for the nth band at location (x2, y2) would be found at:
563: * <pre>
564: * inData[((y2-y)*w + (x2-x))*numDataElements + n]
565: * </pre>
566: * @param x The X coordinate of the upper left pixel location.
567: * @param y The Y coordinate of the upper left pixel location.
568: * @param w Width of the pixel rectangle.
569: * @param h Height of the pixel rectangle.
570: * @param inData An object reference to an array of type defined by
571: * getTransferType() and length w*h*getNumDataElements()
572: * containing the pixel data to place between x,y and
573: * x+h, y+h.
574: */
575: public void setDataElements(int x, int y, int w, int h, Object obj) {
576: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
577: || (y + h > this .maxY)) {
578: throw new ArrayIndexOutOfBoundsException(
579: "Coordinate out of bounds!");
580: }
581: byte inData[] = (byte[]) obj;
582: int yoff = (y - minY) * scanlineStride + (x - minX)
583: * pixelStride;
584: int xoff;
585: int off = 0;
586: int xstart;
587: int ystart;
588:
589: if (numDataElements == 1) {
590: int srcOffset = 0;
591: int dstOffset = yoff + dataOffsets[0];
592: for (ystart = 0; ystart < h; ystart++) {
593: xoff = yoff;
594: System.arraycopy(inData, srcOffset, data, dstOffset, w);
595:
596: srcOffset += w;
597: dstOffset += scanlineStride;
598: }
599: markDirty();
600: return;
601: }
602:
603: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
604: xoff = yoff;
605: for (xstart = 0; xstart < w; xstart++, xoff += pixelStride) {
606: for (int c = 0; c < numDataElements; c++) {
607: data[dataOffsets[c] + xoff] = inData[off++];
608: }
609: }
610: }
611:
612: markDirty();
613: }
614:
615: /**
616: * Stores a byte array of data elements into the specified rectangular
617: * region for the specified band.
618: * An ArrayIndexOutOfBounds exception will be thrown at runtime
619: * if the pixel coordinates are out of bounds.
620: * The data elements in the
621: * data array are assumed to be packed. That is, a data element
622: * at location (x2, y2) would be found at:
623: * <pre>
624: * inData[((y2-y)*w + (x2-x)) + n]
625: * </pre>
626: * @param x The X coordinate of the upper left pixel location.
627: * @param y The Y coordinate of the upper left pixel location.
628: * @param w Width of the pixel rectangle.
629: * @param h Height of the pixel rectangle.
630: * @param band The band to set.
631: * @param inData The data elements to be stored.
632: */
633: public void putByteData(int x, int y, int w, int h, int band,
634: byte[] inData) {
635: // Bounds check for 'band' will be performed automatically
636: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
637: || (y + h > this .maxY)) {
638: throw new ArrayIndexOutOfBoundsException(
639: "Coordinate out of bounds!");
640: }
641: int yoff = (y - minY) * scanlineStride + (x - minX)
642: * pixelStride + dataOffsets[band];
643: int xoff;
644: int off = 0;
645: int xstart;
646: int ystart;
647:
648: if (pixelStride == 1) {
649: if (scanlineStride == w) {
650: System.arraycopy(inData, 0, data, yoff, w * h);
651: } else {
652: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
653: System.arraycopy(inData, off, data, yoff, w);
654: off += w;
655: }
656: }
657: } else {
658: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
659: xoff = yoff;
660: for (xstart = 0; xstart < w; xstart++, xoff += pixelStride) {
661: data[xoff] = inData[off++];
662: }
663: }
664: }
665:
666: markDirty();
667: }
668:
669: /**
670: * Stores a byte array of data elements into the specified rectangular
671: * region.
672: * An ArrayIndexOutOfBounds exception will be thrown at runtime
673: * if the pixel coordinates are out of bounds.
674: * The data elements in the
675: * data array are assumed to be packed. That is, a data element
676: * for the nth band at location (x2, y2) would be found at:
677: * <pre>
678: * inData[((y2-y)*w + (x2-x))*numDataElements + n]
679: * </pre>
680: * @param x The X coordinate of the upper left pixel location.
681: * @param y The Y coordinate of the upper left pixel location.
682: * @param w Width of the pixel rectangle.
683: * @param h Height of the pixel rectangle.
684: * @param inData The data elements to be stored.
685: */
686: public void putByteData(int x, int y, int w, int h, byte[] inData) {
687: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
688: || (y + h > this .maxY)) {
689: throw new ArrayIndexOutOfBoundsException(
690: "Coordinate out of bounds!");
691: }
692: int yoff = (y - minY) * scanlineStride + (x - minX)
693: * pixelStride;
694:
695: int xoff;
696: int off = 0;
697: int xstart;
698: int ystart;
699:
700: if (numDataElements == 1) {
701: yoff += dataOffsets[0];
702: if (pixelStride == 1) {
703: if (scanlineStride == w) {
704: System.arraycopy(inData, 0, data, yoff, w * h);
705: } else {
706: for (ystart = 0; ystart < h; ystart++) {
707: System.arraycopy(inData, off, data, yoff, w);
708: off += w;
709: yoff += scanlineStride;
710: }
711: }
712: } else {
713: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
714: xoff = yoff;
715: for (xstart = 0; xstart < w; xstart++, xoff += pixelStride) {
716: data[xoff] = inData[off++];
717: }
718: }
719: }
720: } else {
721: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
722: xoff = yoff;
723: for (xstart = 0; xstart < w; xstart++, xoff += pixelStride) {
724: for (int c = 0; c < numDataElements; c++) {
725: data[dataOffsets[c] + xoff] = inData[off++];
726: }
727: }
728: }
729: }
730:
731: markDirty();
732: }
733:
734: /**
735: * Creates a subraster given a region of the raster. The x and y
736: * coordinates specify the horizontal and vertical offsets
737: * from the upper-left corner of this raster to the upper-left corner
738: * of the subraster. A subset of the bands of the parent Raster may
739: * be specified. If this is null, then all the bands are present in the
740: * subRaster. A translation to the subRaster may also be specified.
741: * Note that the subraster will reference the same
742: * DataBuffer as the parent raster, but using different offsets.
743: * @param x X offset.
744: * @param y Y offset.
745: * @param width Width (in pixels) of the subraster.
746: * @param height Height (in pixels) of the subraster.
747: * @param x0 Translated X origin of the subraster.
748: * @param y0 Translated Y origin of the subraster.
749: * @param bandList Array of band indices.
750: * @exception RasterFormatException
751: * if the specified bounding box is outside of the parent raster.
752: */
753: public Raster createChild(int x, int y, int width, int height,
754: int x0, int y0, int[] bandList) {
755: WritableRaster newRaster = createWritableChild(x, y, width,
756: height, x0, y0, bandList);
757: return (Raster) newRaster;
758: }
759:
760: /**
761: * Creates a Writable subRaster given a region of the Raster. The x and y
762: * coordinates specify the horizontal and vertical offsets
763: * from the upper-left corner of this Raster to the upper-left corner
764: * of the subRaster. A subset of the bands of the parent Raster may
765: * be specified. If this is null, then all the bands are present in the
766: * subRaster. A translation to the subRaster may also be specified.
767: * Note that the subRaster will reference the same
768: * DataBuffer as the parent Raster, but using different offsets.
769: * @param x X offset.
770: * @param y Y offset.
771: * @param width Width (in pixels) of the subraster.
772: * @param height Height (in pixels) of the subraster.
773: * @param x0 Translated X origin of the subraster.
774: * @param y0 Translated Y origin of the subraster.
775: * @param bandList Array of band indices.
776: * @exception RasterFormatException
777: * if the specified bounding box is outside of the parent Raster.
778: */
779: public WritableRaster createWritableChild(int x, int y, int width,
780: int height, int x0, int y0, int[] bandList) {
781: if (x < this .minX) {
782: throw new RasterFormatException("x lies outside the raster");
783: }
784: if (y < this .minY) {
785: throw new RasterFormatException("y lies outside the raster");
786: }
787: if ((x + width < x) || (x + width > this .minX + this .width)) {
788: throw new RasterFormatException(
789: "(x + width) is outside of Raster");
790: }
791: if ((y + height < y) || (y + height > this .minY + this .height)) {
792: throw new RasterFormatException(
793: "(y + height) is outside of Raster");
794: }
795:
796: SampleModel sm;
797:
798: if (bandList != null)
799: sm = sampleModel.createSubsetSampleModel(bandList);
800: else
801: sm = sampleModel;
802:
803: int deltaX = x0 - x;
804: int deltaY = y0 - y;
805:
806: return new ByteComponentRaster(sm, dataBuffer, new Rectangle(
807: x0, y0, width, height), new Point(sampleModelTranslateX
808: + deltaX, sampleModelTranslateY + deltaY), this );
809: }
810:
811: /**
812: * Creates a Raster with the same layout but using a different
813: * width and height, and with new zeroed data arrays.
814: */
815: public WritableRaster createCompatibleWritableRaster(int w, int h) {
816: if (w <= 0 || h <= 0) {
817: throw new RasterFormatException("negative "
818: + ((w <= 0) ? "width" : "height"));
819: }
820:
821: SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
822:
823: return new ByteComponentRaster(sm, new Point(0, 0));
824:
825: }
826:
827: /**
828: * Creates a Raster with the same layout and the same
829: * width and height, and with new zeroed data arrays. If
830: * the Raster is a subRaster, this will call
831: * createCompatibleRaster(width, height).
832: */
833: public WritableRaster createCompatibleWritableRaster() {
834: return createCompatibleWritableRaster(width, height);
835: }
836:
837: /**
838: * Verify that the layout parameters are consistent with
839: * the data. If strictCheck
840: * is false, this method will check for ArrayIndexOutOfBounds conditions. If
841: * strictCheck is true, this method will check for additional error
842: * conditions such as line wraparound (width of a line greater than
843: * the scanline stride).
844: * @return String Error string, if the layout is incompatible with
845: * the data. Otherwise returns null.
846: */
847: private void verify(boolean strictCheck) {
848: // Make sure data for Raster is in a legal range
849: for (int i = 0; i < dataOffsets.length; i++) {
850: if (dataOffsets[i] < 0) {
851: throw new RasterFormatException(
852: "Data offsets for band " + i + "("
853: + dataOffsets[i] + ") must be >= 0");
854: }
855: }
856:
857: int maxSize = 0;
858: int size;
859:
860: for (int i = 0; i < numDataElements; i++) {
861: size = (height - 1) * scanlineStride + (width - 1)
862: * pixelStride + dataOffsets[i];
863: if (size > maxSize) {
864: maxSize = size;
865: }
866: }
867: if (data.length < maxSize) {
868: throw new RasterFormatException(
869: "Data array too small (should be " + maxSize + " )");
870: }
871: }
872:
873: public String toString() {
874: return new String("ByteComponentRaster: width = " + width
875: + " height = " + height + " #numDataElements "
876: + numDataElements
877: // +" xOff = "+xOffset+" yOff = "+yOffset
878: + " dataOff[0] = " + dataOffsets[0]);
879: }
880:
881: // /**
882: // * For debugging... prints a region of a one-band ByteComponentRaster
883: // */
884: // public void print(int x, int y, int w, int h) {
885: // // REMIND: Only works for 1 band!
886: // System.out.println(this);
887: // int offset = dataOffsets[0] + y*scanlineStride + x*pixelStride;
888: // int off;
889: // for (int yoff=0; yoff < h; yoff++, offset += scanlineStride) {
890: // off = offset;
891: // System.out.print("Line "+(y+yoff)+": ");
892: // for (int xoff = 0; xoff < w; xoff++, off+= pixelStride) {
893: // String s = Integer.toHexString(data[off]);
894: // if (s.length() == 8) {
895: // s = s.substring(6,8);
896: // }
897: // System.out.print(s+" ");
898: // }
899: // System.out.println("");
900: // }
901: // }
902:
903: }
|