001: /*
002: * $RCSfile: CLibPNGImageReader.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.5 $
042: * $Date: 2006/02/24 01:03:28 $
043: * $State: Exp $
044: */
045: package com.sun.media.imageioimpl.plugins.png;
046:
047: import java.awt.color.ColorSpace;
048: import java.awt.color.ICC_ColorSpace;
049: import java.awt.color.ICC_Profile;
050: import java.io.InputStream;
051: import java.io.IOException;
052: import java.util.ArrayList;
053: import java.util.HashMap;
054: import java.util.Iterator;
055: import javax.imageio.IIOException;
056: import javax.imageio.ImageTypeSpecifier;
057: import javax.imageio.metadata.IIOMetadata;
058: import javax.imageio.spi.ImageReaderSpi;
059: import com.sun.media.imageioimpl.plugins.clib.CLibImageReader;
060: import com.sun.medialib.codec.png.Decoder;
061: import com.sun.medialib.codec.jiio.mediaLibImage;
062:
063: final class CLibPNGImageReader extends CLibImageReader {
064: private Decoder decoder;
065: private HashMap imageTypes = new HashMap();
066:
067: CLibPNGImageReader(ImageReaderSpi originatingProvider) {
068: super (originatingProvider);
069: }
070:
071: // Implement abstract method defined in superclass.
072: protected final synchronized mediaLibImage decode(InputStream stream)
073: throws IOException {
074: try {
075: decoder = new Decoder(stream);
076: decoder.decode();
077: } catch (Throwable t) {
078: throw new IIOException("codecLib error", t);
079: }
080:
081: /* XXX Get significant bits (sBIT chunk).
082: byte[] bits = decoder.getSignificantBits();
083: if(bits != null) {
084: System.out.println("getSignificantBits():");
085: for(int i = 0; i < bits.length; i++) {
086: System.out.println((bits[i]&0xff));
087: }
088: }
089: */
090:
091: mediaLibImage mlImage = null;
092: try {
093: mlImage = decoder.getImage();
094: } catch (Throwable t) {
095: throw new IIOException("codecLib error", t);
096: }
097:
098: if (mlImage == null) {
099: throw new IIOException(I18N
100: .getString("CLibPNGImageReader0"));
101: }
102:
103: return mlImage;
104: }
105:
106: public synchronized Iterator getImageTypes(int imageIndex)
107: throws IOException {
108: seekToImage(imageIndex);
109:
110: ArrayList types = null;
111: Integer key = new Integer(imageIndex);
112: if (imageTypes.containsKey(key)) {
113: types = (ArrayList) imageTypes.get(key);
114: } else {
115: types = new ArrayList();
116:
117: // Get the mediaLibImage from the Decoder.
118: mediaLibImage image = getImage(imageIndex);
119:
120: // Get the palette.
121: byte[] rgbPalette = null;
122: try {
123: // Note: the 'decoder' instance variable is set by
124: // decode() which is called by getImage() above.
125: rgbPalette = decoder.getPalette();
126: } catch (Throwable t) {
127: throw new IIOException("codecLib error", t);
128: }
129:
130: if (rgbPalette != null) {
131: // Indexed image: set up the RGB palette arrays.
132: int paletteLength = rgbPalette.length / 3;
133: byte[] r = new byte[paletteLength];
134: byte[] g = new byte[paletteLength];
135: byte[] b = new byte[paletteLength];
136: for (int i = 0, j = 0; i < paletteLength; i++) {
137: r[i] = rgbPalette[j++];
138: g[i] = rgbPalette[j++];
139: b[i] = rgbPalette[j++];
140: }
141:
142: // Set up the alpha palette array if needed.
143: int[] alphaPalette = null;
144: try {
145: alphaPalette = decoder.getTransparency();
146: } catch (Throwable t) {
147: throw new IIOException("codecLib error", t);
148: }
149: byte[] a = null;
150: if (alphaPalette != null) {
151: // Load beginning of palette from the chunk
152: a = new byte[paletteLength];
153: for (int i = 0; i < alphaPalette.length; i++) {
154: a[i] = (byte) (alphaPalette[i] & 0x000000ff);
155: }
156:
157: // Fill rest of palette with 255
158: for (int i = alphaPalette.length; i < paletteLength; i++) {
159: a[i] = (byte) 0xff;
160: }
161: }
162:
163: types.add(createImageType(image, null, decoder
164: .getBitDepth(), r, g, b, a));
165: } else {
166: // Attempt to use the iCCP chunk if present, no sRGB
167: // chunk is present, and the ICC color space type matches
168: // the image type.
169: ColorSpace cs = null;
170: if (decoder.getStandardRGB() == Decoder.PNG_sRGB_NOT_DEFINED) {
171: // Get the profile data.
172: byte[] iccProfileData = decoder
173: .getEmbeddedICCProfile();
174: if (iccProfileData != null) {
175: // Create the ColorSpace.
176: ICC_Profile iccProfile = ICC_Profile
177: .getInstance(iccProfileData);
178: ICC_ColorSpace icccs = new ICC_ColorSpace(
179: iccProfile);
180:
181: // Check the color space type against the
182: // number of bands and the palette.
183: int numBands = image.getChannels();
184: if ((icccs.getType() == ColorSpace.TYPE_RGB && (numBands >= 3 || rgbPalette != null))
185: || (icccs.getType() == ColorSpace.TYPE_GRAY
186: && numBands < 3 && rgbPalette == null)) {
187: cs = icccs;
188: }
189: }
190: }
191:
192: int bitDepth = decoder.getBitDepth();
193:
194: ImageTypeSpecifier type = createImageType(image, cs,
195: bitDepth, null, null, null, null);
196: types.add(type);
197:
198: if (type.getColorModel().getColorSpace().equals(cs)) {
199: types.add(createImageType(image, null, bitDepth,
200: null, null, null, null));
201: }
202: }
203:
204: imageTypes.put(key, types);
205: }
206:
207: // XXX Need also to use getBackground() to save the background
208: // color somewhere, eventually as an image property with the
209: // name "background_color" and with a java.awt.Color value.
210: // See PNGImageDecoder or the PNG ImageReader for more info.
211: // Looks like this needs to be set as a metadata entry. It is
212: // obtained from the decoder using getBackground().
213:
214: return types.iterator();
215: }
216:
217: // Override superclass method.
218: protected void resetLocal() {
219: decoder = null;
220: imageTypes.clear();
221: super .resetLocal();
222: }
223:
224: public synchronized IIOMetadata getImageMetadata(int imageIndex)
225: throws IIOException {
226: if (input == null) {
227: throw new IllegalStateException("input == null");
228: }
229: seekToImage(imageIndex);
230:
231: CLibPNGMetadata im = new CLibPNGMetadata();
232: try {
233: getImage(imageIndex);
234: } catch (IOException e) {
235: throw new IIOException("codecLib error", e);
236: }
237: im.readMetadata(this , decoder);
238: return im;
239: }
240:
241: /**
242: * Package scope method to classes in package to emit warning messages.
243: */
244: void forwardWarningMessage(String warning) {
245: processWarningOccurred(warning);
246: }
247: }
|