001: /**
002: * PDF.java
003: *
004: Copyright (c) 2007, Innovatics Inc.
005:
006: All rights reserved.
007:
008: Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:
009:
010: * Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.
011: * Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.
012:
013: THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
014: "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
015: LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
016: A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
017: CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
018: EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
019: PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
020: PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
021: LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
022: NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
023: SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
024: */package com.pdfjet;
025:
026: import java.lang.*;
027: import java.io.*;
028: import java.text.*;
029: import java.util.*;
030: import java.util.zip.*;
031:
032: //>>>>pdfjet {
033: public class PDF {
034:
035: protected ByteArrayOutputStream buf = null;
036: protected int objNumber = 0;
037:
038: protected List<Font> fonts = new ArrayList<Font>();
039: protected List<Image> images = new ArrayList<Image>();
040: protected List<Page> pages = new ArrayList<Page>();
041: protected String fontPath = "fonts";
042:
043: private List<Integer> objOffset = new ArrayList<Integer>();
044: private String title = "";
045: private String subject = "";
046: private String author = "";
047:
048: // Here is the layout of the PDF document:
049: //
050: // Fonts
051: // Images
052: // Resources Object
053: // Pages
054: // Page1
055: // Page2
056: // ...
057: // PageN
058: // Info
059: // Root
060: // xref table
061: public PDF() throws Exception {
062: buf = new ByteArrayOutputStream(131072);
063:
064: append(buf, "%PDF-1.4\n");
065: append(buf, '%');
066: buf.write((byte) 0x00F2);
067: buf.write((byte) 0x00F3);
068: buf.write((byte) 0x00F4);
069: buf.write((byte) 0x00F5);
070: buf.write((byte) 0x00F6);
071: append(buf, '\n');
072: }
073:
074: protected void newobj() throws IOException {
075: objOffset.add(buf.size());
076: append(buf, ++objNumber);
077: append(buf, " 0 obj\n");
078: }
079:
080: protected void endobj() throws IOException {
081: append(buf, "endobj\n");
082: }
083:
084: private int addResourcesObject() throws Exception {
085: newobj();
086: append(buf, "<<\n");
087: append(buf, "/ProcSet [/PDF /Text /ImageC]\n");
088: append(buf, "/Font\n");
089: append(buf, "<<\n");
090: for (int i = 0; i < fonts.size(); i++) {
091: Font font = fonts.get(i);
092: append(buf, "/F");
093: append(buf, font.objNumber);
094: append(buf, " ");
095: append(buf, font.objNumber);
096: append(buf, " 0 R\n");
097: }
098: append(buf, ">>\n");
099: append(buf, "/XObject\n");
100: append(buf, "<<\n");
101: for (int i = 0; i < images.size(); i++) {
102: Image image = images.get(i);
103: append(buf, "/Im");
104: append(buf, image.objNumber);
105: append(buf, " ");
106: append(buf, image.objNumber);
107: append(buf, " 0 R\n");
108: }
109: append(buf, ">>\n");
110: append(buf, ">>\n");
111: endobj();
112: return objNumber;
113: }
114:
115: protected int addPagesObject() throws Exception {
116: newobj();
117: append(buf, "<<\n");
118: append(buf, "/Type /Pages\n");
119: append(buf, "/Kids [ ");
120: int pageObjNumber = objNumber + 1;
121: for (int i = 0; i < pages.size(); i++) {
122: Page page = pages.get(i);
123: append(buf, pageObjNumber);
124: append(buf, " 0 R ");
125: pageObjNumber += 3;
126: pageObjNumber += page.annots.size();
127: }
128: append(buf, "]\n");
129: append(buf, "/Count ");
130: append(buf, pages.size());
131: append(buf, '\n');
132: append(buf, ">>\n");
133: endobj();
134: return objNumber;
135: }
136:
137: protected int addInfoObject() throws Exception {
138: // This is the info object
139: newobj();
140: append(buf, "<<\n");
141: append(buf, "/Title (");
142: append(buf, title);
143: append(buf, ")\n");
144: append(buf, "/Subject (");
145: append(buf, subject);
146: append(buf, ")\n");
147: append(buf, "/Author (");
148: append(buf, author);
149: append(buf, ")\n");
150: append(buf, "/Producer (PDFjet v2.51)\n");
151: SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");
152: append(buf, "/CreationDate (D:");
153: append(buf, sdf.format(new Date()));
154: append(buf, ")\n");
155: append(buf, ">>\n");
156: endobj();
157: return objNumber;
158: }
159:
160: protected void addAllPages(int pagesObjNumber, int resObjNumber)
161: throws Exception {
162: for (int i = 0; i < pages.size(); i++) {
163: Page page = pages.get(i);
164:
165: // Page object
166: newobj();
167: append(buf, "<<\n");
168: append(buf, "/Type /Page\n");
169: append(buf, "/Parent ");
170: append(buf, pagesObjNumber);
171: append(buf, " 0 R\n");
172: append(buf, "/MediaBox [0 0 ");
173: append(buf, page.width);
174: append(buf, " ");
175: append(buf, page.height);
176: append(buf, "]\n");
177: append(buf, "/Resources ");
178: append(buf, resObjNumber);
179: append(buf, " 0 R\n");
180: append(buf, "/Contents ");
181: append(buf, objNumber + 1);
182: append(buf, " 0 R\n");
183: if (page.annots.size() > 0) {
184: append(buf, "/Annots [ ");
185: for (int j = 0; j < page.annots.size(); j++) {
186: append(buf, objNumber + 3 + j);
187: append(buf, " 0 R ");
188: }
189: append(buf, "]\n");
190: }
191: append(buf, ">>\n");
192: endobj();
193:
194: // Page contents
195: newobj();
196: append(buf, "<<\n");
197: append(buf, "/Filter /FlateDecode\n");
198: append(buf, "/Length ");
199: append(buf, objNumber + 1);
200: append(buf, " 0 R\n");
201: append(buf, ">>\n");
202: append(buf, "stream\n");
203: int count1 = buf.size();
204: DeflaterOutputStream dos = new DeflaterOutputStream(buf,
205: new Deflater());
206: dos.write(page.buf.toByteArray());
207: dos.finish();
208: int count2 = buf.size();
209: append(buf, "\nendstream\n");
210: endobj();
211:
212: // Content stream length
213: newobj();
214: append(buf, count2 - count1);
215: append(buf, '\n');
216: endobj();
217:
218: addAnnotDictionaries(page);
219: }
220: }
221:
222: protected void addAnnotDictionaries(Page page) throws Exception {
223: for (int i = 0; i < page.annots.size(); i++) {
224: Annotation annot = page.annots.get(i);
225: newobj();
226: append(buf, "<<\n");
227: append(buf, "/Type /Annot\n");
228: append(buf, "/Subtype /Link\n");
229: append(buf, "/Rect [");
230: append(buf, annot.x1);
231: append(buf, ' ');
232: append(buf, annot.y1);
233: append(buf, ' ');
234: append(buf, annot.x2);
235: append(buf, ' ');
236: append(buf, annot.y2);
237: append(buf, "]\n");
238: append(buf, "/Border[0 0 0]\n");
239: append(buf, "/A <<\n");
240: append(buf, "/S /URI\n");
241: append(buf, "/URI (");
242: append(buf, annot.uri);
243: append(buf, ")\n");
244: append(buf, ">>\n");
245: append(buf, ">>\n");
246: endobj();
247: }
248: }
249:
250: public void wrap() throws Exception {
251: int resObjNumber = addResourcesObject();
252: int infoObjNumber = addInfoObject();
253: int pagesObjNumber = addPagesObject();
254: addAllPages(pagesObjNumber, resObjNumber);
255:
256: // This is the root object
257: newobj();
258: append(buf, "<<\n");
259: append(buf, "/Type /Catalog\n");
260: append(buf, "/Pages ");
261: append(buf, pagesObjNumber);
262: append(buf, " 0 R\n");
263: append(buf, "/Base ()\n"); // Needed by the Foxit Reader
264: append(buf, ">>\n");
265: endobj();
266:
267: int startxref = buf.size();
268: // Create the xref table
269: append(buf, "xref\n");
270: append(buf, "0 ");
271: append(buf, objNumber + 1);
272: append(buf, '\n');
273: append(buf, "0000000000 65535 f \n");
274: for (int i = 0; i < objOffset.size(); i++) {
275: int offset = objOffset.get(i);
276: String str = String.valueOf(offset);
277: for (int j = 0; j < 10 - str.length(); j++) {
278: append(buf, '0');
279: }
280: append(buf, str);
281: append(buf, " 00000 n \n");
282: }
283: append(buf, "trailer\n");
284: append(buf, "<<\n");
285: append(buf, "/Size ");
286: append(buf, objNumber + 1);
287: append(buf, '\n');
288: append(buf, "/Root ");
289: append(buf, objNumber);
290: append(buf, " 0 R\n");
291: append(buf, "/Info ");
292: append(buf, infoObjNumber);
293: append(buf, " 0 R\n");
294: append(buf, ">>\n");
295: append(buf, "startxref\n");
296: append(buf, startxref);
297: append(buf, '\n');
298: append(buf, "%%EOF\n");
299: }
300:
301: public void setFontPath(String fontPath) {
302: this .fontPath = fontPath;
303: }
304:
305: public void setTitle(String title) {
306: this .title = title;
307: }
308:
309: public void setSubject(String subject) {
310: this .subject = subject;
311: }
312:
313: public void setAuthor(String author) {
314: this .author = author;
315: }
316:
317: public ByteArrayOutputStream getData(String fileName)
318: throws Exception {
319: return buf;
320: }
321:
322: public void save(String fileName) throws Exception {
323: FileOutputStream fos = new FileOutputStream(fileName);
324: BufferedOutputStream bos = new BufferedOutputStream(fos);
325: buf.writeTo(bos);
326: bos.close();
327: }
328:
329: protected void append(ByteArrayOutputStream buf, String str)
330: throws IOException {
331: for (int i = 0; i < str.length(); i++) {
332: buf.write((byte) str.charAt(i));
333: }
334: }
335:
336: protected void append(ByteArrayOutputStream buf, int num)
337: throws IOException {
338: append(buf, String.valueOf(num));
339: }
340:
341: protected void append(ByteArrayOutputStream buf, double val)
342: throws IOException {
343: append(buf, String.valueOf(val));
344: }
345:
346: protected void append(ByteArrayOutputStream buf, char ch)
347: throws IOException {
348: buf.write((byte) ch);
349: }
350:
351: protected void append(DeflaterOutputStream dos, String str)
352: throws IOException {
353: dos.write(str.getBytes());
354: }
355:
356: protected void append(DeflaterOutputStream dos, int num)
357: throws IOException {
358: append(dos, String.valueOf(num));
359: }
360:
361: protected void append(DeflaterOutputStream dos, double val)
362: throws IOException {
363: append(dos, String.valueOf(val));
364: }
365:
366: protected void append(DeflaterOutputStream dos, char ch)
367: throws IOException {
368: dos.write((byte) ch);
369: }
370:
371: protected void addText(ByteArrayOutputStream buf, String str,
372: Font font) throws IOException {
373: append(buf, "[ (");
374: for (int i = 0; i < str.length(); i++) {
375: int c1 = str.charAt(i);
376: if (font.isComposite) {
377: if (c1 < font.firstChar || c1 > font.lastChar) {
378: c1 = 0x0020;
379: }
380: int high = c1 >> 8;
381: if (high == '(' || high == ')' || high == '\\') {
382: buf.write((byte) '\\');
383: }
384: buf.write((byte) high);
385: if (c1 == '(' || c1 == ')' || c1 == '\\') {
386: buf.write((byte) '\\');
387: }
388: buf.write((byte) c1);
389: continue;
390: }
391:
392: if (c1 < font.firstChar || c1 > font.lastChar) {
393: c1 = 0x0020;
394: }
395: if (c1 == '(' || c1 == ')' || c1 == '\\') {
396: buf.write((byte) '\\');
397: }
398: buf.write((byte) c1);
399:
400: if (font.isStandard == false)
401: continue;
402: if (font.kernPairs == false)
403: continue;
404: if (font.name.startsWith("C") || // Courier
405: font.name.startsWith("S") || // Symbol
406: font.name.startsWith("Z")) { // ZapfDingbats
407: continue;
408: }
409:
410: if (i == str.length() - 1)
411: break;
412: c1 -= 32;
413: int c2 = str.charAt(i + 1);
414: if (c2 < font.firstChar || c2 > font.lastChar) {
415: c2 = 32;
416: }
417: for (int j = 2; j < font.metrics[c1].length; j += 2) {
418: if (font.metrics[c1][j] == c2) {
419: append(buf, ") ");
420: append(buf, -font.metrics[c1][j + 1]);
421: append(buf, " (");
422: break;
423: }
424: }
425: }
426: append(buf, ") ] TJ\n");
427: }
428:
429: } // End of PDF.java
430: //>>>>}
|