001: /*
002: * $Id: DCTDecode.java,v 1.2 2007/12/20 18:33:33 rbair Exp $
003: *
004: * Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
005: * Santa Clara, California 95054, U.S.A. All rights reserved.
006: *
007: * This library is free software; you can redistribute it and/or
008: * modify it under the terms of the GNU Lesser General Public
009: * License as published by the Free Software Foundation; either
010: * version 2.1 of the License, or (at your option) any later version.
011: *
012: * This library is distributed in the hope that it will be useful,
013: * but WITHOUT ANY WARRANTY; without even the implied warranty of
014: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
015: * Lesser General Public License for more details.
016: *
017: * You should have received a copy of the GNU Lesser General Public
018: * License along with this library; if not, write to the Free Software
019: * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
020: */
021:
022: package com.sun.pdfview.decode;
023:
024: import java.awt.Graphics;
025: import java.awt.Image;
026: import java.awt.Toolkit;
027: import java.awt.image.BufferedImage;
028: import java.awt.image.DataBufferByte;
029: import java.awt.image.DataBufferInt;
030: import java.awt.image.ImageObserver;
031: import java.io.IOException;
032: import java.nio.ByteBuffer;
033:
034: import com.sun.pdfview.PDFObject;
035: import com.sun.pdfview.PDFParseException;
036: import com.sun.pdfview.colorspace.PDFColorSpace;
037:
038: /**
039: * decode a DCT encoded array into a byte array. This class uses Java's
040: * built-in JPEG image class to do the decoding.
041: *
042: * @author Mike Wessler
043: */
044: public class DCTDecode {
045:
046: /**
047: * decode an array of bytes in DCT format.
048: * <p>
049: * DCT is the format used by JPEG images, so this class simply
050: * loads the DCT-format bytes as an image, then reads the bytes out
051: * of the image to create the array. Unfortunately, their most
052: * likely use is to get turned BACK into an image, so this isn't
053: * terribly efficient... but is is general... don't hit, please.
054: * <p>
055: * The DCT-encoded stream may have 1, 3 or 4 samples per pixel, depending
056: * on the colorspace of the image. In decoding, we look for the colorspace
057: * in the stream object's dictionary to decide how to decode this image.
058: * If no colorspace is present, we guess 3 samples per pixel.
059: *
060: * @param dict the stream dictionary
061: * @param buf the DCT-encoded buffer
062: * @param params the parameters to the decoder (ignored)
063: * @return the decoded buffer
064: */
065: protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf,
066: PDFObject params) throws PDFParseException {
067: // System.out.println("DCTDecode image info: "+params);
068: buf.rewind();
069:
070: // copy the data into a byte array required by createimage
071: byte[] ary = new byte[buf.remaining()];
072: buf.get(ary);
073:
074: // wait for the image to get drawn
075: Image img = Toolkit.getDefaultToolkit().createImage(ary);
076: MyTracker mt = new MyTracker(img);
077: mt.waitForAll();
078:
079: // the default components per pixel is 3
080: int numComponents = 3;
081:
082: // see if we have a colorspace
083: try {
084: PDFObject csObj = dict.getDictRef("ColorSpace");
085: if (csObj != null) {
086: // we do, so get the number of components
087: PDFColorSpace cs = PDFColorSpace.getColorSpace(csObj,
088: null);
089: numComponents = cs.getNumComponents();
090: }
091: } catch (IOException ioe) {
092: // oh well
093: }
094:
095: // figure out the type
096: int type = BufferedImage.TYPE_INT_RGB;
097: if (numComponents == 1) {
098: type = BufferedImage.TYPE_BYTE_GRAY;
099: } else if (numComponents == 4) {
100: type = BufferedImage.TYPE_INT_ARGB;
101: }
102:
103: // create a buffered image
104: BufferedImage bimg = new BufferedImage(img.getWidth(null), img
105: .getHeight(null), type);
106: Graphics bg = bimg.getGraphics();
107:
108: // draw the image onto it
109: bg.drawImage(img, 0, 0, null);
110:
111: byte[] output = null;
112:
113: if (type == BufferedImage.TYPE_INT_RGB) {
114: // read back the data
115: DataBufferInt db = (DataBufferInt) bimg.getData()
116: .getDataBuffer();
117: int[] data = db.getData();
118:
119: output = new byte[data.length * 3];
120: for (int i = 0; i < data.length; i++) {
121: output[i * 3] = (byte) (data[i] >> 16);
122: output[i * 3 + 1] = (byte) (data[i] >> 8);
123: output[i * 3 + 2] = (byte) (data[i]);
124: }
125: } else if (type == BufferedImage.TYPE_BYTE_GRAY) {
126: DataBufferByte db = (DataBufferByte) bimg.getData()
127: .getDataBuffer();
128: output = db.getData();
129: } else if (type == BufferedImage.TYPE_INT_ARGB) {
130: // read back the data
131: DataBufferInt db = (DataBufferInt) bimg.getData()
132: .getDataBuffer();
133: int[] data = db.getData();
134:
135: output = new byte[data.length * 4];
136: for (int i = 0; i < data.length; i++) {
137: output[i * 4] = (byte) (data[i] >> 24);
138: output[i * 4 + 1] = (byte) (data[i] >> 16);
139: output[i * 4 + 2] = (byte) (data[i] >> 8);
140: output[i * 4 + 3] = (byte) (data[i]);
141: }
142: }
143:
144: // System.out.println("Translated data");
145: return ByteBuffer.wrap(output);
146: }
147: }
148:
149: /**
150: * Image tracker. I'm not sure why I'm not using the default Java
151: * image tracker for this one.
152: */
153: class MyTracker implements ImageObserver {
154: boolean done = false;
155:
156: /**
157: * create a new MyTracker that watches this image. The image
158: * will start loading immediately.
159: */
160: public MyTracker(Image img) {
161: img.getWidth(this );
162: }
163:
164: /**
165: * More information has come in about the image.
166: */
167: public boolean imageUpdate(Image img, int infoflags, int x, int y,
168: int width, int height) {
169: if ((infoflags & (ALLBITS | ERROR | ABORT)) != 0) {
170: synchronized (this ) {
171: done = true;
172: notifyAll();
173: }
174: return false;
175: }
176: return true;
177: }
178:
179: /**
180: * Wait until the image is done, then return.
181: */
182: public synchronized void waitForAll() {
183: if (!done) {
184: try {
185: wait();
186: } catch (InterruptedException ie) {
187: }
188: }
189: }
190: }
|