001: /*
002: * $RCSfile: StreamRIF.java,v $
003: *
004: * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
005: *
006: * Use is subject to license terms.
007: *
008: * $Revision: 1.2 $
009: * $Date: 2006/06/17 00:02:28 $
010: * $State: Exp $
011: */
012: package com.sun.media.jai.opimage;
013:
014: import com.sun.media.jai.codec.ImageCodec;
015: import com.sun.media.jai.codec.ImageDecodeParam;
016: import com.sun.media.jai.codec.ImageDecoder;
017: import com.sun.media.jai.codec.SeekableStream;
018: import java.awt.RenderingHints;
019: import java.awt.image.RenderedImage;
020: import java.awt.image.renderable.RenderedImageFactory;
021: import java.awt.image.renderable.ParameterBlock;
022: import java.awt.image.renderable.RenderedImageFactory;
023: import java.io.IOException;
024: import java.io.InputStream;
025: import java.util.Enumeration;
026: import java.util.Map;
027: import javax.media.jai.ImageLayout;
028: import javax.media.jai.JAI;
029: import javax.media.jai.NullOpImage;
030: import javax.media.jai.OpImage;
031: import javax.media.jai.OperationRegistry;
032: import javax.media.jai.PlanarImage;
033: import javax.media.jai.TileCache;
034: import javax.media.jai.registry.RIFRegistry;
035: import javax.media.jai.util.ImagingException;
036: import javax.media.jai.util.ImagingListener;
037: import com.sun.media.jai.util.DisposableNullOpImage;
038: import com.sun.media.jai.util.ImageUtil;
039:
040: /**
041: * @see javax.media.jai.operator.StreamDescriptor
042: *
043: * @since EA2
044: *
045: */
046: public class StreamRIF implements RenderedImageFactory {
047:
048: /** Constructor. */
049: public StreamRIF() {
050: }
051:
052: /**
053: * Creates an image from a SeekableStream.
054: */
055: public RenderedImage create(ParameterBlock paramBlock,
056: RenderingHints renderHints) {
057: ImagingListener listener = ImageUtil
058: .getImagingListener(renderHints);
059: SeekableStream src = (SeekableStream) paramBlock
060: .getObjectParameter(0);
061: try {
062: src.seek(0L);
063: } catch (IOException e) {
064: listener.errorOccurred(JaiI18N.getString("StreamRIF0"), e,
065: this , false);
066: // e.printStackTrace();
067: return null;
068: }
069:
070: ImageDecodeParam param = null;
071: if (paramBlock.getNumParameters() > 1) {
072: param = (ImageDecodeParam) paramBlock.getObjectParameter(1);
073: }
074:
075: String[] names = ImageCodec.getDecoderNames(src);
076:
077: OperationRegistry registry = JAI.getDefaultInstance()
078: .getOperationRegistry();
079: int bound = OpImage.OP_IO_BOUND;
080: ImageLayout layout = RIFUtil.getImageLayoutHint(renderHints);
081:
082: if (renderHints != null) {
083: RenderingHints.Key key;
084:
085: key = JAI.KEY_OPERATION_REGISTRY;
086: if (renderHints.containsKey(key)) {
087: registry = (OperationRegistry) renderHints.get(key);
088: }
089:
090: key = JAI.KEY_OPERATION_BOUND;
091: if (renderHints.containsKey(key)) {
092: bound = ((Integer) renderHints.get(key)).intValue();
093: }
094: }
095:
096: // Try to create a JAI operation with the given name
097: for (int i = 0; i < names.length; i++) {
098: RenderedImageFactory rif = null;
099: try {
100: rif = RIFRegistry.get(registry, names[i]);
101: } catch (IllegalArgumentException iae) {
102: // ignore IAE.
103: }
104: if (rif != null) {
105: RenderedImage im = RIFRegistry.create(registry,
106: names[i], paramBlock, renderHints);
107: if (im != null) {
108: return im;
109: }
110: }
111: }
112:
113: // Set flag indicating that a recovery may be attempted if
114: // an OutOfMemoryError occurs during the decodeAsRenderedImage()
115: // call - which is only possible if the stream can seek backwards.
116: boolean canAttemptRecovery = src.canSeekBackwards();
117:
118: // Save the stream position prior to decodeAsRenderedImage().
119: long streamPosition = Long.MIN_VALUE;
120: if (canAttemptRecovery) {
121: try {
122: streamPosition = src.getFilePointer();
123: } catch (IOException ioe) {
124: listener.errorOccurred(JaiI18N.getString("StreamRIF1"),
125: ioe, this , false);
126: // Unset the recovery attempt flag but otherwise
127: // ignore the exception.
128: canAttemptRecovery = false;
129: }
130: }
131:
132: // Try to create an ImageDecoder directly
133: for (int i = 0; i < names.length; i++) {
134: ImageDecoder dec = ImageCodec.createImageDecoder(names[i],
135: src, param);
136: RenderedImage im = null;
137: try {
138: im = dec.decodeAsRenderedImage();
139: } catch (OutOfMemoryError memoryError) {
140: // Ran out of memory - may be due to the decoder being
141: // obliged to read the entire image when it creates the
142: // RenderedImage it returns.
143: if (canAttemptRecovery) {
144: // First flush the cache if one is defined.
145: TileCache cache = RIFUtil
146: .getTileCacheHint(renderHints);
147: if (cache != null) {
148: cache.flush();
149: }
150:
151: // Force garbage collection.
152: System.gc(); //slow
153:
154: try {
155: // Reposition the stream before the previous decoding.
156: src.seek(streamPosition);
157:
158: // Retry image decoding.
159: im = dec.decodeAsRenderedImage();
160: } catch (IOException ioe) {
161: listener.errorOccurred(JaiI18N
162: .getString("StreamRIF2"), ioe, this ,
163: false);
164: im = null;
165: }
166: } else {
167: String message = JaiI18N.getString("CodecRIFUtil0");
168: listener.errorOccurred(message,
169: new ImagingException(message, memoryError),
170: this , false);
171: // Re-throw the error.
172: // throw memoryError;
173: }
174: } catch (IOException e) {
175: listener.errorOccurred(JaiI18N.getString("StreamRIF2"),
176: e, this , false);
177: im = null;
178: }
179:
180: // If decoding succeeded, wrap the result in an OpImage.
181: if (im != null) {
182: return new DisposableNullOpImage(im, layout,
183: renderHints, bound);
184: }
185: }
186:
187: return null;
188: }
189: }
|