]> gerrit.simantics Code Review - simantics/platform.git/blob - bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/PDFBuilder.java
Migrated source code from Simantics SVN
[simantics/platform.git] / bundles / org.simantics.modeling.ui / src / org / simantics / modeling / ui / pdf / PDFBuilder.java
1 /*******************************************************************************\r
2  * Copyright (c) 2007, 2010 Association for Decentralized Information Management\r
3  * in Industry THTH ry.\r
4  * All rights reserved. This program and the accompanying materials\r
5  * are made available under the terms of the Eclipse Public License v1.0\r
6  * which accompanies this distribution, and is available at\r
7  * http://www.eclipse.org/legal/epl-v10.html\r
8  *\r
9  * Contributors:\r
10  *     VTT Technical Research Centre of Finland - initial API and implementation\r
11  *******************************************************************************/\r
12 package org.simantics.modeling.ui.pdf;\r
13 \r
14 import java.awt.Graphics2D;\r
15 import java.awt.RenderingHints;\r
16 import java.awt.geom.AffineTransform;\r
17 import java.awt.geom.Rectangle2D;\r
18 \r
19 import org.simantics.g2d.canvas.ICanvasContext;\r
20 import org.simantics.g2d.diagram.DiagramHints;\r
21 import org.simantics.g2d.diagram.DiagramUtils;\r
22 import org.simantics.g2d.diagram.IDiagram;\r
23 import org.simantics.g2d.participant.TransformUtil;\r
24 import org.simantics.scenegraph.g2d.G2DPDFRenderingHints;\r
25 import org.simantics.scenegraph.g2d.G2DRenderingHints;\r
26 import org.simantics.scenegraph.utils.QualityHints;\r
27 import org.simantics.utils.page.MarginUtils;\r
28 import org.simantics.utils.page.MarginUtils.Margins;\r
29 import org.simantics.utils.page.PageDesc;\r
30 \r
31 import com.lowagie.text.Rectangle;\r
32 import com.lowagie.text.pdf.FontMapper;\r
33 import com.lowagie.text.pdf.PdfContentByte;\r
34 import com.lowagie.text.pdf.PdfTemplate;\r
35 import com.lowagie.text.pdf.PdfWriter;\r
36 \r
37 /**\r
38  * Renders ICanvasContext instances into PDF documents.\r
39  * \r
40  * @author Tuukka Lehtonen\r
41  */\r
42 public class PDFBuilder {\r
43 \r
44     private final PdfWriter  writer;\r
45 \r
46     private final FontMapper mapper;\r
47 \r
48     private final Rectangle  pageSize;\r
49 \r
50     private final PageDesc   pageDesc;\r
51 \r
52     private final boolean    fitDiagramContentsToPageMargins;\r
53 \r
54     /**\r
55      * @param writer\r
56      * @param mapper\r
57      * @param pageSize\r
58      * @param pageDesc\r
59      * @param fitDiagramContentsToPageMargins see\r
60      *        {@link PDFExportPlan#fitContentToPageMargins} for a description\r
61      *        of this parameter\r
62      */\r
63     public PDFBuilder(PdfWriter writer, FontMapper mapper, Rectangle pageSize, PageDesc pageDesc, boolean fitDiagramContentsToPageMargins) {\r
64         assert writer != null;\r
65         assert mapper != null;\r
66         assert pageSize != null;\r
67         assert pageDesc != null;\r
68 \r
69         this.writer = writer;\r
70         this.mapper = mapper;\r
71         this.pageSize = pageSize;\r
72         this.pageDesc = pageDesc;\r
73         this.fitDiagramContentsToPageMargins = fitDiagramContentsToPageMargins;\r
74     }\r
75 \r
76     /**\r
77      * @param canvasContext the canvas context to paint\r
78      * @param writeResults <code>true</code> to actually write the resulting PDF\r
79      *        content into the {@link PdfWriter} used to construct this\r
80      *        PDFBuilder\r
81      */\r
82     public void paint(ICanvasContext canvasContext, boolean writeResults) {\r
83         // Specify rendering template size in points.\r
84         float pw = pageSize.getWidth();\r
85         float ph = pageSize.getHeight();\r
86         PdfContentByte cb = writer.getDirectContent();\r
87         PdfTemplate tp = cb.createTemplate(pw, ph);\r
88         Graphics2D g2 = tp.createGraphics(pw, ph, mapper);\r
89         g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_WRITER, tp.getPdfWriter());\r
90         g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_BYTECONTENT, tp);\r
91         g2.setRenderingHint(G2DPDFRenderingHints.KEY_PDF_FONTMAPPER, mapper);\r
92 \r
93         double w = pageDesc.getOrientedWidth();\r
94         double h = pageDesc.getOrientedHeight();\r
95 \r
96         //System.out.println("PDFBuilder.paint: page in millimeters " + w + " x " + h + ", page in points " + pw + " x " + ph);\r
97 \r
98         try {\r
99             QualityHints.HIGH_QUALITY_HINTS.setQuality(g2);\r
100             g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);\r
101 \r
102             // Make sure the transformation is reset.\r
103             AffineTransform tr = new AffineTransform();\r
104 \r
105             Margins m = pageDesc.getMargins();\r
106             double mw = pageDesc.getOrientedWidth() - m.left.diagramAbsolute - m.right.diagramAbsolute;\r
107             double mh = pageDesc.getOrientedHeight() - m.top.diagramAbsolute - m.bottom.diagramAbsolute;\r
108 \r
109             Rectangle2D controlArea = new Rectangle2D.Double(m.left.diagramAbsolute, m.top.diagramAbsolute, mw, mh);\r
110 \r
111             if (fitDiagramContentsToPageMargins) {\r
112                 IDiagram diagram = canvasContext.getDefaultHintContext().getHint(DiagramHints.KEY_DIAGRAM);\r
113                 final Rectangle2D diagramRect = DiagramUtils.getContentRect(diagram);\r
114                 if (diagramRect != null) {\r
115                     canvasContext.getSingleItem(TransformUtil.class).fitArea(controlArea, diagramRect, MarginUtils.NO_MARGINS);\r
116                 }\r
117             }\r
118 \r
119             // We render in millimeters, but iText expects coordinates in points.\r
120             // So we scale everything to point space.\r
121             //System.out.println("PDFBuilder.paint: input transform " + tr);\r
122             tr.scale(pw / w, ph / h);\r
123             //System.out.println("PDFBuilder.paint: point space scaled transform " + tr);\r
124 \r
125             g2.setTransform(tr);\r
126             //g2.setClip(new Rectangle2D.Double(0, 0, w, h));\r
127 \r
128 //            if (paintMargin) {\r
129 //                g2.setStroke(new BasicStroke());\r
130 //                g2.setColor(Color.DARK_GRAY);\r
131 //                g2.draw(new Rectangle2D.Double(pageSize.getBorderWidthLeft(), pageSize.getBorderWidthTop(), ww, hh));\r
132 //            }\r
133 \r
134             // DEBUG: Paint page edges\r
135 //            g2.setStroke(new BasicStroke(2));\r
136 //            g2.setColor(Color.MAGENTA);\r
137 //            g2.draw(new Rectangle2D.Double(pageDesc.getLeftEdgePos(), pageDesc.getTopEdgePos(), pageDesc.getOrientedWidth(), pageDesc.getOrientedHeight()));\r
138 \r
139             // DEBUG: paint content area, i.e. the bounds that were fitted to\r
140             // meet the printed page margins.\r
141 //            g2.setColor(new Color(255, 255, 0, 128));\r
142 //            g2.draw(controlArea);\r
143 \r
144             // TODO: test that this doesn't break anything.\r
145             g2.setRenderingHint(G2DRenderingHints.KEY_CONTROL_BOUNDS, new Rectangle2D.Double(0, 0, w, h));\r
146 \r
147             if (canvasContext.isLocked())\r
148                 throw new IllegalStateException("cannot render PDF, canvas context is locked: " + canvasContext);\r
149 \r
150             canvasContext.getSceneGraph().render(g2);\r
151 \r
152             // Code from iText examples:\r
153 //            double ew = w/2;\r
154 //            double eh = h/2;\r
155 //            Ellipse2D.Double circle, oval, leaf, stem;\r
156 //            Area circ, ov, leaf1, leaf2, st1, st2;\r
157 //            circle = new Ellipse2D.Double();\r
158 //            oval = new Ellipse2D.Double();\r
159 //            leaf = new Ellipse2D.Double();\r
160 //            stem = new Ellipse2D.Double();\r
161 //            circ = new Area(circle);\r
162 //            ov = new Area(oval);\r
163 //            leaf1 = new Area(leaf);\r
164 //            leaf2 = new Area(leaf);\r
165 //            st1 = new Area(stem);\r
166 //            st2 = new Area(stem);\r
167 //            g2.setColor(Color.green);\r
168 //\r
169 //            // Creates the first leaf by filling the intersection of two Area objects created from an ellipse.\r
170 //            leaf.setFrame(ew-16, eh-29, 15.0, 15.0);\r
171 //            leaf1 = new Area(leaf);\r
172 //            leaf.setFrame(ew-14, eh-47, 30.0, 30.0);\r
173 //            leaf2 = new Area(leaf);\r
174 //            leaf1.intersect(leaf2);\r
175 //            g2.fill(leaf1);\r
176 //\r
177 //            // Creates the second leaf.\r
178 //            leaf.setFrame(ew+1, eh-29, 15.0, 15.0);\r
179 //            leaf1 = new Area(leaf);\r
180 //            leaf2.intersect(leaf1);\r
181 //            g2.fill(leaf2);\r
182 //\r
183 //            g2.setColor(Color.black);\r
184 //\r
185 //            // Creates the stem by filling the Area resulting from the subtraction of two Area objects created from an ellipse.\r
186 //            stem.setFrame(ew, eh-42, 40.0, 40.0);\r
187 //            st1 = new Area(stem);\r
188 //            stem.setFrame(ew+3, eh-47, 50.0, 50.0);\r
189 //            st2 = new Area(stem);\r
190 //            st1.subtract(st2);\r
191 //            g2.fill(st1);\r
192 //\r
193 //            g2.setColor(Color.yellow);\r
194 //\r
195 //            // Creates the pear itself by filling the Area resulting from the union of two Area objects created by two different ellipses.\r
196 //            circle.setFrame(ew-25, eh, 50.0, 50.0);\r
197 //            oval.setFrame(ew-19, eh-20, 40.0, 70.0);\r
198 //            circ = new Area(circle);\r
199 //            ov = new Area(oval);\r
200 //            circ.add(ov);\r
201 //            g2.fill(circ);\r
202         } finally {\r
203             g2.dispose();\r
204 \r
205             if (writeResults) {\r
206                 //System.out.println("Storing PDF template");\r
207                 float x = (float) pageDesc.getLeftEdgePos();\r
208                 float y = (float) pageDesc.getTopEdgePos();\r
209                 cb.addTemplate(tp, x, y);\r
210             }\r
211         }\r
212     }\r
213 \r
214 }\r