176dc196ae1a1aac3ef49349fe2f535fab9d049b
[jalviewjs.git] / src / javajs / export / PDFObject.java
1 package javajs.export;
2
3 import java.io.ByteArrayOutputStream;
4 import java.io.IOException;
5 import java.io.OutputStream;
6 import java.util.Hashtable;
7 import java.util.Map;
8 import java.util.Map.Entry;
9 import java.util.zip.Deflater;
10 import java.util.zip.DeflaterOutputStream;
11
12 import javajs.util.SB;
13
14
15 /**
16  * A rudimentary class for working with PDF document creation.
17  * Written from scratch based on PDF Reference 13.
18  * 
19  * @author hansonr  Bob Hanson hansonr@stolaf.edu  10/28/2013
20  * 
21  */
22 class PDFObject extends SB {    
23         private Map<String, Object> dictionary;
24         private byte[] stream;
25         private int index;
26         String type;
27         int len;
28         int pt;
29         
30         PDFObject(int index) {
31                 this.index = index;
32         }
33
34         String getRef() {
35                 return index + " 0 R";
36         }
37         
38         String getID() {
39                 return type.substring(0, 1) + index;
40         }
41         
42         boolean isFont() {
43                 return "Font".equals(type);
44         }
45
46         void setStream(byte[] stream) {
47                 this.stream = stream;
48         }
49
50         Object getDef(String key) {
51                 return dictionary.get(key);
52         }
53         
54         void addDef(String key, Object value) {
55                 if (dictionary  == null)
56                         dictionary = new Hashtable<String, Object>();
57                 dictionary.put(key, value);
58                 if (key.equals("Type"))
59                         type = ((String) value).substring(1);
60         }
61         
62         void setAsStream() {
63                 stream = toBytes(0, -1);
64                 setLength(0);
65         }
66         
67         int output(OutputStream os) throws IOException {
68                 if (index > 0) {
69                         String s = index + " 0 obj\n";
70                         write(os, s.getBytes(), 0);
71                 }
72                 int streamLen = 0;
73                 if (dictionary != null) {
74                         if (dictionary.containsKey("Length")) {
75                                 if (stream == null)
76                                         setAsStream();
77                                 streamLen = stream.length;
78                                 boolean doDeflate = (streamLen > 1000);
79         if (doDeflate) {
80           Deflater deflater = new Deflater(9);
81           ByteArrayOutputStream outBytes = new ByteArrayOutputStream(1024);
82           DeflaterOutputStream compBytes = new DeflaterOutputStream(outBytes,
83               deflater);
84           compBytes.write(stream, 0, streamLen);
85           compBytes.finish();
86           stream = outBytes.toByteArray();
87           dictionary.put("Filter", "/FlateDecode");
88           streamLen = stream.length;
89         }
90                                 dictionary.put("Length", "" + streamLen);
91                         }
92                         write(os, getDictionaryText(dictionary, "\n").getBytes(), 0);
93                 }
94                 if (length() > 0)
95                         write(os, this.toString().getBytes(), 0);
96                 if (stream != null) {
97                         write(os, "stream\r\n".getBytes(), 0);
98                         write(os, stream, streamLen);
99                         write(os, "\r\nendstream\r\n".getBytes(), 0);
100                 }
101                 if (index > 0)
102                         write(os, "endobj\n".getBytes(), 0);
103                 return len;
104         }
105
106         private void write(OutputStream os, byte[] bytes, int nBytes) throws IOException {
107                 if (nBytes == 0)
108                         nBytes = bytes.length;
109                 len += nBytes;
110                 os.write(bytes, 0, nBytes);
111         }
112
113         @SuppressWarnings("unchecked")
114         private String getDictionaryText(Map<String, Object> d, String nl) {
115                 SB sb = new SB();
116                 sb.append("<<");
117                 if (d.containsKey("Type"))
118                         sb.append("/Type").appendO(d.get("Type"));
119                 for (Entry<String, Object> e : d.entrySet()) {
120                         String s = e.getKey();
121                         if (s.equals("Type") || s.startsWith("!"))
122                                 continue;
123                         sb.append("/" + s);
124                         Object o = e.getValue();
125                         if (o instanceof Map<?, ?>) {
126                                 sb.append((getDictionaryText((Map<String, Object>) o, "")));
127                                 continue;
128                         }
129                         s = (String) e.getValue();
130                         if (!s.startsWith("/"))
131                                 sb.append(" ");
132                         sb.appendO(s);
133                 }
134                 return (sb.length() > 3 ? sb.append(">>").append(nl).toString() : "");
135         }
136
137         @SuppressWarnings("unchecked")
138         private Map<String, Object> createSubdict(Map<String, Object> d0, String dict) {
139                 Map<String, Object> d = (Map<String, Object>) d0.get(dict);
140                 if (d == null)
141                         d0.put(dict, d = new Hashtable<String, Object>());
142                 return d;
143         }
144
145         void addResource(String type, String key, String value) {
146                 Map<String, Object> r = createSubdict(dictionary, "Resources");
147                 if (type != null)
148                         r = createSubdict(r, type);
149                 r.put(key, value);
150         }
151         
152 }