1 /*******************************************************************************
2 * Copyright (c) 2007, 2010 Association for Decentralized Information Management
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
10 * VTT Technical Research Centre of Finland - initial API and implementation
11 *******************************************************************************/
12 package org.simantics.modeling.ui.pdf;
14 import java.io.FileNotFoundException;
15 import java.io.FileOutputStream;
16 import java.security.Security;
17 import java.util.Collection;
18 import java.util.concurrent.atomic.AtomicBoolean;
20 import org.eclipse.core.runtime.IProduct;
21 import org.eclipse.core.runtime.IProgressMonitor;
22 import org.eclipse.core.runtime.OperationCanceledException;
23 import org.eclipse.core.runtime.Platform;
24 import org.eclipse.core.runtime.SubMonitor;
25 import org.simantics.db.RequestProcessor;
26 import org.simantics.db.Resource;
27 import org.simantics.db.Session;
28 import org.simantics.db.exception.DatabaseException;
29 import org.simantics.db.layer0.util.SessionGarbageCollection;
30 import org.simantics.db.management.ISessionContext;
31 import org.simantics.document.DocumentSettings;
32 import org.simantics.document.DocumentUtils;
33 import org.simantics.export.core.pdf.ServiceBasedPdfExportPageEvent;
34 import org.simantics.modeling.requests.CollectionRequest;
35 import org.simantics.modeling.requests.CollectionResult;
36 import org.simantics.modeling.requests.Node;
37 import org.simantics.modeling.ui.preferences.DiagramPreferenceUtil;
38 import org.simantics.ui.jobs.SessionGarbageCollectorJob;
39 import org.simantics.utils.page.PageDesc;
40 import org.simantics.utils.page.PageOrientation;
41 import org.simantics.utils.threads.WorkerThread;
43 import com.kitfox.svg.SVGCache;
44 import com.lowagie.text.Document;
45 import com.lowagie.text.DocumentException;
46 import com.lowagie.text.FontFactory;
47 import com.lowagie.text.PageSize;
48 import com.lowagie.text.Rectangle;
49 import com.lowagie.text.pdf.DefaultFontMapper;
50 import com.lowagie.text.pdf.PdfBoolean;
51 import com.lowagie.text.pdf.PdfContentByte;
52 import com.lowagie.text.pdf.PdfName;
53 import com.lowagie.text.pdf.PdfTemplate;
54 import com.lowagie.text.pdf.PdfWriter;
56 public class DiagramPrinter {
58 public static CollectionResult browse(IProgressMonitor monitor, RequestProcessor processor, Resource[] input) throws DatabaseException {
59 final CollectionResult result = processor.syncRequest(new CollectionRequest(monitor, DiagramPreferenceUtil.getDefaultPreferences().getCompletePageDesc(), input));
63 private static final AtomicBoolean fontFactoryInitialized = new AtomicBoolean();
66 * @param monitor the progress monitor to use for reporting progress to the
67 * user. It is the caller's responsibility to call done() on the
68 * given monitor. Accepts <code>null</code>, indicating that no
69 * progress should be reported and that the operation cannot be
73 * @param flattenedNodes
74 * @param sessionContext
75 * @throws DocumentException
76 * @throws FileNotFoundException
78 public static void printToPdf(
79 IProgressMonitor monitor,
80 PDFExportPlan exportPlan,
82 Collection<Node> flattenedNodes,
83 ISessionContext sessionContext)
85 Collection<Node> flattened = flattenedNodes;
87 SubMonitor progress = SubMonitor.convert(monitor, "Export to PDF", flattened.size() * 2);
89 WorkerThread workerThread = new WorkerThread("Diagram PDF Painter");
92 PdfWriter writer = null;
93 Document document = null;
96 progress.subTask("Loading system fonts");
97 DefaultFontMapper mapper = new DefaultFontMapper();
98 if (fontFactoryInitialized.compareAndSet(false, true)) {
99 // Only register directories once.
100 FontFactory.registerDirectories();
103 SessionGarbageCollectorJob.getInstance().setEnabled(false);
106 boolean first = true;
108 for (Node d : flattened) {
111 //System.out.println("PAGE DESC: " + d.getPageDesc());
112 //System.out.println("PAGE SIZE: " + pageSize);
114 Rectangle pageSize = toPageSize(d.getPageDesc());
115 if (writer == null) {
116 document = new Document(pageSize);
117 writer = PdfWriter.getInstance(document, new FileOutputStream(exportPath));
118 writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
119 writer.setPageEvent(new ServiceBasedPdfExportPageEvent());
120 if ( exportPlan.attachTG ) {
121 writer.addViewerPreference(PdfName.USEATTACHMENTS, PdfBoolean.PDFTRUE);
124 String creator = getCreator();
125 document.addCreator(creator);
128 File keystoreFile = new File("c:\\0009278.p12");
129 String password = "ka7GfzI9Oq";
132 KeyStore ks = KeyStore.getInstance("pkcs12");
133 ks.load(new FileInputStream(keystoreFile), password.toCharArray());
134 List<String> aliases = Collections.list(ks.aliases());
135 String alias = aliases.get(0);
136 PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray());
137 Certificate[] chain = ks.getCertificateChain(alias);
138 int permission = PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY;
140 PdfEncryption crypto = new PdfEncryption();
141 //for (Certificate c : chain) crypto.addRecipient(c, permission);
142 //crypto.addRecipient(chain[2], permission);
143 crypto.setCryptoMode(PdfWriter.ENCRYPTION_AES_128, 0);
144 crypto.setupByEncryptionKey(key.getEncoded(), key.getEncoded().length*8);
145 crypto.getEncryptionDictionary();
148 } catch (Exception e) {
153 writer.setEncryption(
154 new Certificate[] {},
155 new int[] {PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING},
156 PdfWriter.STANDARD_ENCRYPTION_128);
158 //writer.setEncryption(PdfWriter.STANDARD_ENCRYPTION_128, "", "password", PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY);
161 // PdfName companyName = new PdfName("SMTC");
162 // PdfDeveloperExtension ext = new PdfDeveloperExtension(companyName, PdfWriter.PDF_VERSION_1_7, 3);
163 // writer.addDeveloperExtension( ext );
169 document.setPageSize(pageSize);
174 /// ATTACHMENTS - TG ///
175 byte[] attachment = null;
176 if ( exportPlan.attachTG && !d.getDefiningResources().isEmpty() )
178 PdfDictionary fileParameter = new PdfDictionary();
181 final Resource composite = d.getDefiningResources().iterator().next();
182 final Session session = exportPlan.sessionContext.getSession();
184 SimanticsClipboard clipboard = session.syncRequest(new Read<SimanticsClipboard>() {
186 public SimanticsClipboard perform(ReadGraph graph) throws DatabaseException {
187 CopyHandler ch = graph.adapt(composite, CopyHandler.class);
188 SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl();
189 ch.copyToClipboard(graph, clipboard);
193 for (Set<Representation> object : clipboard.getContents()) {
194 TransferableGraph1 tg = ClipboardUtils.accept(object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH);
195 String filename = d.getName()+".diagram";
197 byte[] data = DataContainers.writeFile(
198 new DataContainer("aprosDiagram", 1, new Variant(TransferableGraph1.BINDING, tg))
200 PdfFileSpecification fs = PdfFileSpecification.fileEmbedded(
202 "/Diagram", filename, data, true, "application/simantics/diagram",
204 writer.addFileAttachment(d.getName()+".diagram", fs);
205 } catch ( NullPointerException npe ) {
206 throw new PdfException("Experiment must be activated to export attachments"+npe.getMessage(), npe);
211 } catch (DatabaseException e) {
213 } catch (IOException e) {
217 //////////////////////////
219 String diagramName = formDiagramName(d, true);
220 String subTask = "Page (" + i + "/" + flattened.size() + "): " + diagramName;
222 Resource diagram = d.getDiagramResource();
223 if (diagram == null) {
224 // No diagram, skip page.
225 subTask += " skipped, no diagram.";
226 System.out.println(subTask);
230 System.out.println(subTask);
231 progress.subTask(subTask);
234 PDFPainter.render(workerThread, sessionContext, exportPlan, d, writer, mapper,
235 pageSize, d.getPageDesc(), exportPlan.fitContentToPageMargins, 10000);
236 } catch (InterruptedException e) {
238 } catch (DatabaseException e) {
242 // Paint diagram path/name on the page
243 // TODO: remove this hard coded diagram name printing and
244 // replace it with a page templates that is loaded along with
245 // the rest of the diagram
247 int w = (int) pageSize.getWidth();
248 int h = (int) pageSize.getHeight();
251 PdfContentByte cb = writer.getDirectContent();
253 // PdfTemplate tp = cb.createTemplate(w, h);
254 // Graphics2D g2d = tp.createGraphics(w, h, mapper);
255 // g2d.setColor(Color.black);
256 // java.awt.Font thisFont = new java.awt.Font("Arial", java.awt.Font.ITALIC, 10);
257 // g2d.setFont(thisFont);
258 // FontMetrics metrics = g2d.getFontMetrics();
259 // int width = metrics.stringWidth(diagramName);
260 // g2d.drawString(diagramName, (w - width) / 2, document.getPageSize().getHeight() - PageDesc.toPoints(5));
262 // cb.addTemplate(tp, 0, 0);
264 /// ATTACHMENTS - Write WIKI ///
265 if ( exportPlan.attachWiki && !d.getDefiningResources().isEmpty() ) {
266 final Session session = exportPlan.sessionContext.getSession();
267 Resource composite = d.getDefiningResources().iterator().next();
268 DocumentUtils du = new DocumentUtils();
269 StringBuilder wiki = new StringBuilder();
270 StringBuilder css = new StringBuilder();
271 du.getDocumentWikiTextRecursive(session, composite, wiki, css);
272 DocumentSettings settings = du.getDocumentSettings(session, composite);
273 PdfTemplate tp_ = cb.createTemplate(w, h);
274 if ( wiki.length()>0 ) {
275 String wikiText = wiki.toString();
276 String cssText = css.toString();
277 du.print(session, composite, wikiText, cssText, settings, tp_.getPdfWriter(), document);
279 cb.addTemplate(tp_, 0, 0);
281 //////////////////////////
286 if (progress.isCanceled())
287 throw new OperationCanceledException();
289 System.out.println("GC");
290 SVGCache.getSVGUniverse().clearUnreferenced();
291 SessionGarbageCollection.gc(null, sessionContext.getSession(), true, null);
293 System.out.println("GC finished");
296 } catch (DatabaseException e) {
297 throw new PdfException(e);
298 } catch (FileNotFoundException e) {
299 throw new PdfException(e);
300 } catch (DocumentException e) {
301 throw new PdfException(e);
303 workerThread.stopDispatchingEvents(true);
304 System.out.println("closing document");
306 if ( document!=null ) document.close();
307 if ( writer!=null ) writer.close();
308 } catch(RuntimeException e) {
311 System.out.println("document closed");
312 SessionGarbageCollectorJob.getInstance().setEnabled(true).scheduleAfterQuietTime();
316 public static Rectangle toPageSize(PageDesc pageDesc) {
317 String arg = PageDesc.toPoints(pageDesc.getWidth()) + " " + PageDesc.toPoints(pageDesc.getHeight());
318 Rectangle r = PageSize.getRectangle(arg);
320 if (PageOrientation.Landscape == pageDesc.getOrientation())
323 // Disable inherent borders from the PDF writer.
329 public static String formDiagramName(Node node, boolean parents) {
331 String ret = d.getName();
333 while (d.getParent() != null) {
335 ret = d.getName() + " / " + ret;
338 // String[] pg = node.getPartOfGroups();
339 // if (pg.length > 0)
340 // ret += " [" + EString.implode(pg, " / ") + " / " + node.getName() + "]";
344 public static String getCreator() {
345 String creator = null;
346 IProduct product = Platform.getProduct();
347 if (product != null) {
348 creator = product.getDescription();
349 if (creator == null) {
350 creator = product.getName();
353 if (creator == null) {
354 creator = "Simantics";
360 Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider());