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