001: /*
002: * Copyright (c) 1998-2008 Caucho Technology -- all rights reserved
003: *
004: * This file is part of Resin(R) Open Source
005: *
006: * Each copy or derived work must preserve the copyright notice and this
007: * notice unmodified.
008: *
009: * Resin Open Source is free software; you can redistribute it and/or modify
010: * it under the terms of the GNU General Public License as published by
011: * the Free Software Foundation; either version 2 of the License, or
012: * (at your option) any later version.
013: *
014: * Resin Open Source is distributed in the hope that it will be useful,
015: * but WITHOUT ANY WARRANTY; without even the implied warranty of
016: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
017: * of NON-INFRINGEMENT. See the GNU General Public License for more
018: * details.
019: *
020: * You should have received a copy of the GNU General Public License
021: * along with Resin Open Source; if not, write to the
022: *
023: * Free Software Foundation, Inc.
024: * 59 Temple Place, Suite 330
025: * Boston, MA 02111-1307 USA
026: *
027: * @author Scott Ferguson
028: */
029:
030: package com.caucho.quercus.lib.pdf;
031:
032: import com.caucho.util.L10N;
033: import com.caucho.vfs.Path;
034: import com.caucho.vfs.ReadStream;
035: import com.caucho.vfs.TempBuffer;
036: import com.caucho.vfs.TempStream;
037: import com.caucho.vfs.WriteStream;
038:
039: import java.io.IOException;
040: import java.util.logging.Logger;
041:
042: /**
043: * deals with an image
044: */
045: public class PDFImage extends PDFObject {
046: private static final Logger log = Logger.getLogger(PDFImage.class
047: .getName());
048: private static final L10N L = new L10N(PDFImage.class);
049:
050: private ReadStream _is;
051:
052: private int _id;
053:
054: private String _type;
055: private int _width;
056: private int _height;
057: private int _bits;
058: private TempBuffer _jpegHead;
059:
060: public PDFImage(Path path) throws IOException {
061: _is = path.openRead();
062:
063: try {
064: parseImage();
065: } finally {
066: _is.close();
067: }
068: }
069:
070: /**
071: * Returns the object id.
072: */
073: public int getId() {
074: return _id;
075: }
076:
077: /**
078: * Sets the object id.
079: */
080: public void setId(int id) {
081: _id = id;
082: }
083:
084: public double get_width() {
085: return _width;
086: }
087:
088: public double get_height() {
089: return _height;
090: }
091:
092: private boolean parseImage() throws IOException {
093: int ch = _is.read();
094:
095: if (ch == 'G') {
096: if (_is.read() != 'I' || _is.read() != 'F'
097: || _is.read() != '8' || _is.read() != '7'
098: || _is.read() != 'a')
099: return false;
100:
101: return parseGIF();
102: } else if (ch == 0xff) {
103: if (_is.read() != 0xd8)
104: return false;
105:
106: TempStream ts = new TempStream();
107:
108: WriteStream ws = new WriteStream(ts);
109: ws.write(0xff);
110: ws.write(0xd8);
111: _is.writeToStream(ws);
112: ws.close();
113:
114: // XXX: issues with _jpegHead vs ts.openReadAndSaveBuffer()
115: _jpegHead = ts.getHead();
116: _is.close();
117:
118: _is = new ReadStream();
119: ts.openRead(_is);
120:
121: parseJPEG();
122:
123: return true;
124: }
125:
126: return false;
127: }
128:
129: private boolean parseGIF() throws IOException {
130: int width = (_is.read() & 0xff) + 256 * (_is.read() & 0xff);
131: int heigth = (_is.read() & 0xff) + 256 * (_is.read() & 0xff);
132: int flags = _is.read();
133: int background = _is.read();
134: int pad = _is.read();
135:
136: int depth = (flags & 0x7) + 1;
137:
138: int[] colorMap = null;
139:
140: if ((flags & 0x80) != 0) {
141: colorMap = parseGIFColorMap(depth);
142: } else {
143: System.out.println("GIF: can't cope with local");
144: return false;
145: }
146:
147: int ch = _is.read();
148: if (ch != ',')
149: return false;
150:
151: int imgLeft = (_is.read() & 0xff) + 256 * (_is.read() & 0xff);
152: int imgTop = (_is.read() & 0xff) + 256 * (_is.read() & 0xff);
153: int imgWidth = (_is.read() & 0xff) + 256 * (_is.read() & 0xff);
154: int imgHeight = (_is.read() & 0xff) + 256 * (_is.read() & 0xff);
155: flags = _is.read() & 0xff;
156:
157: if ((flags & 0x80) != 0) {
158: System.out.println("GIF: can't cope with local");
159: return false;
160: }
161: if ((flags & 0x40) != 0) {
162: System.out.println("GIF: can't cope with interlaced");
163: return false;
164: }
165:
166: parseGIFData(colorMap);
167:
168: return false;
169: }
170:
171: private int[] parseGIFColorMap(int depth) throws IOException {
172: int[] values = new int[1 << depth];
173:
174: for (int i = 0; i < values.length; i++) {
175: int value = (0x10000 * (_is.read() & 0xff) + 0x100
176: * (_is.read() & 0xff) + 0x1 * (_is.read() & 0xff));
177:
178: values[i] = value;
179: }
180:
181: return values;
182: }
183:
184: private void parseGIFData(int[] colorMap) throws IOException {
185: /*
186: System.out.println("CS: " + codeSize);
187:
188: int []strings = new int[4096];
189:
190: for (int i = 0; i < clearCode; i++)
191: strings[i] = i;
192:
193: while ((blockCount = _is.read()) > 0) {
194: int offset = 0;
195: int prev = 0;
196:
197: for (int i = 0; i < blockCount; i++) {
198: int data = _is.read();
199:
200: if (i == 0) {
201: System.out.println("C: " + data);
202: System.out.println("C: " + (data & _codeMask));
203: }
204: }
205: }
206: */
207: }
208:
209: private boolean parseJPEG() throws IOException {
210: if (_is.read() != 0xff || _is.read() != 0xd8)
211: return false;
212:
213: int ch;
214:
215: while ((ch = _is.read()) == 0xff) {
216: ch = _is.read();
217:
218: if (ch == 0xff) {
219: _is.unread();
220: } else if (0xd0 <= ch && ch <= 0xd9) {
221: // rst
222: } else if (0x01 == ch) {
223: // rst
224: } else if (ch == 0xc0) {
225: int len = 256 * _is.read() + _is.read();
226:
227: _bits = _is.read();
228: _height = 256 * _is.read() + _is.read();
229: _width = 256 * _is.read() + _is.read();
230: _type = "jpeg";
231:
232: return true;
233: } else {
234: int len = 256 * _is.read() + _is.read();
235:
236: _is.skip(len - 2);
237: }
238: }
239:
240: return false;
241: }
242:
243: String getResource() {
244: return ("/XObject << /I" + _id + " " + _id + " 0 R >>");
245: }
246:
247: /**
248: * Writes the object to the stream
249: */
250: public void writeObject(PDFWriter out) throws IOException {
251: int length = 0;
252:
253: for (TempBuffer ptr = _jpegHead; ptr != null; ptr = ptr
254: .getNext())
255: length += ptr.getLength();
256:
257: out.println("<< /Type /XObject");
258: out.println(" /Subtype /Image");
259: out.println(" /Width " + _width);
260: out.println(" /Height " + _height);
261: out.println(" /ColorSpace /DeviceRGB");
262: out.println(" /BitsPerComponent " + _bits);
263: out.println(" /Filter /DCTDecode");
264: out.println(" /Length " + length);
265: out.println(">>");
266: out.println("stream");
267:
268: for (TempBuffer ptr = _jpegHead; ptr != null; ptr = ptr
269: .getNext()) {
270: out.write(ptr.getBuffer(), 0, ptr.getLength());
271: }
272: out.println();
273: out.println("endstream");
274: }
275:
276: static class GIFDecode {
277: private final int _codeSize;
278: private final int _clearCode;
279: private final int _endOfCode;
280:
281: private ReadStream _is;
282: private int _blockSize;
283:
284: GIFDecode(ReadStream is) throws IOException {
285: _is = is;
286:
287: _codeSize = _is.read();
288: _clearCode = 1 << _codeSize;
289: _endOfCode = _clearCode + 1;
290: }
291:
292: int readByte() throws IOException {
293: if (_blockSize < 0)
294: return -1;
295: else if (_blockSize == 0) {
296: _blockSize = _is.read();
297:
298: if (_blockSize == 0) {
299: _blockSize = -1;
300: return -1;
301: }
302: }
303:
304: _blockSize--;
305:
306: return _is.read();
307: }
308: }
309: }
|