/*
* Copyright 2004 Sun Microsystems, Inc., 4150 Network Circle,
* Santa Clara, California 95054, U.S.A. All rights reserved.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
package com.sun.pdfview.decode;
import java.awt.Image;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.awt.image.ImageObserver;
import java.io.ByteArrayInputStream;
import java.nio.ByteBuffer;
import javax.swing.ImageIcon;
import ch.randelshofer.media.jpeg.JPEGImageIO;
import com.sun.pdfview.PDFObject;
import com.sun.pdfview.PDFParseException;
/**
* decode a DCT encoded array into a byte array. This class uses Java's
* built-in JPEG image class to do the decoding.
*
* @author Mike Wessler
*/
public class DCTDecode {
/**
* decode an array of bytes in DCT format.
* <p>
* DCT is the format used by JPEG images, so this class simply
* loads the DCT-format bytes as an image, then reads the bytes out
* of the image to create the array. Unfortunately, their most
* likely use is to get turned BACK into an image, so this isn't
* terribly efficient... but is is general... don't hit, please.
* <p>
* The DCT-encoded stream may have 1, 3 or 4 samples per pixel, depending
* on the colorspace of the image. In decoding, we look for the colorspace
* in the stream object's dictionary to decide how to decode this image.
* If no colorspace is present, we guess 3 samples per pixel.
*
* @param dict the stream dictionary
* @param buf the DCT-encoded buffer
* @param params the parameters to the decoder (ignored)
* @return the decoded buffer
* @throws PDFParseException
*/
protected static ByteBuffer decode(PDFObject dict, ByteBuffer buf, PDFObject params) throws PDFParseException {
// BEGIN PATCH W. Randelshofer Completely rewrote decode routine in
// order to
// support JPEG images in the CMYK color space.
BufferedImage bimg = loadImageData(buf);
byte[] output = ImageDataDecoder.decodeImageData(bimg);
return ByteBuffer.wrap(output);
// END PATCH W. Randelshofer Completely rewrote decode routine in order
// to
// support JPEG images in the CMYK color space.
}
/*************************************************************************
* @param buf
* @return
* @throws PDFParseException
************************************************************************/
private static BufferedImage loadImageData(ByteBuffer buf)
throws PDFParseException {
buf.rewind();
byte[] input = new byte[buf.remaining()];
buf.get(input);
BufferedImage bimg;
try {
try {
bimg = JPEGImageIO.read(new ByteArrayInputStream(input), false);
} catch (IllegalArgumentException colorProfileMismatch) {
// we experienced this problem with an embedded jpeg
// that specified a icc color profile with 4 components
// but the raster had only 3 bands (apparently YCC encoded)
Image img = Toolkit.getDefaultToolkit().createImage(input);
// wait until image is loaded using ImageIcon for convenience
ImageIcon imageIcon = new ImageIcon(img);
// copy to buffered image
bimg = new BufferedImage(imageIcon.getIconWidth(), imageIcon.getIconHeight(), BufferedImage.TYPE_INT_RGB);
bimg.getGraphics().drawImage(img, 0, 0 , null);
}
} catch (Exception ex) {
PDFParseException ex2 = new PDFParseException("DCTDecode failed");
ex2.initCause(ex);
throw ex2;
}
return bimg;
}
}
/**
* Image tracker. I'm not sure why I'm not using the default Java
* image tracker for this one.
*/
class MyTracker implements ImageObserver {
boolean done= false;
/**
* create a new MyTracker that watches this image. The image
* will start loading immediately.
*/
public MyTracker(Image img) {
img.getWidth(this);
}
/**
* More information has come in about the image.
*/
@Override
public boolean imageUpdate(Image img, int infoflags, int x, int y,
int width, int height) {
if ((infoflags & (ALLBITS | ERROR | ABORT))!=0) {
synchronized(this) {
this.done= true;
notifyAll();
}
return false;
}
return true;
}
/**
* Wait until the image is done, then return.
*/
public synchronized void waitForAll() {
if (!this.done) {
try {
wait();
} catch (InterruptedException ie) {}
}
}
}