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
10 * VTT Technical Research Centre of Finland - initial API and implementation
\r
11 *******************************************************************************/
\r
12 package org.simantics.modeling.ui.pdf;
\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
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
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
38 * Renders ICanvasContext instances into PDF documents.
\r
40 * @author Tuukka Lehtonen
\r
42 public class PDFBuilder {
\r
44 private final PdfWriter writer;
\r
46 private final FontMapper mapper;
\r
48 private final Rectangle pageSize;
\r
50 private final PageDesc pageDesc;
\r
52 private final boolean fitDiagramContentsToPageMargins;
\r
59 * @param fitDiagramContentsToPageMargins see
\r
60 * {@link PDFExportPlan#fitContentToPageMargins} for a description
\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
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
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
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
93 double w = pageDesc.getOrientedWidth();
\r
94 double h = pageDesc.getOrientedHeight();
\r
96 //System.out.println("PDFBuilder.paint: page in millimeters " + w + " x " + h + ", page in points " + pw + " x " + ph);
\r
99 QualityHints.HIGH_QUALITY_HINTS.setQuality(g2);
\r
100 g2.setRenderingHint(RenderingHints.KEY_STROKE_CONTROL, RenderingHints.VALUE_STROKE_PURE);
\r
102 // Make sure the transformation is reset.
\r
103 AffineTransform tr = new AffineTransform();
\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
109 Rectangle2D controlArea = new Rectangle2D.Double(m.left.diagramAbsolute, m.top.diagramAbsolute, mw, mh);
\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
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
125 g2.setTransform(tr);
\r
126 //g2.setClip(new Rectangle2D.Double(0, 0, w, h));
\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
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
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
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
147 if (canvasContext.isLocked())
\r
148 throw new IllegalStateException("cannot render PDF, canvas context is locked: " + canvasContext);
\r
150 canvasContext.getSceneGraph().render(g2);
\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
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
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
183 // g2.setColor(Color.black);
\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
193 // g2.setColor(Color.yellow);
\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
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