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.BandedSampleModel;
033: import java.awt.image.DataBuffer;
034: import java.awt.image.DataBufferByte;
035: import java.awt.Rectangle;
036: import java.awt.Point;
037:
038: /**
039: * This class defines a Raster with pixels consisting of multiple
040: * 8-bit samples stored in possibly separate arrays for each band.
041: * Operations on sets of pixels are performed on a given band in the
042: * Raster before moving on to the next band. The arrays used for
043: * storage may be distinct or shared between some or all of the bands.
044: * Each band additionally has an offset that is added to determine the
045: * DataBuffer location of each pixel.
046: *
047: * There is only one scanline stride for all bands. The pixel stride
048: * is always equal to one. This type of raster can be used with a
049: * ComponentColorModel. This class requires a BandedSampleModel.
050: *
051: * @version 10 Feb 1997
052: */
053: public class ByteBandedRaster extends SunWritableRaster {
054:
055: /** Data offsets for each band of image data. */
056: int[] dataOffsets;
057:
058: /** Scanline stride of the image data contained in this Raster. */
059: int scanlineStride;
060:
061: /** The image data array. */
062: byte[][] data;
063:
064: /** A cached copy of minX + width for use in bounds checks. */
065: private int maxX;
066:
067: /** A cached copy of minY + height for use in bounds checks. */
068: private int maxY;
069:
070: /**
071: * Constructs a ByteBandedRaster with the given sampleModel. The
072: * Raster's upper left corner is origin and it is the same
073: * size as the SampleModel. A dataBuffer large
074: * enough to describe the Raster is automatically created. SampleModel
075: * must be of type BandedSampleModel.
076: * @param sampleModel The SampleModel that specifies the layout.
077: * @param origin The Point that specifies the origin.
078: */
079: public ByteBandedRaster(SampleModel sampleModel, Point origin) {
080: this (sampleModel, sampleModel.createDataBuffer(),
081: new Rectangle(origin.x, origin.y, sampleModel
082: .getWidth(), sampleModel.getHeight()), origin,
083: null);
084: }
085:
086: /**
087: * Constructs a ByteBanded Raster with the given sampleModel
088: * and DataBuffer. The Raster's upper left corner is origin and
089: * it is the same size as the SampleModel. The DataBuffer is not
090: * initialized and must be a DataBufferShort compatible with SampleModel.
091: * SampleModel must be of type BandedSampleModel.
092: * @param sampleModel The SampleModel that specifies the layout.
093: * @param dataBuffer The DataBufferShort that contains the image data.
094: * @param origin The Point that specifies the origin.
095: */
096: public ByteBandedRaster(SampleModel sampleModel,
097: DataBuffer dataBuffer, Point origin) {
098: this (sampleModel, dataBuffer, new Rectangle(origin.x, origin.y,
099: sampleModel.getWidth(), sampleModel.getHeight()),
100: origin, null);
101: }
102:
103: /**
104: * Constructs a ByteBandedRaster with the given sampleModel,
105: * DataBuffer, and parent. DataBuffer must be a DataBufferShort and
106: * SampleModel must be of type BandedSampleModel.
107: * When translated into the base Raster's
108: * coordinate system, aRegion must be contained by the base Raster.
109: * Origin is the coordinate in the new Raster's coordinate system of
110: * the origin of the base Raster. (The base Raster is the Raster's
111: * ancestor which has no parent.)
112: *
113: * Note that this constructor should generally be called by other
114: * constructors or create methods, it should not be used directly.
115: * @param sampleModel The SampleModel that specifies the layout.
116: * @param dataBuffer The DataBufferShort that contains the image data.
117: * @param aRegion The Rectangle that specifies the image area.
118: * @param origin The Point that specifies the origin.
119: * @param parent The parent (if any) of this raster.
120: */
121: public ByteBandedRaster(SampleModel sampleModel,
122: DataBuffer dataBuffer, Rectangle aRegion, Point origin,
123: ByteBandedRaster parent) {
124:
125: super (sampleModel, dataBuffer, aRegion, origin, parent);
126: this .maxX = minX + width;
127: this .maxY = minY + height;
128:
129: if (!(dataBuffer instanceof DataBufferByte)) {
130: throw new RasterFormatException(
131: "ByteBandedRaster must have" + "byte DataBuffers");
132: }
133: DataBufferByte dbb = (DataBufferByte) dataBuffer;
134:
135: if (sampleModel instanceof BandedSampleModel) {
136: BandedSampleModel bsm = (BandedSampleModel) sampleModel;
137: this .scanlineStride = bsm.getScanlineStride();
138: int bankIndices[] = bsm.getBankIndices();
139: int bandOffsets[] = bsm.getBandOffsets();
140: int dOffsets[] = dbb.getOffsets();
141: dataOffsets = new int[bankIndices.length];
142: data = new byte[bankIndices.length][];
143: int xOffset = aRegion.x - origin.x;
144: int yOffset = aRegion.y - origin.y;
145: for (int i = 0; i < bankIndices.length; i++) {
146: data[i] = stealData(dbb, bankIndices[i]);
147: dataOffsets[i] = dOffsets[bankIndices[i]] + xOffset
148: + yOffset * scanlineStride + bandOffsets[i];
149: }
150: } else {
151: throw new RasterFormatException(
152: "ByteBandedRasters must have"
153: + "BandedSampleModels");
154: }
155: verify(false);
156: }
157:
158: /**
159: * Returns a copy of the data offsets array. For each band the data
160: * offset is the index into the band's data array, of the first sample
161: * of the band.
162: */
163: public int[] getDataOffsets() {
164: return (int[]) dataOffsets.clone();
165: }
166:
167: /**
168: * Returns data offset for the specified band. The data offset
169: * is the index into the band's data array
170: * in which the first sample of the first scanline is stored.
171: * @param The band whose offset is returned.
172: */
173: public int getDataOffset(int band) {
174: return dataOffsets[band];
175: }
176:
177: /**
178: * Returns the scanline stride -- the number of data array elements
179: * between a given sample and the sample in the same column
180: * of the next row in the same band.
181: */
182: public int getScanlineStride() {
183: return scanlineStride;
184: }
185:
186: /**
187: * Returns the pixel stride, which is always equal to one for
188: * a Raster with a BandedSampleModel.
189: */
190: public int getPixelStride() {
191: return 1;
192: }
193:
194: /**
195: * Returns a reference to the entire data array.
196: */
197: public byte[][] getDataStorage() {
198: return data;
199: }
200:
201: /**
202: * Returns a reference to the specific band data array.
203: */
204: public byte[] getDataStorage(int band) {
205: return data[band];
206: }
207:
208: /**
209: * Returns the data elements for all bands at the specified
210: * location.
211: * An ArrayIndexOutOfBounds exception will be thrown at runtime
212: * if the pixel coordinate is out of bounds.
213: * A ClassCastException will be thrown if the input object is non null
214: * and references anything other than an array of transferType.
215: * @param x The X coordinate of the pixel location.
216: * @param y The Y coordinate of the pixel location.
217: * @param outData An object reference to an array of type defined by
218: * getTransferType() and length getNumDataElements().
219: * If null an array of appropriate type and size will be
220: * allocated.
221: * @return An object reference to an array of type defined by
222: * getTransferType() with the request pixel data.
223: */
224: public Object getDataElements(int x, int y, Object obj) {
225: if ((x < this .minX) || (y < this .minY) || (x >= this .maxX)
226: || (y >= this .maxY)) {
227: throw new ArrayIndexOutOfBoundsException(
228: "Coordinate out of bounds!");
229: }
230: byte outData[];
231: if (obj == null) {
232: outData = new byte[numDataElements];
233: } else {
234: outData = (byte[]) obj;
235: }
236: int off = (y - minY) * scanlineStride + (x - minX);
237:
238: for (int band = 0; band < numDataElements; band++) {
239: outData[band] = data[band][dataOffsets[band] + off];
240: }
241:
242: return outData;
243: }
244:
245: /**
246: * Returns an array of data elements from the specified
247: * rectangular region.
248: * An ArrayIndexOutOfBounds exception will be thrown at runtime
249: * if the pixel coordinates are out of bounds.
250: * A ClassCastException will be thrown if the input object is non null
251: * and references anything other than an array of transferType.
252: * <pre>
253: * byte[] bandData = (byte[])raster.getDataElement(x, y, w, h, null);
254: * int numDataElements = raster.getNumDataElements();
255: * byte[] pixel = new byte[numDataElements];
256: * // To find a data element at location (x2, y2)
257: * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
258: * pixel, 0, numDataElements);
259: * </pre>
260: * @param x The X coordinate of the upper left pixel location.
261: * @param y The Y coordinate of the upper left pixel location.
262: * @param width Width of the pixel rectangle.
263: * @param height Height of the pixel rectangle.
264: * @param outData An object reference to an array of type defined by
265: * getTransferType() and length w*h*getNumDataElements().
266: * If null an array of appropriate type and size will be
267: * allocated.
268: * @return An object reference to an array of type defined by
269: * getTransferType() with the request pixel data.
270: */
271: public Object getDataElements(int x, int y, int w, int h, Object obj) {
272: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
273: || (y + h > this .maxY)) {
274: throw new ArrayIndexOutOfBoundsException(
275: "Coordinate out of bounds!");
276: }
277: byte outData[];
278: if (obj == null) {
279: outData = new byte[numDataElements * w * h];
280: } else {
281: outData = (byte[]) obj;
282: }
283: int yoff = (y - minY) * scanlineStride + (x - minX);
284:
285: for (int c = 0; c < numDataElements; c++) {
286: int off = c;
287: byte[] bank = data[c];
288: int dataOffset = dataOffsets[c];
289:
290: int yoff2 = yoff;
291: for (int ystart = 0; ystart < h; ystart++, yoff2 += scanlineStride) {
292: int xoff = dataOffset + yoff2;
293: for (int xstart = 0; xstart < w; xstart++) {
294: outData[off] = bank[xoff++];
295: off += numDataElements;
296: }
297: }
298: }
299:
300: return outData;
301: }
302:
303: /**
304: * Returns a byte array of data elements from the specified rectangular
305: * region for the specified band.
306: * An ArrayIndexOutOfBounds exception will be thrown at runtime
307: * if the pixel coordinates are out of bounds.
308: * <pre>
309: * byte[] bandData = raster.getByteData(x, y, w, h, null);
310: * // To find the data element at location (x2, y2)
311: * byte bandElement = bandData[((y2-y)*w + (x2-x))];
312: * </pre>
313: * @param x The X coordinate of the upper left pixel location.
314: * @param y The Y coordinate of the upper left pixel location.
315: * @param width Width of the pixel rectangle.
316: * @param height Height of the pixel rectangle.
317: * @param band The band to return.
318: * @param outData If non-null, data elements for all bands
319: * at the specified location are returned in this array.
320: * @return Data array with data elements for all bands.
321: */
322: public byte[] getByteData(int x, int y, int w, int h, int band,
323: byte[] outData) {
324: // Bounds check for 'band' will be performed automatically
325: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
326: || (y + h > this .maxY)) {
327: throw new ArrayIndexOutOfBoundsException(
328: "Coordinate out of bounds!");
329: }
330: if (outData == null) {
331: outData = new byte[scanlineStride * h];
332: }
333: int yoff = (y - minY) * scanlineStride + (x - minX)
334: + dataOffsets[band];
335:
336: if (scanlineStride == w) {
337: System.arraycopy(data[band], yoff, outData, 0, w * h);
338: } else {
339: int off = 0;
340: for (int ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
341: System.arraycopy(data[band], yoff, outData, off, w);
342: off += w;
343: }
344: }
345:
346: return outData;
347: }
348:
349: /**
350: * Returns a byte array of data elements from the specified rectangular
351: * region.
352: * An ArrayIndexOutOfBounds exception will be thrown at runtime
353: * if the pixel coordinates are out of bounds.
354: * <pre>
355: * byte[] bandData = raster.getByteData(x, y, w, h, null);
356: * int numDataElements = raster.getNumDataElements();
357: * byte[] pixel = new byte[numDataElements];
358: * // To find a data element at location (x2, y2)
359: * System.arraycopy(bandData, ((y2-y)*w + (x2-x))*numDataElements,
360: * pixel, 0, numDataElements);
361: * </pre>
362: * @param x The X coordinate of the upper left pixel location.
363: * @param y The Y coordinate of the upper left pixel location.
364: * @param width Width of the pixel rectangle.
365: * @param height Height of the pixel rectangle.
366: * @param outData If non-null, data elements for all bands
367: * at the specified location are returned in this array.
368: * @return Data array with data elements for all bands.
369: */
370: public byte[] getByteData(int x, int y, int w, int h, byte[] outData) {
371: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
372: || (y + h > this .maxY)) {
373: throw new ArrayIndexOutOfBoundsException(
374: "Coordinate out of bounds!");
375: }
376: if (outData == null) {
377: outData = new byte[numDataElements * scanlineStride * h];
378: }
379: int yoff = (y - minY) * scanlineStride + (x - minX);
380:
381: for (int c = 0; c < numDataElements; c++) {
382: int off = c;
383: byte[] bank = data[c];
384: int dataOffset = dataOffsets[c];
385:
386: // REMIND: Should keep track if dataoffsets are in a nice order
387: int yoff2 = yoff;
388: for (int ystart = 0; ystart < h; ystart++, yoff2 += scanlineStride) {
389: int xoff = dataOffset + yoff2;
390: for (int xstart = 0; xstart < w; xstart++) {
391: outData[off] = bank[xoff++];
392: off += numDataElements;
393: }
394: }
395: }
396:
397: return outData;
398: }
399:
400: /**
401: * Stores the data elements for all bands at the specified location.
402: * An ArrayIndexOutOfBounds exception will be thrown at runtime
403: * if the pixel coordinate is out of bounds.
404: * A ClassCastException will be thrown if the input object is non null
405: * and references anything other than an array of transferType.
406: * @param x The X coordinate of the pixel location.
407: * @param y The Y coordinate of the pixel location.
408: * @param inData An object reference to an array of type defined by
409: * getTransferType() and length getNumDataElements()
410: * containing the pixel data to place at x,y.
411: */
412: public void setDataElements(int x, int y, Object obj) {
413: if ((x < this .minX) || (y < this .minY) || (x >= this .maxX)
414: || (y >= this .maxY)) {
415: throw new ArrayIndexOutOfBoundsException(
416: "Coordinate out of bounds!");
417: }
418: byte inData[] = (byte[]) obj;
419: int off = (y - minY) * scanlineStride + (x - minX);
420: for (int i = 0; i < numDataElements; i++) {
421: data[i][dataOffsets[i] + off] = inData[i];
422: }
423: markDirty();
424: }
425:
426: /**
427: * Stores the Raster data at the specified location.
428: * An ArrayIndexOutOfBounds exception will be thrown at runtime
429: * if the pixel coordinate is out of bounds.
430: * @param x The X coordinate of the pixel location.
431: * @param y The Y coordinate of the pixel location.
432: * @param inRaster Raster of data to place at x,y location.
433: */
434: public void setDataElements(int x, int y, Raster inRaster) {
435: int dstOffX = inRaster.getMinX() + x;
436: int dstOffY = inRaster.getMinY() + y;
437: int width = inRaster.getWidth();
438: int height = inRaster.getHeight();
439: if ((dstOffX < this .minX) || (dstOffY < this .minY)
440: || (dstOffX + width > this .maxX)
441: || (dstOffY + height > this .maxY)) {
442: throw new ArrayIndexOutOfBoundsException(
443: "Coordinate out of bounds!");
444: }
445:
446: setDataElements(dstOffX, dstOffY, width, height, inRaster);
447: }
448:
449: /**
450: * Stores the Raster data at the specified location.
451: * @param dstX The absolute X coordinate of the destination pixel
452: * that will receive a copy of the upper-left pixel of the
453: * inRaster
454: * @param dstY The absolute Y coordinate of the destination pixel
455: * that will receive a copy of the upper-left pixel of the
456: * inRaster
457: * @param width The number of pixels to store horizontally
458: * @param height The number of pixels to store vertically
459: * @param inRaster Raster of data to place at x,y location.
460: */
461: private void setDataElements(int dstX, int dstY, int width,
462: int height, Raster inRaster) {
463: // Assume bounds checking has been performed previously
464: if (width <= 0 || height <= 0) {
465: return;
466: }
467:
468: int srcOffX = inRaster.getMinX();
469: int srcOffY = inRaster.getMinY();
470: Object tdata = null;
471:
472: // // REMIND: Do something faster!
473: // if (inRaster instanceof ByteBandedRaster) {
474: // }
475:
476: for (int startY = 0; startY < height; startY++) {
477: // Grab one scanline at a time
478: tdata = inRaster.getDataElements(srcOffX, srcOffY + startY,
479: width, 1, tdata);
480: setDataElements(dstX, dstY + startY, width, 1, tdata);
481: }
482: }
483:
484: /**
485: * Stores an array of data elements into the specified rectangular
486: * region.
487: * An ArrayIndexOutOfBounds exception will be thrown at runtime
488: * if the pixel coordinates are out of bounds.
489: * A ClassCastException will be thrown if the input object is non null
490: * and references anything other than an array of transferType.
491: * The data elements in the
492: * data array are assumed to be packed. That is, a data element
493: * for the nth band at location (x2, y2) would be found at:
494: * <pre>
495: * inData[((y2-y)*w + (x2-x))*numDataElements + n]
496: * </pre>
497: * @param x The X coordinate of the upper left pixel location.
498: * @param y The Y coordinate of the upper left pixel location.
499: * @param w Width of the pixel rectangle.
500: * @param h Height of the pixel rectangle.
501: * @param inData An object reference to an array of type defined by
502: * getTransferType() and length w*h*getNumDataElements()
503: * containing the pixel data to place between x,y and
504: * x+h, y+h.
505: */
506: public void setDataElements(int x, int y, int w, int h, Object obj) {
507: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
508: || (y + h > this .maxY)) {
509: throw new ArrayIndexOutOfBoundsException(
510: "Coordinate out of bounds!");
511: }
512: byte inData[] = (byte[]) obj;
513: int yoff = (y - minY) * scanlineStride + (x - minX);
514:
515: for (int c = 0; c < numDataElements; c++) {
516: int off = c;
517: byte[] bank = data[c];
518: int dataOffset = dataOffsets[c];
519:
520: int yoff2 = yoff;
521: for (int ystart = 0; ystart < h; ystart++, yoff2 += scanlineStride) {
522: int xoff = dataOffset + yoff2;
523: for (int xstart = 0; xstart < w; xstart++) {
524: bank[xoff++] = inData[off];
525: off += numDataElements;
526: }
527: }
528: }
529:
530: markDirty();
531: }
532:
533: /**
534: * Stores a byte array of data elements into the specified rectangular
535: * region.
536: * An ArrayIndexOutOfBounds exception will be thrown at runtime
537: * if the pixel coordinates are out of bounds.
538: * The data elements in the
539: * data array are assumed to be packed. That is, a data element
540: * for the nth band at location (x2, y2) would be found at:
541: * <pre>
542: * inData[((y2-y)*w + (x2-x))*numDataElements + n]
543: * </pre>
544: * @param x The X coordinate of the upper left pixel location.
545: * @param y The Y coordinate of the upper left pixel location.
546: * @param w Width of the pixel rectangle.
547: * @param h Height of the pixel rectangle.
548: * @param band The band to set.
549: * @param inData The data elements to be stored.
550: */
551: public void putByteData(int x, int y, int w, int h, int band,
552: byte[] inData) {
553: // Bounds check for 'band' will be performed automatically
554: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
555: || (y + h > this .maxY)) {
556: throw new ArrayIndexOutOfBoundsException(
557: "Coordinate out of bounds!");
558: }
559: int yoff = (y - minY) * scanlineStride + (x - minX)
560: + dataOffsets[band];
561: int xoff;
562: int off = 0;
563: int xstart;
564: int ystart;
565:
566: if (scanlineStride == w) {
567: System.arraycopy(inData, 0, data[band], yoff, w * h);
568: } else {
569: for (ystart = 0; ystart < h; ystart++, yoff += scanlineStride) {
570: System.arraycopy(inData, off, data[band], yoff, w);
571: off += w;
572: }
573: }
574:
575: markDirty();
576: }
577:
578: /**
579: * Stores a byte array of data elements into the specified rectangular
580: * region.
581: * An ArrayIndexOutOfBounds exception will be thrown at runtime
582: * if the pixel coordinates are out of bounds.
583: * The data elements in the
584: * data array are assumed to be packed. That is, a data element
585: * for the nth band at location (x2, y2) would be found at:
586: * <pre>
587: * inData[((y2-y)*w + (x2-x))*numDataElements + n]
588: * </pre>
589: * @param x The X coordinate of the upper left pixel location.
590: * @param y The Y coordinate of the upper left pixel location.
591: * @param w Width of the pixel rectangle.
592: * @param h Height of the pixel rectangle.
593: * @param inData The data elements to be stored.
594: */
595: public void putByteData(int x, int y, int w, int h, byte[] inData) {
596: if ((x < this .minX) || (y < this .minY) || (x + w > this .maxX)
597: || (y + h > this .maxY)) {
598: throw new ArrayIndexOutOfBoundsException(
599: "Coordinate out of bounds!");
600: }
601: int yoff = (y - minY) * scanlineStride + (x - minX);
602:
603: for (int c = 0; c < numDataElements; c++) {
604: int off = c;
605: byte[] bank = data[c];
606: int dataOffset = dataOffsets[c];
607:
608: int yoff2 = yoff;
609: for (int ystart = 0; ystart < h; ystart++, yoff2 += scanlineStride) {
610: int xoff = dataOffset + yoff2;
611: for (int xstart = 0; xstart < w; xstart++) {
612: bank[xoff++] = inData[off];
613: off += numDataElements;
614: }
615: }
616: }
617:
618: markDirty();
619: }
620:
621: /**
622: * Creates a Writable subraster given a region of the raster. The x and y
623: * coordinates specify the horizontal and vertical offsets
624: * from the upper-left corner of this raster to the upper-left corner
625: * of the subraster. A subset of the bands of the parent Raster may
626: * be specified. If this is null, then all the bands are present in the
627: * subRaster. A translation to the subRaster may also be specified.
628: * Note that the subraster will reference the same
629: * DataBuffers as the parent raster, but using different offsets.
630: * @param x X offset.
631: * @param y Y offset.
632: * @param width Width of the subraster.
633: * @param height Height of the subraster.
634: * @param x0 Translated X origin of the subraster.
635: * @param y0 Translated Y origin of the subraster.
636: * @param bandList Array of band indices.
637: * @exception RasterFormatException
638: * if the specified bounding box is outside of the parent raster.
639: */
640: public WritableRaster createWritableChild(int x, int y, int width,
641: int height, int x0, int y0, int bandList[]) {
642:
643: if (x < this .minX) {
644: throw new RasterFormatException("x lies outside raster");
645: }
646: if (y < this .minY) {
647: throw new RasterFormatException("y lies outside raster");
648: }
649: if ((x + width < x) || (x + width > this .width + this .minX)) {
650: throw new RasterFormatException(
651: "(x + width) is outside raster");
652: }
653: if ((y + height < y) || (y + height > this .height + this .minY)) {
654: throw new RasterFormatException(
655: "(y + height) is outside raster");
656: }
657:
658: SampleModel sm;
659:
660: if (bandList != null)
661: sm = sampleModel.createSubsetSampleModel(bandList);
662: else
663: sm = sampleModel;
664:
665: int deltaX = x0 - x;
666: int deltaY = y0 - y;
667:
668: return new ByteBandedRaster(sm, dataBuffer, new Rectangle(x0,
669: y0, width, height), new Point(sampleModelTranslateX
670: + deltaX, sampleModelTranslateY + deltaY), this );
671: }
672:
673: /**
674: * Creates a subraster given a region of the raster. The x and y
675: * coordinates specify the horizontal and vertical offsets
676: * from the upper-left corner of this raster to the upper-left corner
677: * of the subraster. A subset of the bands of the parent Raster may
678: * be specified. If this is null, then all the bands are present in the
679: * subRaster. A translation to the subRaster may also be specified.
680: * Note that the subraster will reference the same
681: * DataBuffers as the parent raster, but using different offsets.
682: * @param x X offset.
683: * @param y Y offset.
684: * @param width Width (in pixels) of the subraster.
685: * @param height Height (in pixels) of the subraster.
686: * @param x0 Translated X origin of the subraster.
687: * @param y0 Translated Y origin of the subraster.
688: * @param bandList Array of band indices.
689: * @exception RasterFormatException
690: * if the specified bounding box is outside of the parent raster.
691: */
692: public Raster createChild(int x, int y, int width, int height,
693: int x0, int y0, int bandList[]) {
694: return createWritableChild(x, y, width, height, x0, y0,
695: bandList);
696: }
697:
698: /**
699: * Creates a Raster with the same layout but using a different
700: * width and height, and with new zeroed data arrays.
701: */
702: public WritableRaster createCompatibleWritableRaster(int w, int h) {
703: if (w <= 0 || h <= 0) {
704: throw new RasterFormatException("negative "
705: + ((w <= 0) ? "width" : "height"));
706: }
707:
708: SampleModel sm = sampleModel.createCompatibleSampleModel(w, h);
709:
710: return new ByteBandedRaster(sm, new Point(0, 0));
711: }
712:
713: /**
714: * Creates a Raster with the same layout and the same
715: * width and height, and with new zeroed data arrays. If
716: * the Raster is a subRaster, this will call
717: * createCompatibleRaster(width, height).
718: */
719: public WritableRaster createCompatibleWritableRaster() {
720: return createCompatibleWritableRaster(width, height);
721: }
722:
723: /**
724: * Verify that the layout parameters are consistent with
725: * the data. If strictCheck
726: * is false, this method will check for ArrayIndexOutOfBounds conditions. If
727: * strictCheck is true, this method will check for additional error
728: * conditions such as line wraparound (width of a line greater than
729: * the scanline stride).
730: * @return String Error string, if the layout is incompatible with
731: * the data. Otherwise returns null.
732: */
733: private void verify(boolean strictCheck) {
734: // Make sure data for Raster is in a legal range
735: for (int i = 0; i < dataOffsets.length; i++) {
736: if (dataOffsets[i] < 0) {
737: throw new RasterFormatException(
738: "Data offsets for band " + i + "("
739: + dataOffsets[i] + ") must be >= 0");
740: }
741: }
742:
743: int maxSize = 0;
744: int size;
745:
746: for (int i = 0; i < numDataElements; i++) {
747: size = (height - 1) * scanlineStride + (width - 1)
748: + dataOffsets[i];
749: if (size > maxSize) {
750: maxSize = size;
751: }
752: }
753:
754: if (data.length == 1) {
755: if (data[0].length < maxSize * numDataElements) {
756: throw new RasterFormatException("Data array too small "
757: + "(it is " + data[0].length
758: + " and should be "
759: + (maxSize * numDataElements) + " )");
760: }
761: } else {
762: for (int i = 0; i < numDataElements; i++) {
763: if (data[i].length < maxSize) {
764: throw new RasterFormatException(
765: "Data array too small " + "(it is "
766: + data[i].length
767: + " and should be " + maxSize
768: + " )");
769: }
770: }
771: }
772: }
773:
774: public String toString() {
775: return new String("ByteBandedRaster: width = " + width
776: + " height = " + height + " #bands " + numDataElements
777: + " minX = " + minX + " minY = " + minY);
778: }
779:
780: }
|