001: /*
002: * $RCSfile: RawImageWriter.java,v $
003: *
004: *
005: * Copyright (c) 2005 Sun Microsystems, Inc. All Rights Reserved.
006: *
007: * Redistribution and use in source and binary forms, with or without
008: * modification, are permitted provided that the following conditions
009: * are met:
010: *
011: * - Redistribution of source code must retain the above copyright
012: * notice, this list of conditions and the following disclaimer.
013: *
014: * - Redistribution in binary form must reproduce the above copyright
015: * notice, this list of conditions and the following disclaimer in
016: * the documentation and/or other materials provided with the
017: * distribution.
018: *
019: * Neither the name of Sun Microsystems, Inc. or the names of
020: * contributors may be used to endorse or promote products derived
021: * from this software without specific prior written permission.
022: *
023: * This software is provided "AS IS," without a warranty of any
024: * kind. ALL EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND
025: * WARRANTIES, INCLUDING ANY IMPLIED WARRANTY OF MERCHANTABILITY,
026: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT, ARE HEREBY
027: * EXCLUDED. SUN MIDROSYSTEMS, INC. ("SUN") AND ITS LICENSORS SHALL
028: * NOT BE LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF
029: * USING, MODIFYING OR DISTRIBUTING THIS SOFTWARE OR ITS
030: * DERIVATIVES. IN NO EVENT WILL SUN OR ITS LICENSORS BE LIABLE FOR
031: * ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT, INDIRECT, SPECIAL,
032: * CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER CAUSED AND
033: * REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF OR
034: * INABILITY TO USE THIS SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
035: * POSSIBILITY OF SUCH DAMAGES.
036: *
037: * You acknowledge that this software is not designed or intended for
038: * use in the design, construction, operation or maintenance of any
039: * nuclear facility.
040: *
041: * $Revision: 1.1 $
042: * $Date: 2005/02/11 05:01:42 $
043: * $State: Exp $
044: */
045: package com.sun.media.imageioimpl.plugins.raw;
046:
047: import java.awt.Point;
048: import java.awt.Rectangle;
049: import java.awt.image.BandedSampleModel;
050: import java.awt.image.ColorModel;
051: import java.awt.image.ComponentSampleModel;
052: import java.awt.image.DataBuffer;
053: import java.awt.image.DataBufferByte;
054: import java.awt.image.DataBufferShort;
055: import java.awt.image.DataBufferUShort;
056: import java.awt.image.DataBufferInt;
057: import java.awt.image.DataBufferFloat;
058: import java.awt.image.DataBufferDouble;
059: import java.awt.image.IndexColorModel;
060: import java.awt.image.MultiPixelPackedSampleModel;
061: import java.awt.image.Raster;
062: import java.awt.image.RenderedImage;
063: import java.awt.image.SampleModel;
064: import java.awt.image.SinglePixelPackedSampleModel;
065: import java.awt.image.WritableRaster;
066:
067: import java.io.IOException;
068:
069: import javax.imageio.IIOImage;
070: import javax.imageio.IIOException;
071: import javax.imageio.ImageTypeSpecifier;
072: import javax.imageio.ImageWriteParam;
073: import javax.imageio.ImageWriter;
074: import javax.imageio.metadata.IIOMetadata;
075: import javax.imageio.metadata.IIOMetadataNode;
076: import javax.imageio.metadata.IIOMetadataFormatImpl;
077: import javax.imageio.metadata.IIOInvalidTreeException;
078: import javax.imageio.spi.ImageWriterSpi;
079: import javax.imageio.stream.ImageOutputStream;
080:
081: import com.sun.media.imageioimpl.common.ImageUtil;
082:
083: /**
084: * The Java Image IO plugin writer for encoding a binary RenderedImage into
085: * a Raw format.
086: *
087: * <p> The encoding process may clip, subsample or select bands using the
088: * parameters specified in the <code>ImageWriteParam</code>.
089: *
090: * Thus, when read this raw image the proper image data type
091: * should be provided.
092: *
093: * @see com.sun.media.imageio.plugins.RawImageWriteParam
094: */
095:
096: // <p> If the destination data is packed packed, the data is written in the
097: // order defined by the sample model. That the data is packed is defined as
098: // (1) if the sample model is <code>SingleSamplePackedSampleModel</code> or
099: // <code>BandedSampleModel</code>; or (2) the pixel stride or sanline stride
100: // equals to the band number; or (3) the pixel stride equals to the band
101: // number multiply the tile height; or (4) the scanline stride equals to the
102: // band number multiply the tile width; or (5) the data for a band is stored
103: // in a separate data bank.
104: //
105: // <p> Otherwise, the data is reordered in a packed pixel interleaved format,
106: // and then written into the stream. In this case the data order may be change.
107: // For example, the original image data is in the order of
108: // <pre>
109: // RRRRRRRRRRRRRRRRRRRR
110: // GGGGGGGGGGGGGGGGGGGG
111: // BBBBBBBBBBBBBBBBBBBB
112: // RRRRRRRRRRRRRRRRRRRR
113: // GGGGGGGGGGGGGGGGGGGG
114: // BBBBBBBBBBBBBBBBBBBB
115: // </pre>
116: //
117: // , and only the G and B bands are written in the stream. So the data in the
118: // stream will be in the order of
119: // <pre>
120: // GBGBGBGBGBGBGB
121: // </pre>.
122: public class RawImageWriter extends ImageWriter {
123: /** The output stream to write into */
124: private ImageOutputStream stream = null;
125:
126: /** The image index in this stream. */
127: private int imageIndex;
128:
129: /** The tile width for encoding */
130: private int tileWidth;
131:
132: /** The tile height for encoding */
133: private int tileHeight;
134:
135: /** The tile grid offset for encoding */
136: private int tileXOffset, tileYOffset;
137:
138: /** The source -> destination transformation */
139: private int scaleX, scaleY, xOffset, yOffset;
140:
141: /** The source bands to be encoded. */
142: private int[] sourceBands = null;
143:
144: /** The number of components in the image */
145: private int numBands;
146:
147: /** The source raster if write raster. */
148: private RenderedImage input;
149:
150: /** The input source raster. */
151: private Raster inputRaster;
152:
153: private Rectangle destinationRegion = null;
154:
155: private SampleModel sampleModel;
156:
157: /** Coordinate transform or sub selection is needed before encoding. */
158: private boolean noTransform = true;
159: private boolean noSubband = true;
160:
161: /** Indicates a <code>raster</code> rather than a <code>RenderedImage</code>
162: * to be encoded.
163: */
164: private boolean writeRaster = false;
165:
166: /** Whether can write optimally. */
167: private boolean optimal = false;
168:
169: /** The strides for pixel, band, and scanline. */
170: private int pxlStride, lineStride, bandStride;
171:
172: /** Constructs <code>RawImageWriter</code> based on the provided
173: * <code>ImageWriterSpi</code>.
174: */
175: public RawImageWriter(ImageWriterSpi originator) {
176: super (originator);
177: }
178:
179: public void setOutput(Object output) {
180: super .setOutput(output); // validates output
181: if (output != null) {
182: if (!(output instanceof ImageOutputStream))
183: throw new IllegalArgumentException(I18N
184: .getString("RawImageWriter0"));
185: this .stream = (ImageOutputStream) output;
186: } else
187: this .stream = null;
188: }
189:
190: public IIOMetadata getDefaultStreamMetadata(ImageWriteParam param) {
191: return null;
192: }
193:
194: public IIOMetadata getDefaultImageMetadata(
195: ImageTypeSpecifier imageType, ImageWriteParam param) {
196: return null;
197: }
198:
199: public IIOMetadata convertStreamMetadata(IIOMetadata inData,
200: ImageWriteParam param) {
201: return null;
202: }
203:
204: public IIOMetadata convertImageMetadata(IIOMetadata metadata,
205: ImageTypeSpecifier type, ImageWriteParam param) {
206: return null;
207: }
208:
209: public boolean canWriteRasters() {
210: return true;
211: }
212:
213: public ImageWriteParam getDefaultWriteParam() {
214: return new RawImageWriteParam(getLocale());
215: }
216:
217: public void write(IIOMetadata streamMetadata, IIOImage image,
218: ImageWriteParam param) throws IOException {
219: clearAbortRequest();
220: processImageStarted(imageIndex++);
221:
222: if (param == null)
223: param = getDefaultWriteParam();
224:
225: writeRaster = image.hasRaster();
226: Rectangle sourceRegion = param.getSourceRegion();
227: ColorModel colorModel = null;
228: Rectangle originalRegion = null;
229:
230: if (writeRaster) {
231: inputRaster = image.getRaster();
232: sampleModel = inputRaster.getSampleModel();
233: originalRegion = inputRaster.getBounds();
234: } else {
235: input = image.getRenderedImage();
236: sampleModel = input.getSampleModel();
237:
238: originalRegion = new Rectangle(input.getMinX(), input
239: .getMinY(), input.getWidth(), input.getHeight());
240:
241: colorModel = input.getColorModel();
242: }
243:
244: if (sourceRegion == null)
245: sourceRegion = (Rectangle) originalRegion.clone();
246: else
247: sourceRegion = sourceRegion.intersection(originalRegion);
248:
249: if (sourceRegion.isEmpty())
250: throw new RuntimeException(I18N
251: .getString("RawImageWriter1"));
252:
253: scaleX = param.getSourceXSubsampling();
254: scaleY = param.getSourceYSubsampling();
255: xOffset = param.getSubsamplingXOffset();
256: yOffset = param.getSubsamplingYOffset();
257:
258: sourceRegion.translate(xOffset, yOffset);
259: sourceRegion.width -= xOffset;
260: sourceRegion.height -= yOffset;
261:
262: xOffset = sourceRegion.x % scaleX;
263: yOffset = sourceRegion.y % scaleY;
264:
265: int minX = sourceRegion.x / scaleX;
266: int minY = sourceRegion.y / scaleY;
267: int w = (sourceRegion.width + scaleX - 1) / scaleX;
268: int h = (sourceRegion.height + scaleY - 1) / scaleY;
269:
270: destinationRegion = new Rectangle(minX, minY, w, h);
271: noTransform = destinationRegion.equals(originalRegion);
272:
273: tileHeight = sampleModel.getHeight();
274: tileWidth = sampleModel.getWidth();
275: if (noTransform) {
276: if (writeRaster) {
277: tileXOffset = inputRaster.getMinX();
278: tileYOffset = inputRaster.getMinY();
279: } else {
280: tileXOffset = input.getTileGridXOffset();
281: tileYOffset = input.getTileGridYOffset();
282: }
283: } else {
284: tileXOffset = destinationRegion.x;
285: tileYOffset = destinationRegion.y;
286: }
287:
288: sourceBands = param.getSourceBands();
289: boolean noSubband = true;
290: numBands = sampleModel.getNumBands();
291:
292: if (sourceBands != null) {
293: sampleModel = sampleModel
294: .createSubsetSampleModel(sourceBands);
295: colorModel = null;
296: noSubband = false;
297: numBands = sampleModel.getNumBands();
298: } else {
299: sourceBands = new int[numBands];
300: for (int i = 0; i < numBands; i++)
301: sourceBands[i] = i;
302: }
303:
304: if (sampleModel instanceof ComponentSampleModel) {
305: ComponentSampleModel csm = (ComponentSampleModel) sampleModel;
306: int[] bandOffsets = csm.getBandOffsets();
307:
308: bandStride = bandOffsets[0];
309:
310: for (int i = 1; i < bandOffsets.length; i++)
311: if (bandStride > bandOffsets[i])
312: bandStride = bandOffsets[i];
313:
314: int[] bankIndices = csm.getBankIndices();
315: int numBank = bankIndices[0];
316: for (int i = 1; i < bankIndices.length; i++)
317: if (numBank > bankIndices[i])
318: numBank = bankIndices[i];
319:
320: pxlStride = csm.getPixelStride();
321: lineStride = csm.getScanlineStride();
322:
323: optimal = bandStride == 0
324: || (pxlStride < lineStride && pxlStride == numBands)
325: || (lineStride < pxlStride && lineStride == numBands)
326: || (pxlStride < lineStride && lineStride == numBands
327: * csm.getWidth())
328: || (lineStride < pxlStride && pxlStride == numBands
329: * csm.getHeight())
330: || csm instanceof BandedSampleModel;
331: } else if (sampleModel instanceof SinglePixelPackedSampleModel
332: || sampleModel instanceof MultiPixelPackedSampleModel) {
333: optimal = true;
334: }
335:
336: int numXTiles = getMaxTileX() - getMinTileX() + 1;
337: int totalTiles = numXTiles
338: * (getMaxTileY() - getMinTileY() + 1);
339:
340: for (int y = getMinTileY(); y <= getMaxTileY(); y++) {
341: for (int x = getMinTileX(); x <= getMaxTileX(); x++) {
342: writeRaster(getTile(x, y));
343:
344: float percentage = (x + y * numXTiles + 1.0F)
345: / totalTiles;
346: processImageProgress(percentage * 100.0F);
347: }
348: }
349:
350: stream.flush();
351: if (abortRequested())
352: processWriteAborted();
353: else
354: processImageComplete();
355: }
356:
357: //XXX: just for test
358: public int getWidth() {
359: return destinationRegion.width;
360: }
361:
362: public int getHeight() {
363: return destinationRegion.height;
364: }
365:
366: private void writeRaster(Raster raster) throws IOException {
367: int numBank = 0;
368: int bandStride = 0;
369: int[] bankIndices = null;
370: int[] bandOffsets = null;
371: int bandSize = 0;
372: int numBand = sampleModel.getNumBands();
373: int type = sampleModel.getDataType();
374:
375: if (sampleModel instanceof ComponentSampleModel) {
376: ComponentSampleModel csm = (ComponentSampleModel) sampleModel;
377:
378: bandOffsets = csm.getBandOffsets();
379: for (int i = 0; i < numBand; i++)
380: if (bandStride < bandOffsets[i])
381: bandStride = bandOffsets[i];
382:
383: bankIndices = csm.getBankIndices();
384: for (int i = 0; i < numBand; i++)
385: if (numBank < bankIndices[i])
386: numBank = bankIndices[i];
387:
388: bandSize = (int) ImageUtil.getBandSize(sampleModel);
389: }
390:
391: byte[] bdata = null;
392: short[] sdata = null;
393: int[] idata = null;
394: float[] fdata = null;
395: double[] ddata = null;
396:
397: if (raster.getParent() != null
398: && !sampleModel.equals(raster.getParent()
399: .getSampleModel())) {
400: WritableRaster ras = Raster.createWritableRaster(
401: sampleModel, new Point(raster.getMinX(), raster
402: .getMinY()));
403: ras.setRect(raster);
404: raster = ras;
405: }
406:
407: DataBuffer data = raster.getDataBuffer();
408:
409: if (optimal) {
410: if (numBank > 0) { //multiple data bank
411: for (int i = 0; i < numBands; i++) {
412: int bank = bankIndices[sourceBands[i]];
413: switch (type) {
414: case DataBuffer.TYPE_BYTE:
415: bdata = ((DataBufferByte) data).getData(bank);
416: stream.write(bdata, 0, bdata.length);
417: break;
418: case DataBuffer.TYPE_SHORT:
419: sdata = ((DataBufferShort) data).getData(bank);
420: stream.writeShorts(sdata, 0, sdata.length);
421: break;
422: case DataBuffer.TYPE_USHORT:
423: sdata = ((DataBufferUShort) data).getData(bank);
424: stream.writeShorts(sdata, 0, sdata.length);
425: break;
426: case DataBuffer.TYPE_INT:
427: idata = ((DataBufferInt) data).getData(bank);
428: stream.writeInts(idata, 0, idata.length);
429: break;
430: case DataBuffer.TYPE_FLOAT:
431: fdata = ((DataBufferFloat) data).getData(bank);
432: stream.writeFloats(fdata, 0, fdata.length);
433: break;
434: case DataBuffer.TYPE_DOUBLE:
435: ddata = ((DataBufferDouble) data).getData(bank);
436: stream.writeDoubles(ddata, 0, ddata.length);
437: break;
438: }
439: }
440: } else { // Single data bank
441: switch (type) {
442: case DataBuffer.TYPE_BYTE:
443: bdata = ((DataBufferByte) data).getData();
444: break;
445: case DataBuffer.TYPE_SHORT:
446: sdata = ((DataBufferShort) data).getData();
447: break;
448: case DataBuffer.TYPE_USHORT:
449: sdata = ((DataBufferUShort) data).getData();
450: break;
451: case DataBuffer.TYPE_INT:
452: idata = ((DataBufferInt) data).getData();
453: break;
454: case DataBuffer.TYPE_FLOAT:
455: fdata = ((DataBufferFloat) data).getData();
456: break;
457: case DataBuffer.TYPE_DOUBLE:
458: ddata = ((DataBufferDouble) data).getData();
459: break;
460: }
461:
462: if (!noSubband
463: && bandStride >= raster.getWidth()
464: * raster.getHeight() * (numBands - 1)) {
465:
466: for (int i = 0; i < numBands; i++) {
467: int offset = bandOffsets[sourceBands[i]];
468: switch (type) {
469: case DataBuffer.TYPE_BYTE:
470: stream.write(bdata, offset, bandSize);
471: break;
472: case DataBuffer.TYPE_SHORT:
473: case DataBuffer.TYPE_USHORT:
474: stream.writeShorts(sdata, offset, bandSize);
475: break;
476: case DataBuffer.TYPE_INT:
477: stream.writeInts(idata, offset, bandSize);
478: break;
479: case DataBuffer.TYPE_FLOAT:
480: stream.writeFloats(fdata, offset, bandSize);
481: break;
482: case DataBuffer.TYPE_DOUBLE:
483: stream
484: .writeDoubles(ddata, offset,
485: bandSize);
486: break;
487: }
488: }
489: } else {
490: switch (type) {
491: case DataBuffer.TYPE_BYTE:
492: stream.write(bdata, 0, bdata.length);
493: break;
494: case DataBuffer.TYPE_SHORT:
495: case DataBuffer.TYPE_USHORT:
496: stream.writeShorts(sdata, 0, sdata.length);
497: break;
498: case DataBuffer.TYPE_INT:
499: stream.writeInts(idata, 0, idata.length);
500: break;
501: case DataBuffer.TYPE_FLOAT:
502: stream.writeFloats(fdata, 0, fdata.length);
503: break;
504: case DataBuffer.TYPE_DOUBLE:
505: stream.writeDoubles(ddata, 0, ddata.length);
506: break;
507: }
508: }
509: }
510: } else if (sampleModel instanceof ComponentSampleModel) {
511: // The others, must be a ComponentSampleModel
512: switch (type) {
513: case DataBuffer.TYPE_BYTE:
514: bdata = ((DataBufferByte) data).getData();
515: break;
516: case DataBuffer.TYPE_SHORT:
517: sdata = ((DataBufferShort) data).getData();
518: break;
519: case DataBuffer.TYPE_USHORT:
520: sdata = ((DataBufferUShort) data).getData();
521: break;
522: case DataBuffer.TYPE_INT:
523: idata = ((DataBufferInt) data).getData();
524: break;
525: case DataBuffer.TYPE_FLOAT:
526: fdata = ((DataBufferFloat) data).getData();
527: break;
528: case DataBuffer.TYPE_DOUBLE:
529: ddata = ((DataBufferDouble) data).getData();
530: break;
531: }
532:
533: ComponentSampleModel csm = (ComponentSampleModel) sampleModel;
534: int offset = csm.getOffset(raster.getMinX()
535: - raster.getSampleModelTranslateX(), raster
536: .getMinY()
537: - raster.getSampleModelTranslateY())
538: - bandOffsets[0];
539:
540: int srcSkip = pxlStride;
541: int copyLength = 1;
542: int innerStep = pxlStride;
543:
544: int width = raster.getWidth();
545: int height = raster.getHeight();
546:
547: int innerBound = width;
548: int outerBound = height;
549:
550: if (srcSkip < lineStride) {
551: if (bandStride > pxlStride)
552: copyLength = width;
553: srcSkip = lineStride;
554: } else {
555: if (bandStride > lineStride)
556: copyLength = height;
557: innerStep = lineStride;
558: innerBound = height;
559: outerBound = width;
560: }
561:
562: int writeLength = innerBound * numBands;
563: byte[] destBBuf = null;
564: short[] destSBuf = null;
565: int[] destIBuf = null;
566: float[] destFBuf = null;
567: double[] destDBuf = null;
568: Object srcBuf = null;
569: Object dstBuf = null;
570:
571: switch (type) {
572: case DataBuffer.TYPE_BYTE:
573: srcBuf = bdata;
574: dstBuf = destBBuf = new byte[writeLength];
575: break;
576: case DataBuffer.TYPE_SHORT:
577: case DataBuffer.TYPE_USHORT:
578: srcBuf = sdata;
579: dstBuf = destSBuf = new short[writeLength];
580: break;
581: case DataBuffer.TYPE_INT:
582: srcBuf = idata;
583: dstBuf = destIBuf = new int[writeLength];
584: break;
585: case DataBuffer.TYPE_FLOAT:
586: srcBuf = fdata;
587: dstBuf = destFBuf = new float[writeLength];
588: break;
589: case DataBuffer.TYPE_DOUBLE:
590: srcBuf = ddata;
591: dstBuf = destDBuf = new double[writeLength];
592: break;
593: }
594:
595: if (copyLength > 1) {
596: for (int i = 0; i < outerBound; i++) {
597: for (int b = 0; b < numBands; b++) {
598: int bandOffset = bandOffsets[b];
599:
600: System.arraycopy(srcBuf, offset + bandOffset,
601: dstBuf, b * innerBound, innerBound);
602: }
603:
604: switch (type) {
605: case DataBuffer.TYPE_BYTE:
606: stream.write((byte[]) dstBuf, 0, writeLength);
607: break;
608: case DataBuffer.TYPE_SHORT:
609: case DataBuffer.TYPE_USHORT:
610: stream.writeShorts((short[]) dstBuf, 0,
611: writeLength);
612: break;
613: case DataBuffer.TYPE_INT:
614: stream
615: .writeInts((int[]) dstBuf, 0,
616: writeLength);
617: break;
618: case DataBuffer.TYPE_FLOAT:
619: stream.writeFloats((float[]) dstBuf, 0,
620: writeLength);
621: break;
622: case DataBuffer.TYPE_DOUBLE:
623: stream.writeDoubles((double[]) dstBuf, 0,
624: writeLength);
625: break;
626: }
627: offset += srcSkip;
628: }
629: } else {
630: switch (type) {
631: case DataBuffer.TYPE_BYTE: {
632: for (int i = 0; i < outerBound; i++) {
633: for (int b = 0, k = 0; b < numBands; b++) {
634: int bandOffset = bandOffsets[b];
635:
636: for (int j = 0, m = offset; j < innerBound; j++, m += innerStep)
637: // copy one sample to the destination buffer
638: destBBuf[k++] = bdata[m + bandOffset];
639: }
640:
641: stream.write(destBBuf, 0, writeLength);
642: offset += srcSkip;
643: }
644: }
645: break;
646: case DataBuffer.TYPE_SHORT:
647: case DataBuffer.TYPE_USHORT: {
648: for (int i = 0; i < outerBound; i++) {
649: for (int b = 0, k = 0; b < numBands; b++) {
650: int bandOffset = bandOffsets[b];
651:
652: for (int j = 0, m = offset; j < innerBound; j++, m += innerStep)
653: // copy one sample to the destination buffer
654: destSBuf[k++] = sdata[m + bandOffset];
655: }
656:
657: stream.writeShorts(destSBuf, 0, writeLength);
658: offset += srcSkip;
659: }
660: }
661: break;
662: case DataBuffer.TYPE_INT: {
663: for (int i = 0; i < outerBound; i++) {
664: for (int b = 0, k = 0; b < numBands; b++) {
665: int bandOffset = bandOffsets[b];
666:
667: for (int j = 0, m = offset; j < innerBound; j++, m += innerStep)
668: // copy one sample to the destination buffer
669: destIBuf[k++] = idata[m + bandOffset];
670: }
671:
672: stream.writeInts(destIBuf, 0, writeLength);
673: offset += srcSkip;
674: }
675: }
676: break;
677: case DataBuffer.TYPE_FLOAT: {
678: for (int i = 0; i < outerBound; i++) {
679: for (int b = 0, k = 0; b < numBands; b++) {
680: int bandOffset = bandOffsets[b];
681:
682: for (int j = 0, m = offset; j < innerBound; j++, m += innerStep)
683: // copy one sample to the destination buffer
684: destFBuf[k++] = fdata[m + bandOffset];
685: }
686:
687: stream.writeFloats(destFBuf, 0, writeLength);
688: offset += srcSkip;
689: }
690: }
691: break;
692: case DataBuffer.TYPE_DOUBLE: {
693: for (int i = 0; i < outerBound; i++) {
694: for (int b = 0, k = 0; b < numBands; b++) {
695: int bandOffset = bandOffsets[b];
696:
697: for (int j = 0, m = offset; j < innerBound; j++, m += innerStep)
698: // copy one sample to the destination buffer
699: destDBuf[k++] = ddata[m + bandOffset];
700: }
701:
702: stream.writeDoubles(destDBuf, 0, writeLength);
703: offset += srcSkip;
704: }
705: }
706: break;
707: }
708: }
709: }
710: }
711:
712: private Raster getTile(int tileX, int tileY) {
713: int sx = tileXOffset + tileX * tileWidth;
714: int sy = tileYOffset + tileY * tileHeight;
715: Rectangle bounds = new Rectangle(sx, sy, tileWidth, tileHeight);
716:
717: if (writeRaster) {
718: bounds = bounds.intersection(destinationRegion);
719: if (noTransform) {
720: return inputRaster.createChild(bounds.x, bounds.y,
721: bounds.width, bounds.height, bounds.x,
722: bounds.y, sourceBands);
723: }
724:
725: sx = bounds.x;
726: sy = bounds.y;
727:
728: WritableRaster ras = Raster.createWritableRaster(
729: sampleModel, new Point(sx, sy));
730:
731: int x = mapToSourceX(sx);
732: int y = mapToSourceY(sy);
733:
734: int minY = inputRaster.getMinY();
735: int maxY = inputRaster.getMinY() + inputRaster.getHeight();
736:
737: int cTileWidth = bounds.width;
738:
739: int length = (cTileWidth - 1) * scaleX + 1;
740:
741: for (int j = 0; j < bounds.height; j++, sy++, y += scaleY) {
742: if (y < minY || y >= maxY)
743: continue;
744: Raster source = inputRaster.createChild(x, y, length,
745: 1, x, y, null);
746: int tempX = sx;
747: for (int i = 0, offset = x; i < cTileWidth; i++, tempX++, offset += scaleX) {
748: for (int k = 0; k < numBands; k++) {
749: int p = source.getSample(offset, y,
750: sourceBands[k]);
751: ras.setSample(tempX, sy, k, p);
752: }
753: }
754: }
755:
756: return ras;
757:
758: } else {
759: if (noTransform) {
760: Raster ras = input.getTile(tileX, tileY);
761: if (destinationRegion.contains(bounds) && noSubband)
762: return ras;
763: else {
764: bounds = bounds.intersection(destinationRegion);
765: return ras.createChild(bounds.x, bounds.y,
766: bounds.width, bounds.height, bounds.x,
767: bounds.y, sourceBands);
768: }
769: }
770:
771: bounds = bounds.intersection(destinationRegion);
772: sx = bounds.x;
773: sy = bounds.y;
774:
775: WritableRaster ras = Raster.createWritableRaster(
776: sampleModel, new Point(sx, sy));
777:
778: int x = mapToSourceX(sx);
779: int y = mapToSourceY(sy);
780:
781: int minY = input.getMinY();
782: int maxY = input.getMinY() + input.getHeight();
783:
784: int cTileWidth = bounds.width;
785: int length = (cTileWidth - 1) * scaleX + 1;
786:
787: for (int j = 0; j < bounds.height; j++, sy++, y += scaleY) {
788: if (y < minY || y >= maxY)
789: continue;
790:
791: Raster source = input.getData(new Rectangle(x, y,
792: length, 1));
793:
794: int tempX = sx;
795: for (int i = 0, offset = x; i < cTileWidth; i++, tempX++, offset += scaleX) {
796: for (int k = 0; k < numBands; k++) {
797: int p = source.getSample(offset, y,
798: sourceBands[k]);
799: ras.setSample(tempX, sy, k, p);
800: }
801: }
802: }
803: return ras;
804: }
805: }
806:
807: private int mapToSourceX(int x) {
808: return x * scaleX + xOffset;
809: }
810:
811: private int mapToSourceY(int y) {
812: return y * scaleY + yOffset;
813: }
814:
815: private int getMinTileX() {
816: return ToTile(destinationRegion.x, tileXOffset, tileWidth);
817: }
818:
819: private int getMaxTileX() {
820: return ToTile(
821: destinationRegion.x + destinationRegion.width - 1,
822: tileXOffset, tileWidth);
823: }
824:
825: private int getMinTileY() {
826: return ToTile(destinationRegion.y, tileYOffset, tileHeight);
827: }
828:
829: private int getMaxTileY() {
830: return ToTile(destinationRegion.y + destinationRegion.height
831: - 1, tileYOffset, tileHeight);
832: }
833:
834: private static int ToTile(int pos, int tileOffset, int tileSize) {
835: pos -= tileOffset;
836: if (pos < 0) {
837: pos += 1 - tileSize; // force round to -infinity (ceiling)
838: }
839: return pos / tileSize;
840: }
841:
842: public void reset() {
843: super .reset();
844: stream = null;
845: optimal = false;
846: sourceBands = null;
847: destinationRegion = null;
848: noTransform = true;
849: noSubband = true;
850: writeRaster = false;
851: }
852: }
|