001: /*
002: * $RCSfile: CLibImageReader.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.11 $
042: * $Date: 2006/02/28 01:33:31 $
043: * $State: Exp $
044: */
045: package com.sun.media.imageioimpl.plugins.clib;
046:
047: import java.awt.Point;
048: import java.awt.Rectangle;
049: import java.awt.Transparency;
050: import java.awt.color.ColorSpace;
051: import java.awt.geom.AffineTransform;
052: import java.awt.image.AffineTransformOp;
053: import java.awt.image.BufferedImage;
054: import java.awt.image.ColorModel;
055: import java.awt.image.ComponentColorModel;
056: import java.awt.image.ComponentSampleModel;
057: import java.awt.image.DataBuffer;
058: import java.awt.image.DataBufferByte;
059: import java.awt.image.DataBufferUShort;
060: import java.awt.image.IndexColorModel;
061: import java.awt.image.MultiPixelPackedSampleModel;
062: import java.awt.image.PixelInterleavedSampleModel;
063: import java.awt.image.Raster;
064: import java.awt.image.SampleModel;
065: import java.awt.image.WritableRaster;
066: import java.io.InputStream;
067: import java.io.IOException;
068: import java.util.ArrayList;
069: import java.util.Iterator;
070: import java.util.NoSuchElementException;
071: import javax.imageio.IIOException;
072: import javax.imageio.ImageReader;
073: import javax.imageio.ImageReadParam;
074: import javax.imageio.ImageTypeSpecifier;
075: import javax.imageio.metadata.IIOMetadata;
076: import javax.imageio.spi.ImageReaderSpi;
077: import javax.imageio.stream.ImageInputStream;
078: import com.sun.medialib.codec.jiio.Constants;
079: import com.sun.medialib.codec.jiio.mediaLibImage;
080:
081: // XXX Need to verify compliance of all methods with ImageReader specificaiton.
082: public abstract class CLibImageReader extends ImageReader {
083: // The current image index.
084: private int currIndex = -1;
085:
086: // The position of the byte after the last byte read so far.
087: private long highWaterMark = Long.MIN_VALUE;
088:
089: // An <code>ArrayList</code> of <code>Long</code>s indicating the stream
090: // positions of the start of each image. Entries are added as needed.
091: private ArrayList imageStartPosition = new ArrayList();
092:
093: // The number of images in the stream, if known, otherwise -1.
094: private int numImages = -1;
095:
096: // The image returned by the codecLib Decoder.
097: private mediaLibImage mlibImage = null;
098:
099: // The index of the cached image.
100: private int mlibImageIndex = -1;
101:
102: /**
103: * Returns true if and only if both arguments are null or
104: * both are non-null and have the same length and content.
105: */
106: private static boolean subBandsMatch(int[] sourceBands,
107: int[] destinationBands) {
108: if (sourceBands == null && destinationBands == null) {
109: return true;
110: } else if (sourceBands != null && destinationBands != null) {
111: if (sourceBands.length != destinationBands.length) {
112: // Shouldn't happen ...
113: return false;
114: }
115: for (int i = 0; i < sourceBands.length; i++) {
116: if (sourceBands[i] != destinationBands[i]) {
117: return false;
118: }
119: }
120: return true;
121: }
122:
123: return false;
124: }
125:
126: /**
127: * Creates a <code>ImageTypeSpecifier</code> corresponding to a
128: * <code>mediaLibImage</code>. The <code>mediaLibImage</code> is
129: * assumed always to be either bilevel-packed (MLIB_BIT) or
130: * pixel interleaved in the order ((G|I)|RGB)[A] where 'I' indicates
131: * an index as for palette images.
132: */
133: protected static final ImageTypeSpecifier createImageType(
134: mediaLibImage mlImage, ColorSpace colorSpace, int bitDepth,
135: byte[] redPalette, byte[] greenPalette, byte[] bluePalette,
136: byte[] alphaPalette) throws IOException {
137:
138: // Get the mediaLibImage attributes.
139: int mlibType = mlImage.getType();
140: int mlibWidth = mlImage.getWidth();
141: int mlibHeight = mlImage.getHeight();
142: int mlibBands = mlImage.getChannels();
143: int mlibStride = mlImage.getStride();
144:
145: // Convert mediaLib type to Java2D type.
146: int dataType;
147: switch (mlibType) {
148: case Constants.MLIB_BIT:
149: case Constants.MLIB_BYTE:
150: dataType = DataBuffer.TYPE_BYTE;
151: break;
152: case Constants.MLIB_SHORT:
153: case Constants.MLIB_USHORT:
154: // Deliberately cast MLIB_SHORT to TYPE_USHORT.
155: dataType = DataBuffer.TYPE_USHORT;
156: break;
157: default:
158: throw new UnsupportedOperationException(I18N
159: .getString("Generic0")
160: + " " + mlibType);
161: }
162:
163: // Set up the SampleModel.
164: SampleModel sampleModel = null;
165: if (mlibType == Constants.MLIB_BIT) {
166: // Bilevel-packed
167: sampleModel = new MultiPixelPackedSampleModel(dataType,
168: mlibWidth, mlibHeight, 1, mlibStride, mlImage
169: .getBitOffset());
170: } else {
171: // Otherwise has to be interleaved in the order ((G|I)|RGB)[A].
172: int[] bandOffsets = new int[mlibBands];
173: for (int i = 0; i < mlibBands; i++) {
174: bandOffsets[i] = i;
175: }
176:
177: sampleModel = new PixelInterleavedSampleModel(dataType,
178: mlibWidth, mlibHeight, mlibBands, mlibStride,
179: bandOffsets);
180: }
181:
182: // Set up the ColorModel.
183: ColorModel colorModel = null;
184: if (mlibBands == 1 && redPalette != null
185: && greenPalette != null && bluePalette != null
186: && redPalette.length == greenPalette.length
187: && redPalette.length == bluePalette.length) {
188:
189: // Indexed image.
190: int paletteLength = redPalette.length;
191: if (alphaPalette != null) {
192: if (alphaPalette.length != paletteLength) {
193: byte[] alphaTmp = new byte[paletteLength];
194: if (alphaPalette.length > paletteLength) {
195: System.arraycopy(alphaPalette, 0, alphaTmp, 0,
196: paletteLength);
197: } else { // alphaPalette.length < paletteLength
198: System.arraycopy(alphaPalette, 0, alphaTmp, 0,
199: alphaPalette.length);
200: for (int i = alphaPalette.length; i < paletteLength; i++) {
201: alphaTmp[i] = (byte) 255; // Opaque.
202: }
203: }
204: alphaPalette = alphaTmp;
205: }
206:
207: colorModel = new IndexColorModel(
208: bitDepth, //XXX 8
209: paletteLength, redPalette, greenPalette,
210: bluePalette, alphaPalette);
211: } else {
212: colorModel = new IndexColorModel(
213: bitDepth, //XXX 8
214: paletteLength, redPalette, greenPalette,
215: bluePalette);
216: }
217: } else if (mlibType == Constants.MLIB_BIT) {
218: // Bilevel image with no palette: assume black-is-zero.
219: byte[] cmap = new byte[] { (byte) 0x00, (byte) 0xFF };
220: colorModel = new IndexColorModel(1, 2, cmap, cmap, cmap);
221: } else {
222: // Set the color space and the alpha flag.
223: ColorSpace cs;
224: boolean hasAlpha;
225: if (colorSpace != null
226: && (colorSpace.getNumComponents() == mlibBands || colorSpace
227: .getNumComponents() == mlibBands - 1)) {
228: // Use the provided ColorSpace.
229: cs = colorSpace;
230:
231: // Set alpha if numBands == numColorComponents + 1.
232: hasAlpha = colorSpace.getNumComponents() != mlibBands;
233: } else {
234: // RGB if more than 2 bands.
235: cs = ColorSpace
236: .getInstance(mlibBands < 3 ? ColorSpace.CS_GRAY
237: : ColorSpace.CS_sRGB);
238:
239: // Alpha if band count is even.
240: hasAlpha = mlibBands % 2 == 0;
241: }
242:
243: // All bands have same depth.
244: int[] bits = new int[mlibBands];
245: for (int i = 0; i < mlibBands; i++) {
246: bits[i] = bitDepth;
247: }
248:
249: colorModel = new ComponentColorModel(cs, bits, hasAlpha,
250: false, hasAlpha ? Transparency.TRANSLUCENT
251: : Transparency.OPAQUE, dataType);
252: }
253:
254: return new ImageTypeSpecifier(colorModel, sampleModel);
255: }
256:
257: private static final void subsample(Raster src, int subX, int subY,
258: WritableRaster dst) {
259: int sx0 = src.getMinX();
260: int sy0 = src.getMinY();
261: int sw = src.getWidth();
262: int syUB = sy0 + src.getHeight();
263:
264: int dx0 = dst.getMinX();
265: int dy0 = dst.getMinY();
266: int dw = dst.getWidth();
267:
268: int b = src.getSampleModel().getNumBands();
269: int t = src.getSampleModel().getDataType();
270:
271: int numSubSamples = (sw + subX - 1) / subX;
272:
273: if (t == DataBuffer.TYPE_FLOAT || t == DataBuffer.TYPE_DOUBLE) {
274: float[] fsamples = new float[sw];
275: float[] fsubsamples = new float[numSubSamples];
276:
277: for (int k = 0; k < b; k++) {
278: for (int sy = sy0, dy = dy0; sy < syUB; sy += subY, dy++) {
279: src.getSamples(sx0, sy, sw, 1, k, fsamples);
280: for (int i = 0, s = 0; i < sw; s++, i += subX) {
281: fsubsamples[s] = fsamples[i];
282: }
283: dst.setSamples(dx0, dy, dw, 1, k, fsubsamples);
284: }
285: }
286: } else {
287: int[] samples = new int[sw];
288: int[] subsamples = new int[numSubSamples];
289:
290: for (int k = 0; k < b; k++) {
291: for (int sy = sy0, dy = dy0; sy < syUB; sy += subY, dy++) {
292: src.getSamples(sx0, sy, sw, 1, k, samples);
293: for (int i = 0, s = 0; i < sw; s++, i += subX) {
294: subsamples[s] = samples[i];
295: }
296: dst.setSamples(dx0, dy, dw, 1, k, subsamples);
297: }
298: }
299: }
300: }
301:
302: protected CLibImageReader(ImageReaderSpi originatingProvider) {
303: super (originatingProvider);
304: }
305:
306: /**
307: * An <code>Iterator</code> over a single element.
308: */
309: private class SoloIterator implements Iterator {
310: Object theObject;
311:
312: SoloIterator(Object o) {
313: if (o == null) {
314: new IllegalArgumentException(I18N
315: .getString("CLibImageReader0"));
316: }
317: theObject = o;
318: }
319:
320: public boolean hasNext() {
321: return theObject != null;
322: }
323:
324: public Object next() {
325: if (theObject == null) {
326: throw new NoSuchElementException();
327: }
328: Object theNextObject = theObject;
329: theObject = null;
330: return theNextObject;
331: }
332:
333: public void remove() {
334: throw new UnsupportedOperationException();
335: }
336: }
337:
338: // Stores the location of the image at the specified index in the
339: // imageStartPosition List.
340: private int locateImage(int imageIndex) throws IIOException {
341: if (imageIndex < 0) {
342: throw new IndexOutOfBoundsException("imageIndex < 0!");
343: }
344:
345: try {
346: // Find closest known index (which can be -1 if none read before).
347: int index = Math.min(imageIndex,
348: imageStartPosition.size() - 1);
349:
350: ImageInputStream stream = (ImageInputStream) input;
351:
352: // Seek unless at beginning of stream
353: if (index >= 0) { // index == -1
354: if (index == imageIndex) {
355: // Seek to previously identified position and return.
356: Long l = (Long) imageStartPosition.get(index);
357: stream.seek(l.longValue());
358: return imageIndex;
359: } else if (highWaterMark >= 0) {
360: // index >= imageStartPosition.size()
361: // Seek to first unread byte.
362: stream.seek(highWaterMark);
363: }
364: }
365:
366: // Get the reader SPI.
367: ImageReaderSpi provider = getOriginatingProvider();
368:
369: // Search images until at desired index or last image found.
370: do {
371: try {
372: if (provider.canDecodeInput(stream)) {
373: // Append the image position.
374: long offset = stream.getStreamPosition();
375: imageStartPosition.add(new Long(offset));
376: } else {
377: return index;
378: }
379: } catch (IOException e) {
380: // Ignore it.
381: return index;
382: }
383:
384: // Incrememt the index.
385: if (++index == imageIndex)
386: break;
387:
388: // Skip the image.
389: if (!skipImage())
390: return index - 1;
391: } while (true);
392: } catch (IOException e) {
393: throw new IIOException("IOException", e);
394: }
395:
396: currIndex = imageIndex;
397:
398: return imageIndex;
399: }
400:
401: // Verify that imageIndex is in bounds and find the image position.
402: protected void seekToImage(int imageIndex) throws IIOException {
403: // Check lower bound.
404: if (imageIndex < minIndex) {
405: throw new IndexOutOfBoundsException(
406: "imageIndex < minIndex!");
407: }
408:
409: // Update lower bound if cannot seek back.
410: if (seekForwardOnly) {
411: minIndex = imageIndex;
412: }
413:
414: // Locate the image.
415: int index = locateImage(imageIndex);
416:
417: // If the located is not the one sought => exception.
418: if (index != imageIndex) {
419: throw new IndexOutOfBoundsException(
420: "imageIndex out of bounds!");
421: }
422: }
423:
424: /**
425: * Skip the current image. If possible subclasses should override
426: * this method with a more efficient implementation.
427: *
428: * @return Whether the image was successfully skipped.
429: */
430: protected boolean skipImage() throws IOException {
431: boolean retval = false;
432:
433: if (input == null) {
434: throw new IllegalStateException("input == null");
435: }
436: InputStream stream = null;
437: if (input instanceof ImageInputStream) {
438: stream = new InputStreamAdapter((ImageInputStream) input);
439: } else {
440: throw new IllegalArgumentException(
441: "!(input instanceof ImageInputStream)");
442: }
443:
444: retval = decode(stream) != null;
445:
446: if (retval) {
447: long pos = ((ImageInputStream) input).getStreamPosition();
448: if (pos > highWaterMark) {
449: highWaterMark = pos;
450: }
451: }
452:
453: return retval;
454: }
455:
456: /**
457: * Decodes an image from the supplied <code>InputStream</code>.
458: */
459: protected abstract mediaLibImage decode(InputStream stream)
460: throws IOException;
461:
462: /**
463: * Returns the value of the private <code>mlibImage</code> instance
464: * variable initializing it first if it is <code>null</code>.
465: */
466: protected synchronized mediaLibImage getImage(int imageIndex)
467: throws IOException {
468: if (mlibImage == null || imageIndex != mlibImageIndex) {
469: if (input == null) {
470: throw new IllegalStateException("input == null");
471: }
472: seekToImage(imageIndex);
473: InputStream stream = null;
474: if (input instanceof ImageInputStream) {
475: stream = new InputStreamAdapter(
476: (ImageInputStream) input);
477: } else {
478: throw new IllegalArgumentException(
479: "!(input instanceof ImageInputStream)");
480: }
481: mlibImage = decode(stream);
482: if (mlibImage != null) {
483: mlibImageIndex = imageIndex;
484: long pos = ((ImageInputStream) input)
485: .getStreamPosition();
486: if (pos > highWaterMark) {
487: highWaterMark = pos;
488: }
489: } else { // mlibImage == null
490: mlibImageIndex = -1;
491: }
492: }
493: return mlibImage;
494: }
495:
496: /**
497: * Returns the index of the image cached in the private
498: * <code>mlibImage</code> instance variable or -1 if no
499: * image is currently cached.
500: */
501: protected int getImageIndex() {
502: return mlibImageIndex;
503: }
504:
505: public int getNumImages(boolean allowSearch) throws IOException {
506: if (input == null) {
507: throw new IllegalStateException("input == null");
508: }
509: if (seekForwardOnly && allowSearch) {
510: throw new IllegalStateException(
511: "seekForwardOnly && allowSearch!");
512: }
513:
514: if (numImages > 0) {
515: return numImages;
516: }
517: if (allowSearch) {
518: this .numImages = locateImage(Integer.MAX_VALUE) + 1;
519: }
520: return numImages;
521: }
522:
523: public int getWidth(int imageIndex) throws IOException {
524: seekToImage(imageIndex);
525:
526: return getImage(imageIndex).getWidth();
527: }
528:
529: public int getHeight(int imageIndex) throws IOException {
530: seekToImage(imageIndex);
531:
532: return getImage(imageIndex).getHeight();
533: }
534:
535: public IIOMetadata getStreamMetadata() throws IOException {
536: return null;
537: }
538:
539: public IIOMetadata getImageMetadata(int imageIndex)
540: throws IOException {
541: seekToImage(imageIndex);
542:
543: return null;
544: }
545:
546: public synchronized BufferedImage read(int imageIndex,
547: ImageReadParam param) throws IOException {
548:
549: processImageStarted(imageIndex);
550:
551: seekToImage(imageIndex);
552:
553: processImageProgress(0.0F);
554: processImageProgress(0.5F);
555:
556: ImageTypeSpecifier rawImageType = getRawImageType(imageIndex);
557:
558: processImageProgress(0.95F);
559:
560: mediaLibImage mlImage = getImage(imageIndex);
561: int dataOffset = mlImage.getOffset();
562:
563: SampleModel rawSampleModel = rawImageType.getSampleModel();
564:
565: DataBuffer db;
566: int smType = rawSampleModel.getDataType();
567: switch (smType) {
568: case DataBuffer.TYPE_BYTE:
569: byte[] byteData = mlImage.getType() == mediaLibImage.MLIB_BIT ? mlImage
570: .getBitData()
571: : mlImage.getByteData();
572: db = new DataBufferByte(byteData, byteData.length
573: - dataOffset, dataOffset);
574: break;
575: case DataBuffer.TYPE_USHORT:
576: // Deliberately cast MLIB_SHORT to TYPE_USHORT.
577: short[] shortData = mlImage.getShortData();
578: if (shortData == null) {
579: shortData = mlImage.getUShortData();
580: }
581: db = new DataBufferUShort(shortData, shortData.length
582: - dataOffset, dataOffset);
583: break;
584: default:
585: throw new UnsupportedOperationException(I18N
586: .getString("Generic0")
587: + " " + smType);
588: }
589:
590: WritableRaster rawRaster = Raster.createWritableRaster(
591: rawSampleModel, db, null);
592:
593: ColorModel rawColorModel = rawImageType.getColorModel();
594:
595: BufferedImage image = new BufferedImage(rawColorModel,
596: rawRaster, rawColorModel.isAlphaPremultiplied(), null); // XXX getDestination()?
597:
598: Rectangle destRegion = new Rectangle(image.getWidth(), image
599: .getHeight());
600: int[] destinationBands = null;
601: int subX = 1;
602: int subY = 1;
603:
604: if (param != null) {
605: BufferedImage destination = param.getDestination();
606: destinationBands = param.getDestinationBands();
607: Point destinationOffset = param.getDestinationOffset();
608: int[] sourceBands = param.getSourceBands();
609: Rectangle sourceRegion = param.getSourceRegion();
610: subX = param.getSourceXSubsampling();
611: subY = param.getSourceYSubsampling();
612:
613: boolean isNominal = destination == null
614: && destinationBands == null
615: & destinationOffset.x == 0
616: && destinationOffset.y == 0 && sourceBands == null
617: && sourceRegion == null && subX == 1 && subY == 1;
618:
619: if (!isNominal) {
620: int srcWidth = image.getWidth();
621: int srcHeight = image.getHeight();
622:
623: if (destination == null) {
624: destination = getDestination(param,
625: getImageTypes(imageIndex), srcWidth,
626: srcHeight);
627: }
628:
629: checkReadParamBandSettings(param, image
630: .getSampleModel().getNumBands(), destination
631: .getSampleModel().getNumBands());
632:
633: Rectangle srcRegion = new Rectangle();
634: computeRegions(param, srcWidth, srcHeight, destination,
635: srcRegion, destRegion);
636:
637: WritableRaster dst = destination.getWritableTile(0, 0)
638: .createWritableChild(destRegion.x,
639: destRegion.y, destRegion.width,
640: destRegion.height, destRegion.x,
641: destRegion.y, destinationBands);
642:
643: if (subX != 1 || subY != 1) { // Subsampling
644: WritableRaster src = image.getWritableTile(0, 0)
645: .createWritableChild(srcRegion.x,
646: srcRegion.y, srcRegion.width,
647: srcRegion.height, srcRegion.x,
648: srcRegion.y, sourceBands);
649: subsample(src, subX, subY, dst);
650: } else { // No subsampling
651: WritableRaster src = image.getWritableTile(0, 0)
652: .createWritableChild(srcRegion.x,
653: srcRegion.y, srcRegion.width,
654: srcRegion.height, destRegion.x,
655: destRegion.y, sourceBands);
656: dst.setRect(src);
657: }
658:
659: image = destination;
660: } else if (param.getDestinationType() != null) {
661: // Check for image type other than raw image type.
662: ImageTypeSpecifier destImageType = param
663: .getDestinationType();
664: ColorSpace rawColorSpace = rawColorModel
665: .getColorSpace();
666: ColorSpace destColorSpace = destImageType
667: .getColorModel().getColorSpace();
668: if (!destColorSpace.equals(rawColorSpace)
669: || !destImageType.equals(rawImageType)) {
670: // Look for destination type in legal types list.
671: Iterator imageTypes = getImageTypes(imageIndex);
672: boolean isLegalType = false;
673: while (imageTypes.hasNext()) {
674: ImageTypeSpecifier imageType = (ImageTypeSpecifier) imageTypes
675: .next();
676: if (imageType.equals(destImageType)) {
677: isLegalType = true;
678: break;
679: }
680: }
681:
682: if (isLegalType) {
683: // Set the destination raster.
684: WritableRaster raster;
685: if (rawSampleModel.equals(destImageType
686: .getSampleModel())) {
687: // Re-use the raw raster.
688: raster = rawRaster;
689: } else {
690: // Create a new raster and copy the data.
691: SampleModel sm = destImageType
692: .getSampleModel();
693: raster = Raster.createWritableRaster(sm,
694: null);
695: raster.setRect(rawRaster);
696: }
697:
698: // Replace the output image.
699: ColorModel cm = destImageType.getColorModel();
700: image = new BufferedImage(cm, raster, cm
701: .isAlphaPremultiplied(), null);
702: }
703: }
704: }
705: }
706:
707: processImageUpdate(image, destRegion.x, destRegion.y,
708: destRegion.width, destRegion.height, subX, subY,
709: destinationBands);
710:
711: processImageProgress(1.0F);
712: processImageComplete();
713:
714: return image;
715: }
716:
717: public void reset() {
718: resetLocal();
719: super .reset();
720: }
721:
722: protected void resetLocal() {
723: currIndex = -1;
724: highWaterMark = Long.MIN_VALUE;
725: imageStartPosition.clear();
726: numImages = -1;
727: mlibImage = null;
728: mlibImageIndex = -1;
729: }
730:
731: public void setInput(Object input, boolean seekForwardOnly,
732: boolean ignoreMetadata) {
733: super .setInput(input, seekForwardOnly, ignoreMetadata);
734: if (input != null) {
735: // Check the class type.
736: if (!(input instanceof ImageInputStream)) {
737: throw new IllegalArgumentException(
738: "!(input instanceof ImageInputStream)");
739: }
740: }
741: resetLocal();
742: }
743: }
|