removes org.json from srcjar
[jalview.git] / unused / javajs / export / PDFCreator.java
1 /* $RCSfile$
2  * $Author: hansonr $
3  * $Date: 2009-06-30 18:58:33 -0500 (Tue, 30 Jun 2009) $
4  * $Revision: 11158 $
5  *
6  * Some portions of this file have been modified by Robert Hanson hansonr.at.stolaf.edu 2012-2017
7  * for use in SwingJS via transpilation into JavaScript using Java2Script.
8  *
9  * Copyright (C) 2002-2005  The Jmol Development Team
10  *
11  * Contact: jmol-developers@lists.sf.net
12  *
13  *  This library is free software; you can redistribute it and/or
14  *  modify it under the terms of the GNU Lesser General Public
15  *  License as published by the Free Software Foundation; either
16  *  version 2.1 of the License, or (at your option) any later version.
17  *
18  *  This library is distributed in the hope that it will be useful,
19  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
21  *  Lesser General Public License for more details.
22  *
23  *  You should have received a copy of the GNU Lesser General Public
24  *  License along with this library; if not, write to the Free Software
25  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
26  */
27 package javajs.export;
28
29 import java.io.IOException;
30 import java.io.OutputStream;
31 import java.util.Hashtable;
32 import java.util.Map;
33 import java.util.Map.Entry;
34
35 import javajs.util.Lst;
36 import javajs.util.SB;
37
38
39
40 public class PDFCreator {
41  
42   private OutputStream os;
43   private Lst<PDFObject> indirectObjects;
44   private PDFObject root;
45   private PDFObject graphics; 
46 //  private PDFObject pageResources;
47 //  private PDFObject graphicsResources;
48
49   private int pt;
50   private int xrefPt;
51   private int count;
52
53   private int height;
54   private int width;
55   
56   private Map<String, PDFObject>fonts;
57
58   public PDFCreator() {
59    // for Class.forName  
60   }
61
62   public void setOutputStream(OutputStream os) {
63     this.os = os;
64   }
65
66   public void newDocument(int paperWidth, int paperHeight, boolean isLandscape) {
67     width = (isLandscape ? paperHeight : paperWidth);
68     height = (isLandscape ? paperWidth : paperHeight);
69     System.out.println("Creating PDF with width=" + width + " and height=" + height);
70     fonts = new Hashtable<String, PDFObject>();
71     indirectObjects = new Lst<PDFObject>();
72     //graphicsResources = newObject(null);
73     //pageResources = newObject(null); // will set this to compressed stream later
74     root = newObject("Catalog");
75     PDFObject pages = newObject("Pages");
76     PDFObject page = newObject("Page");
77     PDFObject pageContents = newObject(null);
78     graphics = newObject("XObject");
79     
80     root.addDef("Pages", pages.getRef());
81     pages.addDef("Count", "1");
82     pages.addDef("Kids", "[ " + page.getRef() +" ]");
83     page.addDef("Parent", pages.getRef());
84     page.addDef("MediaBox", "[ 0 0 " + paperWidth + " " + paperHeight + " ]");
85     if (isLandscape)
86       page.addDef("Rotate", "90");
87
88     pageContents.addDef("Length", "?");
89     pageContents.append((isLandscape ? "q 0 1 1 0 0 0 " : "q 1 0 0 -1 0 "+(paperHeight))+" cm /" + graphics.getID() + " Do Q");
90     page.addDef("Contents", pageContents.getRef());   
91     addProcSet(page);
92     addProcSet(graphics);
93     // will add fonts as well as they are needed
94     graphics.addDef("Subtype", "/Form");
95     graphics.addDef("FormType", "1");
96     graphics.addDef("BBox", "[0 0 " + width + " " + height + "]");
97     graphics.addDef("Matrix", "[1 0 0 1 0 0]");
98     graphics.addDef("Length", "?");
99     page.addResource("XObject", graphics.getID(), graphics.getRef());   
100     g("q 1 w 1 J 1 j 10 M []0 d q "); // line width 1, line cap circle, line join circle, miter limit 10, solid
101     clip(0, 0, width, height);
102   }   
103
104   private void addProcSet(PDFObject o) {
105     o.addResource(null, "ProcSet", "[/PDF /Text /ImageB /ImageC /ImageI]");
106   }
107
108   private void clip(int x1, int y1, int x2, int y2) {
109     moveto(x1, y1);
110     lineto(x2, y1);
111     lineto(x2, y2);
112     lineto(x1, y2);
113     g("h W n");
114   }
115
116   public void moveto(int x, int y) {
117     g(x + " " + y  + " m");
118   }
119
120   public void lineto(int x, int y) {
121     g(x + " " + y  + " l");
122   }
123
124   private PDFObject newObject(String type) {
125     PDFObject o = new PDFObject(++count);
126     if (type != null)
127       o.addDef("Type", "/" + type);
128     indirectObjects.addLast(o);
129     return o;
130   }
131
132   public void addInfo(Map<String, String> data) {
133     Hashtable<String, Object> info = new Hashtable<String, Object>();
134     for (Entry<String, String> e: data.entrySet()) {
135       String value = "(" + e.getValue().replace(')','_').replace('(','_')+ ")";
136       info.put(e.getKey(), value);      
137     }
138     root.addDef("Info", info);
139   }
140
141   private PDFObject addFontResource(String fname) {
142     PDFObject f = newObject("Font");
143     fonts.put(fname, f);
144     f.addDef("BaseFont", fname);
145     f.addDef("Encoding", "/WinAnsiEncoding");
146     f.addDef("Subtype", "/Type1");
147     graphics.addResource("Font", f.getID(), f.getRef());
148     return f;
149   }
150
151   private Map<Object, PDFObject> images;
152   
153   public void addImageResource(Object newImage, int width, int height, int[] buffer, boolean isRGB) {
154     PDFObject imageObj = newObject("XObject");
155     if (images == null)
156       images = new Hashtable<Object, PDFObject>();
157     images.put(newImage, imageObj);   
158     imageObj.addDef("Subtype", "/Image");
159     imageObj.addDef("Length", "?");
160     imageObj.addDef("ColorSpace", isRGB ? "/DeviceRGB" : "/DeviceGray");
161     imageObj.addDef("BitsPerComponent", "8");
162     imageObj.addDef("Width", "" + width);
163     imageObj.addDef("Height", "" + height);
164     graphics.addResource("XObject", imageObj.getID(), imageObj.getRef());
165     int n = buffer.length;
166     byte[] stream = new byte[n * (isRGB ? 3 : 1)];
167     if (isRGB) {
168       for (int i = 0, pt = 0; i < n; i++) {
169         stream[pt++] = (byte) ((buffer[i] >> 16) & 0xFF);
170         stream[pt++] = (byte) ((buffer[i] >> 8) & 0xFF);
171         stream[pt++] = (byte) (buffer[i] & 0xFF);
172       }
173     } else {
174       for (int i = 0; i < n; i++)
175         stream[i] = (byte) buffer[i];
176     }
177     imageObj.setStream(stream);
178     graphics.addResource("XObject", imageObj.getID(), imageObj.getRef());
179   }
180
181   public void g(String cmd) {
182     graphics.append(cmd).appendC('\n');
183   }
184
185   private void output(String s) throws IOException {
186    byte[] b = s.getBytes();
187    os.write(b, 0, b.length);
188    pt += b.length;
189   }
190
191   public void closeDocument() throws IOException {
192     g("Q Q");
193     outputHeader();
194     writeObjects();
195     writeXRefTable();
196     writeTrailer();
197     os.flush();
198     os.close();
199   }
200
201   private void outputHeader() throws IOException {
202     output("%PDF-1.3\n%");
203     byte[] b = new byte[] {-1, -1, -1, -1};
204     os.write(b, 0, b.length);
205     pt += 4;
206     output("\n");
207   }
208
209   private void writeTrailer() throws IOException {
210     PDFObject trailer = new PDFObject(-2);
211     output("trailer");
212     trailer.addDef("Size", "" + indirectObjects.size());
213     trailer.addDef("Root", root.getRef());
214     trailer.output(os);
215     output("startxref\n");
216     output("" + xrefPt + "\n");
217     output("%%EOF\n");
218   }
219
220   /**
221    * Write Font objects first.
222    * 
223    * @throws IOException
224    */
225   private void writeObjects() throws IOException {
226     int nObj = indirectObjects.size();
227     for (int i = 0; i < nObj; i++) {
228       PDFObject o = indirectObjects.get(i);
229       if (!o.isFont())
230         continue;
231       o.pt = pt;
232       pt += o.output(os);
233     }
234     for (int i = 0; i < nObj; i++) {
235       PDFObject o = indirectObjects.get(i);
236       if (o.isFont())
237         continue;
238       o.pt = pt;
239       pt += o.output(os);
240     }
241   }
242
243   private void writeXRefTable() throws IOException {
244     xrefPt = pt;
245     int nObj = indirectObjects.size();
246     SB sb = new SB();
247     // note trailing space, needed because \n is just one character
248     sb.append("xref\n0 " + (nObj + 1) 
249         + "\n0000000000 65535 f\r\n");
250     for (int i = 0; i < nObj; i++) {
251       PDFObject o = indirectObjects.get(i);
252       String s = "0000000000" + o.pt;
253       sb.append(s.substring(s.length() - 10));
254       sb.append(" 00000 n\r\n");
255     }
256     output(sb.toString());
257   }
258
259   public boolean canDoLineTo() {
260     return true;
261   }
262
263   public void fill() {
264     g("f");   
265   }
266
267   public void stroke() {
268     g("S");   
269   }
270
271   public void doCircle(int x, int y, int r, boolean doFill) {
272     double d = r*4*(Math.sqrt(2)-1)/3;
273     double dx = x;
274     double dy = y;
275     g((dx + r) + " " + dy + " m");
276     g((dx + r) + " " + (dy + d) + " " + (dx + d) + " " + (dy + r) + " " + (dx) + " " + (dy + r) + " "  + " c");
277     g((dx - d) + " " + (dy + r) + " " + (dx - r) + " " + (dy + d) + " " + (dx - r) + " " + (dy) + " c");
278     g((dx - r) + " " + (dy - d) + " " + (dx - d) + " " + (dy - r) + " " + (dx) + " " + (dy - r) + " c");
279     g((dx + d) + " " + (dy - r) + " " + (dx + r) + " " + (dy - d) + " " + (dx + r) + " " + (dy) + " c");
280     g(doFill ? "f" : "s");
281   }
282
283   public void doPolygon(int[] axPoints, int[] ayPoints, int nPoints, boolean doFill) {
284     moveto(axPoints[0], ayPoints[0]);
285     for (int i = 1; i < nPoints; i++)
286       lineto(axPoints[i], ayPoints[i]);
287     g(doFill ? "f" : "s");
288   }
289
290   public void doRect(int x, int y, int width, int height, boolean doFill) {
291     g(x + " " + y + " " + width + " " + height + " re " + (doFill ? "f" : "s"));
292   }
293
294   public void drawImage(Object image, int destX0, int destY0,
295       int destX1, int destY1, int srcX0, int srcY0, int srcX1, int srcY1) {
296     PDFObject imageObj = images.get(image);
297     if (imageObj == null)
298       return;
299     g("q");
300     clip(destX0, destY0, destX1, destY1);
301     double iw = Double.parseDouble((String) imageObj.getDef("Width"));
302     double ih = Double.parseDouble((String) imageObj.getDef("Height"));   
303     double dw = (destX1 - destX0 + 1);
304     double dh  = (destY1 - destY0 + 1);
305     double sw = (srcX1 - srcX0 + 1);
306     double sh = (srcY1 - srcY0 + 1);
307     double scaleX = dw / sw;
308     double scaleY = dh / sh;
309     double transX = destX0 - srcX0 * scaleX;
310     double transY = destY0 + (ih - srcY0) * scaleY;
311     g(scaleX*iw + " 0 0 " + -scaleY*ih + " " + transX + " " + transY + " cm");
312     g("/" + imageObj.getID() + " Do");
313     g("Q");
314   }
315
316   public void drawStringRotated(String s, int x, int y, int angle) {
317     g("q " + getRotation(angle) + " " + x + " " + y
318         + " cm BT(" + s + ")Tj ET Q");
319   }
320
321   public String getRotation(int angle) {    
322     float cos = 0, sin = 0;
323     switch (angle) {
324     case 0:
325       cos = 1;
326       break;
327     case 90:
328       sin = 1;
329       break;
330     case -90:
331       sin = -1;
332       break;
333     case 180:
334       cos = -1;
335       break;
336     default:
337       float a = (float) (angle * (Math.PI / 180));
338       cos = (float) Math.cos(a);
339       sin = (float) Math.sin(a);
340       if (Math.abs(cos) < 0.0001)
341         cos = 0;
342       if (Math.abs(sin) < 0.0001)
343         sin = 0;
344     }
345     return  cos + " " + sin + " " + sin + " " + -cos;
346   }
347
348   public void setColor(float[] rgb, boolean isFill) {
349     g(rgb[0] + " " + rgb[1] + " " + rgb[2] + (isFill ? " rg" : " RG"));
350   }
351
352   public void setFont(String fname, float size) {
353     PDFObject f = fonts.get(fname);
354     if (f == null)
355       f = addFontResource(fname);
356     g("/" + f.getID() + " " + size + " Tf");
357   }
358
359   public void setLineWidth(float width) {
360     g(width + " w");    
361   }
362
363   public void translateScale(float x, float y, float scale) {
364     g(scale + " 0 0 " + scale + " " + x + " " + y + " cm");
365   }
366
367 }