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