1 /*
2  * $RCSfile: StreamRIF.java,v $
3  *
4  * Copyright (c) 2005 Sun Microsystems, Inc. All rights reserved.
5  *
6  * Use is subject to license terms.
7  *
8  * $Revision: 1.2 $
9  * $Date: 2006/06/17 00:02:28 $
10  * $State: Exp $
11  */
12 package com.lightcrafts.media.jai.opimage;
13 
14 import com.lightcrafts.media.jai.codec.ImageCodec;
15 import com.lightcrafts.media.jai.codec.ImageDecodeParam;
16 import com.lightcrafts.media.jai.codec.ImageDecoder;
17 import com.lightcrafts.media.jai.codec.SeekableStream;
18 import java.awt.RenderingHints;
19 import java.awt.image.RenderedImage;
20 import java.awt.image.renderable.RenderedImageFactory;
21 import java.awt.image.renderable.ParameterBlock;
22 import java.io.IOException;
23 import com.lightcrafts.mediax.jai.ImageLayout;
24 import com.lightcrafts.mediax.jai.JAI;
25 import com.lightcrafts.mediax.jai.OpImage;
26 import com.lightcrafts.mediax.jai.OperationRegistry;
27 import com.lightcrafts.mediax.jai.TileCache;
28 import com.lightcrafts.mediax.jai.registry.RIFRegistry;
29 import com.lightcrafts.mediax.jai.util.ImagingException;
30 import com.lightcrafts.mediax.jai.util.ImagingListener;
31 import com.lightcrafts.media.jai.util.DisposableNullOpImage;
32 import com.lightcrafts.media.jai.util.ImageUtil;
33 
34 /**
35  * @see com.lightcrafts.mediax.jai.operator.StreamDescriptor
36  *
37  * @since EA2
38  *
39  */
40 public class StreamRIF implements RenderedImageFactory {
41 
42     /** Constructor. */
StreamRIF()43     public StreamRIF() {}
44 
45     /**
46      * Creates an image from a SeekableStream.
47      */
create(ParameterBlock paramBlock, RenderingHints renderHints)48     public RenderedImage create(ParameterBlock paramBlock,
49                                 RenderingHints renderHints) {
50         ImagingListener listener = ImageUtil.getImagingListener(renderHints);
51         SeekableStream src = (SeekableStream)paramBlock.getObjectParameter(0);
52         try {
53             src.seek(0L);
54         } catch (IOException e) {
55             listener.errorOccurred(JaiI18N.getString("StreamRIF0"),
56                                    e, this, false);
57 //            e.printStackTrace();
58             return null;
59         }
60 
61         ImageDecodeParam param = null;
62         if (paramBlock.getNumParameters() > 1) {
63             param = (ImageDecodeParam)paramBlock.getObjectParameter(1);
64         }
65 
66         String[] names = ImageCodec.getDecoderNames(src);
67 
68         OperationRegistry registry =
69             JAI.getDefaultInstance().getOperationRegistry();
70         int bound = OpImage.OP_IO_BOUND;
71         ImageLayout layout = RIFUtil.getImageLayoutHint(renderHints);
72 
73         if (renderHints != null) {
74             RenderingHints.Key key;
75 
76             key = JAI.KEY_OPERATION_REGISTRY;
77             if (renderHints.containsKey(key)) {
78                 registry = (OperationRegistry)renderHints.get(key);
79             }
80 
81             key = JAI.KEY_OPERATION_BOUND;
82             if (renderHints.containsKey(key)) {
83                 bound = ((Integer)renderHints.get(key)).intValue();
84             }
85         }
86 
87         // Try to create a JAI operation with the given name
88         for (int i = 0; i < names.length; i++) {
89             RenderedImageFactory rif = null;
90             try {
91                 rif = RIFRegistry.get(registry, names[i]);
92             } catch(IllegalArgumentException iae) {
93                 // ignore IAE.
94             }
95             if(rif != null) {
96                 RenderedImage im = RIFRegistry.create(registry, names[i],
97                                                       paramBlock, renderHints);
98                 if (im != null) {
99                     return im;
100                 }
101             }
102         }
103 
104         // Set flag indicating that a recovery may be attempted if
105         // an OutOfMemoryError occurs during the decodeAsRenderedImage()
106         // call - which is only possible if the stream can seek backwards.
107         boolean canAttemptRecovery = src.canSeekBackwards();
108 
109         // Save the stream position prior to decodeAsRenderedImage().
110         long streamPosition = Long.MIN_VALUE;
111         if(canAttemptRecovery) {
112             try {
113                 streamPosition = src.getFilePointer();
114             } catch(IOException ioe) {
115                 listener.errorOccurred(JaiI18N.getString("StreamRIF1"),
116                                        ioe, this, false);
117                 // Unset the recovery attempt flag but otherwise
118                 // ignore the exception.
119                 canAttemptRecovery = false;
120             }
121         }
122 
123         // Try to create an ImageDecoder directly
124         for (int i = 0; i < names.length; i++) {
125             ImageDecoder dec =
126                 ImageCodec.createImageDecoder(names[i], src, param);
127             RenderedImage im = null;
128             try {
129                 im = dec.decodeAsRenderedImage();
130             } catch(OutOfMemoryError memoryError) {
131                 // Ran out of memory - may be due to the decoder being
132                 // obliged to read the entire image when it creates the
133                 // RenderedImage it returns.
134                 if(canAttemptRecovery) {
135                     // First flush the cache if one is defined.
136                     TileCache cache = RIFUtil.getTileCacheHint(renderHints);
137                     if(cache != null) {
138                         cache.flush();
139                     }
140 
141                     // Force garbage collection.
142                     System.gc(); //slow
143 
144                     try {
145                         // Reposition the stream before the previous decoding.
146                         src.seek(streamPosition);
147 
148                         // Retry image decoding.
149                         im = dec.decodeAsRenderedImage();
150                     } catch (IOException ioe) {
151                         listener.errorOccurred(JaiI18N.getString("StreamRIF2"),
152                                                ioe, this, false);
153                         im = null;
154                     }
155                 } else {
156                     String message = JaiI18N.getString("CodecRIFUtil0");
157                     listener.errorOccurred(message,
158                                            new ImagingException(message,
159                                                                 memoryError),
160                                            this, false);
161                     // Re-throw the error.
162 //                    throw memoryError;
163                 }
164             } catch (IOException e) {
165                 listener.errorOccurred(JaiI18N.getString("StreamRIF2"),
166                                        e, this, false);
167                 im = null;
168             }
169 
170             // If decoding succeeded, wrap the result in an OpImage.
171             if (im != null) {
172                 return new DisposableNullOpImage(im, layout,
173                                                  renderHints, bound);
174             }
175         }
176 
177         return null;
178     }
179 }
180