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