001: /*
002: * $RCSfile: CLibJPEGImageReader.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.10 $
042: * $Date: 2006/04/24 20:53:01 $
043: * $State: Exp $
044: */
045: package com.sun.media.imageioimpl.plugins.jpeg;
046:
047: import java.awt.color.ColorSpace;
048: import java.awt.color.ICC_ColorSpace;
049: import java.awt.color.ICC_Profile;
050: import java.awt.image.BufferedImage;
051: import java.awt.image.ColorModel;
052: import java.awt.image.DataBuffer;
053: import java.awt.image.MultiPixelPackedSampleModel;
054: import java.awt.image.PixelInterleavedSampleModel;
055: import java.awt.image.SampleModel;
056: import java.io.File;
057: import java.io.FileInputStream;
058: import java.io.InputStream;
059: import java.io.IOException;
060: import java.util.ArrayList;
061: import java.util.HashMap;
062: import java.util.Iterator;
063: import javax.imageio.IIOException;
064: import javax.imageio.IIOImage;
065: import javax.imageio.ImageReader;
066: import javax.imageio.ImageReadParam;
067: import javax.imageio.ImageTypeSpecifier;
068: import javax.imageio.metadata.IIOMetadata;
069: import javax.imageio.spi.ImageReaderSpi;
070: import javax.imageio.stream.ImageInputStream;
071: import com.sun.media.imageioimpl.common.InvertedCMYKColorSpace;
072: import com.sun.media.imageioimpl.plugins.clib.CLibImageReader;
073: import com.sun.media.imageioimpl.plugins.clib.InputStreamAdapter;
074: import com.sun.medialib.codec.jpeg.Decoder;
075: import com.sun.medialib.codec.jiio.mediaLibImage;
076:
077: final class CLibJPEGImageReader extends CLibImageReader {
078: private static final boolean DEBUG = false; // XXX false for release
079:
080: private mediaLibImage infoImage = null;
081: private int infoImageIndex = -1;
082: private byte[] iccProfileData = null;
083: private IIOMetadata imageMetadata = null;
084: private int imageMetadataIndex = -1;
085: private HashMap imageTypes = new HashMap();
086: private int bitDepth; // XXX Should depend on imageIndex.
087:
088: CLibJPEGImageReader(ImageReaderSpi originatingProvider) {
089: super (originatingProvider);
090: }
091:
092: // Implement abstract method defined in superclass.
093: protected final synchronized mediaLibImage decode(InputStream stream)
094: throws IOException {
095: if (DEBUG)
096: System.out.println("In decode()");
097:
098: mediaLibImage mlImage = null;
099: Decoder decoder = null;
100: try {
101: if (stream instanceof InputStreamAdapter) {
102: ImageInputStream iis = ((InputStreamAdapter) stream)
103: .getWrappedStream();
104: decoder = new Decoder(iis);
105: } else {
106: decoder = new Decoder(stream);
107: }
108: //decoder.setType(Decoder.JPEG_TYPE_UNKNOWN);
109: mlImage = decoder.decode(null);
110:
111: // Set the ICC profile data.
112: iccProfileData = decoder.getEmbeddedICCProfile();
113:
114: // If there is a profile need to invert the data if they
115: // are YCCK or CMYK originally.
116: if (iccProfileData != null
117: && mlImage.getType() == mediaLibImage.MLIB_BYTE) {
118: int format = mlImage.getFormat();
119: if (format == mediaLibImage.MLIB_FORMAT_CMYK
120: || format == mediaLibImage.MLIB_FORMAT_YCCK) {
121: long t0 = System.currentTimeMillis();
122: byte[] data = mlImage.getByteData();
123: int len = data.length;
124: for (int i = mlImage.getOffset(); i < len; i++) {
125: data[i] = (byte) (255 - data[i] & 0xff);
126: }
127: }
128: }
129:
130: } catch (Throwable t) {
131: throw new IIOException("codecLib error", t);
132: }
133:
134: if (mlImage == null) {
135: throw new IIOException(I18N
136: .getString("CLibJPEGImageReader0"));
137: }
138:
139: // Set variable indicating bit depth.
140: try {
141: bitDepth = decoder.getDepth();
142: } catch (Throwable t) {
143: throw new IIOException("codecLib error", t);
144: }
145:
146: // Free native resources.
147: decoder.dispose();
148:
149: if (DEBUG) {
150: System.out.println("type = " + mlImage.getType());
151: System.out.println("channels = " + mlImage.getChannels());
152: System.out.println("width = " + mlImage.getWidth());
153: System.out.println("height = " + mlImage.getHeight());
154: System.out.println("stride = " + mlImage.getStride());
155: System.out.println("offset = " + mlImage.getOffset());
156: System.out.println("bitOffset = " + mlImage.getBitOffset());
157: System.out.println("format = " + mlImage.getFormat());
158: }
159:
160: return mlImage;
161: }
162:
163: // Retrieve mediaLibImage containing everything except possibly the
164: // decoded image data. If the real image has already been decoded
165: // then it will be returned.
166: private synchronized mediaLibImage getInfoImage(int imageIndex)
167: throws IOException {
168: if (DEBUG)
169: System.out.println("In getInfoImage()");
170: if (infoImage == null || imageIndex != infoImageIndex) {
171: // Use the cached image if it has the correct index.
172: if (imageIndex == getImageIndex()) {
173: if (DEBUG) {
174: System.out.println("Using cached image.");
175: }
176: infoImage = getImage(imageIndex);
177: infoImageIndex = imageIndex;
178: return infoImage;
179: }
180:
181: if (input == null) {
182: throw new IllegalStateException("input == null");
183: }
184:
185: // Check the input and set local variable.
186: ImageInputStream iis = null;
187: if (input instanceof ImageInputStream) {
188: iis = (ImageInputStream) input;
189: } else {
190: throw new IllegalArgumentException(
191: "!(input instanceof ImageInputStream)");
192: }
193:
194: seekToImage(imageIndex);
195:
196: // Mark the input.
197: iis.mark();
198:
199: Decoder decoder = null;
200: try {
201: // Create the decoder
202: decoder = new Decoder(iis);
203:
204: // Set the informational image.
205: infoImage = decoder.getSize();
206:
207: // Set the ICC profile data.
208: iccProfileData = decoder.getEmbeddedICCProfile();
209: } catch (Throwable t) {
210: throw new IIOException("codecLib error", t);
211: }
212:
213: // XXX The lines marked "XXX" are a workaround for getSize()
214: // not correctly setting the format of infoImage.
215: if (infoImage == null || (infoImage.getFormat() == // XXX
216: mediaLibImage.MLIB_FORMAT_UNKNOWN && // XXX
217: ((infoImage = getImage(imageIndex)) == null))) { // XXX
218: throw new IIOException(I18N
219: .getString("CLibJPEGImageReader0"));
220: }
221:
222: infoImageIndex = imageIndex;
223:
224: try {
225: // Set variable indicating bit depth.
226: bitDepth = decoder.getDepth();
227: } catch (Throwable t) {
228: throw new IIOException("codecLib error", t);
229: }
230:
231: // Reset the input to the marked position.
232: iis.reset();
233:
234: // Free native resources.
235: decoder.dispose();
236:
237: if (DEBUG) {
238: System.out.println("type = " + infoImage.getType());
239: System.out.println("channels = "
240: + infoImage.getChannels());
241: System.out.println("width = " + infoImage.getWidth());
242: System.out.println("height = " + infoImage.getHeight());
243: System.out.println("stride = " + infoImage.getStride());
244: System.out.println("offset = " + infoImage.getOffset());
245: System.out.println("bitOffset = "
246: + infoImage.getBitOffset());
247: System.out.println("format = " + infoImage.getFormat());
248: }
249: }
250:
251: return infoImage;
252: }
253:
254: public int getWidth(int imageIndex) throws IOException {
255: if (DEBUG)
256: System.out.println("In getWidth()");
257:
258: return getInfoImage(imageIndex).getWidth();
259: }
260:
261: public int getHeight(int imageIndex) throws IOException {
262: if (DEBUG)
263: System.out.println("In getHeight()");
264:
265: return getInfoImage(imageIndex).getHeight();
266: }
267:
268: public Iterator getImageTypes(int imageIndex) throws IOException {
269: if (DEBUG)
270: System.out.println("In getImageTypes()");
271: seekToImage(imageIndex);
272:
273: ArrayList types = null;
274: synchronized (imageTypes) {
275: Integer key = new Integer(imageIndex);
276: if (imageTypes.containsKey(key)) {
277: types = (ArrayList) imageTypes.get(key);
278: } else {
279: types = new ArrayList();
280:
281: // Get the informational image.
282: mediaLibImage mlImage = getInfoImage(imageIndex);
283:
284: ColorSpace cs;
285:
286: // Add profile-based type if an ICC profile is present.
287: if (iccProfileData != null) {
288: ICC_Profile profile = ICC_Profile
289: .getInstance(iccProfileData);
290: cs = new ICC_ColorSpace(profile);
291: types.add(createImageType(mlImage, cs, bitDepth,
292: null, null, null, null));
293: }
294:
295: // Add a standard type.
296: cs = mlImage.getFormat() == mediaLibImage.MLIB_FORMAT_CMYK ? InvertedCMYKColorSpace
297: .getInstance()
298: : null;
299: types.add(createImageType(mlImage, cs, bitDepth, null,
300: null, null, null));
301: }
302: }
303:
304: return types.iterator();
305: }
306:
307: public synchronized IIOMetadata getImageMetadata(int imageIndex)
308: throws IOException {
309: if (input == null) {
310: throw new IllegalStateException("input == null");
311: }
312:
313: if (imageMetadata == null || imageIndex != imageMetadataIndex) {
314: seekToImage(imageIndex);
315:
316: ImageInputStream stream = (ImageInputStream) input;
317: long pos = stream.getStreamPosition();
318:
319: try {
320: imageMetadata = new CLibJPEGMetadata(stream);
321: imageMetadataIndex = imageIndex;
322: } catch (IIOException e) {
323: throw e;
324: } finally {
325: stream.seek(pos);
326: }
327: }
328:
329: return imageMetadata;
330: }
331:
332: // Override thumbnail methods.
333:
334: public boolean readerSupportsThumbnails() {
335: return true;
336: }
337:
338: public int getNumThumbnails(int imageIndex) throws IOException {
339: CLibJPEGMetadata metadata = (CLibJPEGMetadata) getImageMetadata(imageIndex);
340: return metadata.getNumThumbnails();
341: }
342:
343: public BufferedImage readThumbnail(int imageIndex,
344: int thumbnailIndex) throws IOException {
345: CLibJPEGMetadata metadata = (CLibJPEGMetadata) getImageMetadata(imageIndex);
346: return metadata.getThumbnail(thumbnailIndex);
347: }
348:
349: // Override superclass method.
350: protected void resetLocal() {
351: infoImage = null;
352: infoImageIndex = -1;
353: iccProfileData = null;
354: imageMetadata = null;
355: imageMetadataIndex = -1;
356: imageTypes.clear();
357: super.resetLocal();
358: }
359: }
|