/* * Copyright (c) 1998-2011 Caucho Technology -- all rights reserved * * This file is part of Resin(R) Open Source * * Each copy or derived work must preserve the copyright notice and this * notice unmodified. * * Resin Open Source is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * Resin Open Source 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, or any warranty * of NON-INFRINGEMENT. See the GNU General Public License for more * details. * * You should have received a copy of the GNU General Public License * along with Resin Open Source; if not, write to the * * Free Software Foundation, Inc. * 59 Temple Place, Suite 330 * Boston, MA 02111-1307 USA * * @author Scott Ferguson */ package com.caucho.quercus.lib.pdf; import com.caucho.util.L10N; import com.caucho.vfs.Path; import com.caucho.vfs.ReadStream; import com.caucho.vfs.TempBuffer; import com.caucho.vfs.TempStream; import com.caucho.vfs.Vfs; import com.caucho.vfs.WriteStream; import java.awt.image.BufferedImage; import java.io.IOException; import java.io.InputStream; import java.util.logging.Logger; import javax.imageio.ImageIO; /** * deals with an image */ public class PDFImage extends PDFObject { private static final Logger log = Logger.getLogger(PDFImage.class.getName()); private static final L10N L = new L10N(PDFImage.class); private Path _path; private ReadStream _is; private BufferedImage _image; private int _id; private String _type; private int _width; private int _height; private int _bits; private TempBuffer _jpegHead; public PDFImage(Path path) throws IOException { _path = path; _is = path.openRead(); try { parseImage(); } finally { _is.close(); } } /** * Returns the object id. */ public int getId() { return _id; } /** * Sets the object id. */ public void setId(int id) { _id = id; } public double get_width() { return _width; } public double get_height() { return _height; } private boolean parseImage() throws IOException { _image = ImageIO.read(_is); _width = _image.getWidth(); _height = _image.getHeight(); TempStream ts = new TempStream(); WriteStream os = new WriteStream(ts); try { ImageIO.write(_image, "jpeg", os); } finally { os.close(); } /* os = Vfs.openWrite("file:/tmp/caucho/qa/test.jpg"); try { ImageIO.write(_image, "jpeg", os); } finally { os.close(); } os = Vfs.openWrite("file:/tmp/caucho/qa/test.png"); try { ImageIO.write(_image, "png", os); } finally { os.close(); } */ return parseImageJpeg(ts.openRead()); } private boolean parseImageJpeg(ReadStream is) throws IOException { int ch = is.read(); if (ch != 0xff) return false; if (is.read() != 0xd8) return false; TempStream ts = new TempStream(); WriteStream ws = new WriteStream(ts); ws.write(0xff); ws.write(0xd8); is.writeToStream(ws); ws.close(); // XXX: issues with _jpegHead vs ts.openReadAndSaveBuffer() _jpegHead = ts.getHead(); is.close(); _is = new ReadStream(); ts.openRead(_is); parseJPEG(); return true; } private boolean parseGIF() throws IOException { int width = (_is.read() & 0xff) + 256 * (_is.read() & 0xff); int heigth = (_is.read() & 0xff) + 256 * (_is.read() & 0xff); int flags = _is.read(); int background = _is.read(); int pad = _is.read(); int depth = (flags & 0x7) + 1; int []colorMap = null; if ((flags & 0x80) != 0) { colorMap = parseGIFColorMap(depth); } else { System.out.println("GIF: can't cope with local"); return false; } int ch = _is.read(); if (ch != ',') return false; int imgLeft = (_is.read() & 0xff) + 256 * (_is.read() & 0xff); int imgTop = (_is.read() & 0xff) + 256 * (_is.read() & 0xff); int imgWidth = (_is.read() & 0xff) + 256 * (_is.read() & 0xff); int imgHeight = (_is.read() & 0xff) + 256 * (_is.read() & 0xff); flags = _is.read() & 0xff; if ((flags & 0x80) != 0) { System.out.println("GIF: can't cope with local"); return false; } if ((flags & 0x40) != 0) { System.out.println("GIF: can't cope with interlaced"); return false; } parseGIFData(colorMap); return false; } private int []parseGIFColorMap(int depth) throws IOException { int []values = new int[1 << depth]; for (int i = 0; i < values.length; i++) { int value = (0x10000 * (_is.read() & 0xff) + 0x100 * (_is.read() & 0xff) + 0x1 * (_is.read() & 0xff)); values[i] = value; } return values; } private void parseGIFData(int []colorMap) throws IOException { /* System.out.println("CS: " + codeSize); int []strings = new int[4096]; for (int i = 0; i < clearCode; i++) strings[i] = i; while ((blockCount = _is.read()) > 0) { int offset = 0; int prev = 0; for (int i = 0; i < blockCount; i++) { int data = _is.read(); if (i == 0) { System.out.println("C: " + data); System.out.println("C: " + (data & _codeMask)); } } } */ } private boolean parseJPEG() throws IOException { if (_is.read() != 0xff || _is.read() != 0xd8) return false; int ch; while ((ch = _is.read()) == 0xff) { ch = _is.read(); if (ch == 0xff) { _is.unread(); } else if (0xd0 <= ch && ch <= 0xd9) { // rst } else if (0x01 == ch) { // rst } else if (ch == 0xc0) { int len = 256 * _is.read() + _is.read(); _bits = _is.read(); _height = 256 * _is.read() + _is.read(); _width = 256 * _is.read() + _is.read(); _type = "jpeg"; return true; } else { int len = 256 * _is.read() + _is.read(); _is.skip(len - 2); } } return false; } String getResourceName() { return "/XObject"; } String getResource() { return ("<< /I" + _id + " " + _id + " 0 R >>"); } /** * Writes the object to the stream */ public void writeObjectNew(PDFWriter out) throws IOException { long length = _path.getLength(); out.println("<< /Type /XObject"); out.println(" /Subtype /Image"); out.println(" /Width " + _width); out.println(" /Height " + _height); out.println(" /ColorSpace /DeviceRGB"); out.println(" /BitsPerComponent " + _bits); // out.println(" /Filter /DCTDecode"); out.println(" /Length " + length); out.println(">>"); out.println("stream"); TempBuffer tb = TempBuffer.allocate(); byte []buffer = tb.getBuffer(); int sublen; InputStream is = _path.openRead(); while ((sublen = is.read(buffer, 0, buffer.length)) > 0) { out.write(buffer, 0, sublen); } out.println(); out.println("endstream"); } public void writeObject(PDFWriter out) throws IOException { int length = 0; for (TempBuffer ptr = _jpegHead; ptr != null; ptr = ptr.getNext()) length += ptr.getLength(); out.println("<< /Type /XObject"); out.println(" /Subtype /Image"); out.println(" /Width " + _width); out.println(" /Height " + _height); out.println(" /ColorSpace /DeviceRGB"); out.println(" /BitsPerComponent " + _bits); out.println(" /Filter /DCTDecode"); out.println(" /Length " + length); out.println(">>"); out.println("stream"); for (TempBuffer ptr = _jpegHead; ptr != null; ptr = ptr.getNext()) { out.write(ptr.getBuffer(), 0, ptr.getLength()); } out.println(); out.println("endstream"); } static class GIFDecode { private final int _codeSize; private final int _clearCode; private final int _endOfCode; private ReadStream _is; private int _blockSize; GIFDecode(ReadStream is) throws IOException { _is = is; _codeSize = _is.read(); _clearCode = 1 << _codeSize; _endOfCode = _clearCode + 1; } int readByte() throws IOException { if (_blockSize < 0) return -1; else if (_blockSize == 0) { _blockSize = _is.read(); if (_blockSize == 0) { _blockSize = -1; return -1; } } _blockSize--; return _is.read(); } } }