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