X-Git-Url: https://gerrit.simantics.org/r/gitweb?p=simantics%2Fplatform.git;a=blobdiff_plain;f=bundles%2Forg.simantics.modeling.ui%2Fsrc%2Forg%2Fsimantics%2Fmodeling%2Fui%2Fpdf%2FDiagramPrinter.java;h=7f0559348d5b67d227512b37c433b5b407936041;hp=e3101dce2e31ea8d2e200d9f96f56c692e6e463f;hb=9d4a145fef9bcec16e3d1f1477894cba6429b9c4;hpb=15d8500282b7bc9f54e561c88564a10a7def44fb diff --git a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/DiagramPrinter.java b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/DiagramPrinter.java index e3101dce2..7f0559348 100644 --- a/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/DiagramPrinter.java +++ b/bundles/org.simantics.modeling.ui/src/org/simantics/modeling/ui/pdf/DiagramPrinter.java @@ -1,5 +1,5 @@ /******************************************************************************* - * Copyright (c) 2007, 2010 Association for Decentralized Information Management + * Copyright (c) 2007, 2017 Association for Decentralized Information Management * in Industry THTH ry. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 @@ -8,14 +8,17 @@ * * Contributors: * VTT Technical Research Centre of Finland - initial API and implementation + * Semantum Oy - (#7084) refactoring, page numbering support *******************************************************************************/ package org.simantics.modeling.ui.pdf; import java.io.FileNotFoundException; import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.security.Security; import java.util.Collection; -import java.util.concurrent.atomic.AtomicBoolean; import org.eclipse.core.runtime.IProduct; import org.eclipse.core.runtime.IProgressMonitor; @@ -27,9 +30,10 @@ import org.simantics.db.Resource; import org.simantics.db.Session; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.util.SessionGarbageCollection; -import org.simantics.db.management.ISessionContext; import org.simantics.document.DocumentSettings; import org.simantics.document.DocumentUtils; +import org.simantics.export.core.pdf.FontMapping; +import org.simantics.export.core.pdf.PageNumbering; import org.simantics.export.core.pdf.ServiceBasedPdfExportPageEvent; import org.simantics.modeling.requests.CollectionRequest; import org.simantics.modeling.requests.CollectionResult; @@ -39,29 +43,34 @@ import org.simantics.ui.jobs.SessionGarbageCollectorJob; import org.simantics.utils.page.PageDesc; import org.simantics.utils.page.PageOrientation; import org.simantics.utils.threads.WorkerThread; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import com.kitfox.svg.SVGCache; import com.lowagie.text.Document; import com.lowagie.text.DocumentException; -import com.lowagie.text.FontFactory; +import com.lowagie.text.ExceptionConverter; import com.lowagie.text.PageSize; import com.lowagie.text.Rectangle; -import com.lowagie.text.pdf.DefaultFontMapper; +import com.lowagie.text.pdf.FontMapper; import com.lowagie.text.pdf.PdfBoolean; import com.lowagie.text.pdf.PdfContentByte; import com.lowagie.text.pdf.PdfName; import com.lowagie.text.pdf.PdfTemplate; import com.lowagie.text.pdf.PdfWriter; +/** + * @author Tuukka Lehtonen + */ public class DiagramPrinter { + private static final Logger LOGGER = LoggerFactory.getLogger(DiagramPrinter.class); + public static CollectionResult browse(IProgressMonitor monitor, RequestProcessor processor, Resource[] input) throws DatabaseException { final CollectionResult result = processor.syncRequest(new CollectionRequest(monitor, DiagramPreferenceUtil.getDefaultPreferences().getCompletePageDesc(), input)); return result; } - private static final AtomicBoolean fontFactoryInitialized = new AtomicBoolean(); - /** * @param monitor the progress monitor to use for reporting progress to the * user. It is the caller's responsibility to call done() on the @@ -76,38 +85,88 @@ public class DiagramPrinter { * @throws FileNotFoundException */ public static void printToPdf( - IProgressMonitor monitor, - PDFExportPlan exportPlan, - String exportPath, - Collection flattenedNodes, - ISessionContext sessionContext) - throws PdfException { - Collection flattened = flattenedNodes; + IProgressMonitor monitor, + PDFExportPlan exportPlan, + String exportPath, + Collection flattenedNodes) + throws PdfException + { + if (!exportPlan.addPageNumbers) { + printToPdfWithoutPageNumbers(monitor, exportPlan, exportPath, flattenedNodes); + } else { + SubMonitor mon = SubMonitor.convert(monitor, "Export to PDF", flattenedNodes.size() * 3); + + Path tempOutput = Paths.get(exportPath + ".tmp"); + Path finalOutput = Paths.get(exportPath); + + int exportedPages = printToPdfWithoutPageNumbers( + mon.newChild(flattenedNodes.size() * 2, SubMonitor.SUPPRESS_NONE), + exportPlan, + tempOutput.toString(), + flattenedNodes); + + if (mon.isCanceled()) { + tempOutput.toFile().delete(); + throw new OperationCanceledException(); + } - SubMonitor progress = SubMonitor.convert(monitor, "Export to PDF", flattened.size() * 2); + try { + mon.setWorkRemaining(exportedPages); + mon.setTaskName("Numbering output pages"); + mon.subTask(""); + PageNumbering.addPageNumbers( + mon.newChild(flattenedNodes.size()), + tempOutput, finalOutput, + exportPlan.pageNumberPosition, + exportPlan.pageNumberFormat); + } catch (IOException | DocumentException | ExceptionConverter e) { + throw new PdfException(e); + } finally { + tempOutput.toFile().delete(); + } + } + } + + /** + * @param monitor the progress monitor to use for reporting progress to the + * user. It is the caller's responsibility to call done() on the + * given monitor. Accepts null, indicating that no + * progress should be reported and that the operation cannot be + * cancelled. + * + * @param exportPath + * @param flattenedNodes + * @return number of pages printed + * @throws PdfException + * @since 1.28.0 + */ + public static int printToPdfWithoutPageNumbers( + IProgressMonitor monitor, + PDFExportPlan exportPlan, + String exportPath, + Collection flattenedNodes) + throws PdfException + { + SubMonitor progress = SubMonitor.convert(monitor, "Export to PDF", flattenedNodes.size() * 2); WorkerThread workerThread = new WorkerThread("Diagram PDF Painter"); workerThread.start(); PdfWriter writer = null; Document document = null; + int exportedPages = 0; try { progress.subTask("Loading system fonts"); - DefaultFontMapper mapper = new DefaultFontMapper(); - if (fontFactoryInitialized.compareAndSet(false, true)) { - // Only register directories once. - FontFactory.registerDirectories(); - } + FontMapper mapper = FontMapping.defaultFontMapper(); SessionGarbageCollectorJob.getInstance().setEnabled(false); - - boolean first = true; + boolean first = true; int i = 0; - for (Node d : flattened) { + for (Node d : flattenedNodes) { ++i; - + //System.out.println("PAGE DESC: " + d.getPageDesc()); //System.out.println("PAGE SIZE: " + pageSize); @@ -115,98 +174,96 @@ public class DiagramPrinter { if (writer == null) { document = new Document(pageSize); writer = PdfWriter.getInstance(document, new FileOutputStream(exportPath)); - writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7); - writer.setPageEvent(new ServiceBasedPdfExportPageEvent()); - if ( exportPlan.attachTG ) { - writer.addViewerPreference(PdfName.USEATTACHMENTS, PdfBoolean.PDFTRUE); - } + writer.setPdfVersion(PdfWriter.PDF_VERSION_1_7); + writer.setPageEvent(new ServiceBasedPdfExportPageEvent()); + if ( exportPlan.attachTG ) { + writer.addViewerPreference(PdfName.USEATTACHMENTS, PdfBoolean.PDFTRUE); + } - String creator = getCreator(); - document.addCreator(creator); - - /* - File keystoreFile = new File("c:\\0009278.p12"); - String password = "ka7GfzI9Oq"; - - try { - KeyStore ks = KeyStore.getInstance("pkcs12"); - ks.load(new FileInputStream(keystoreFile), password.toCharArray()); - List aliases = Collections.list(ks.aliases()); - String alias = aliases.get(0); - PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray()); - Certificate[] chain = ks.getCertificateChain(alias); - int permission = PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY; - - PdfEncryption crypto = new PdfEncryption(); - //for (Certificate c : chain) crypto.addRecipient(c, permission); - //crypto.addRecipient(chain[2], permission); - crypto.setCryptoMode(PdfWriter.ENCRYPTION_AES_128, 0); - crypto.setupByEncryptionKey(key.getEncoded(), key.getEncoded().length*8); - crypto.getEncryptionDictionary(); - - - } catch (Exception e) { - e.printStackTrace(); - }*/ - - /* - writer.setEncryption( - new Certificate[] {}, - new int[] {PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING}, - PdfWriter.STANDARD_ENCRYPTION_128); - */ - //writer.setEncryption(PdfWriter.STANDARD_ENCRYPTION_128, "", "password", PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY); - - -// PdfName companyName = new PdfName("SMTC"); -// PdfDeveloperExtension ext = new PdfDeveloperExtension(companyName, PdfWriter.PDF_VERSION_1_7, 3); -// writer.addDeveloperExtension( ext ); - + String creator = getCreator(); + document.addCreator(creator); + + /* + File keystoreFile = new File("c:\\0009278.p12"); + String password = "ka7GfzI9Oq"; + + try { + KeyStore ks = KeyStore.getInstance("pkcs12"); + ks.load(new FileInputStream(keystoreFile), password.toCharArray()); + List aliases = Collections.list(ks.aliases()); + String alias = aliases.get(0); + PrivateKey key = (PrivateKey)ks.getKey(alias, password.toCharArray()); + Certificate[] chain = ks.getCertificateChain(alias); + int permission = PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY; + + PdfEncryption crypto = new PdfEncryption(); + //for (Certificate c : chain) crypto.addRecipient(c, permission); + //crypto.addRecipient(chain[2], permission); + crypto.setCryptoMode(PdfWriter.ENCRYPTION_AES_128, 0); + crypto.setupByEncryptionKey(key.getEncoded(), key.getEncoded().length*8); + crypto.getEncryptionDictionary(); + + } catch (Exception e) { + e.printStackTrace(); + }*/ + + /* + writer.setEncryption( + new Certificate[] {}, + new int[] {PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING}, + PdfWriter.STANDARD_ENCRYPTION_128); + */ + //writer.setEncryption(PdfWriter.STANDARD_ENCRYPTION_128, "", "password", PdfWriter.ALLOW_FILL_IN|PdfWriter.ALLOW_PRINTING|PdfWriter.ALLOW_COPY|PdfWriter.ALLOW_ASSEMBLY); + +// PdfName companyName = new PdfName("SMTC"); +// PdfDeveloperExtension ext = new PdfDeveloperExtension(companyName, PdfWriter.PDF_VERSION_1_7, 3); +// writer.addDeveloperExtension( ext ); + document.open(); } if (!first) { - document.setPageSize(pageSize); - document.newPage(); + document.setPageSize(pageSize); + document.newPage(); } /* /// ATTACHMENTS - TG /// byte[] attachment = null; - if ( exportPlan.attachTG && !d.getDefiningResources().isEmpty() ) + if ( exportPlan.attachTG && !d.getDefiningResources().isEmpty() ) try { PdfDictionary fileParameter = new PdfDictionary(); - { - final Resource composite = d.getDefiningResources().iterator().next(); - final Session session = exportPlan.sessionContext.getSession(); - - SimanticsClipboard clipboard = session.syncRequest(new Read() { - @Override - public SimanticsClipboard perform(ReadGraph graph) throws DatabaseException { - CopyHandler ch = graph.adapt(composite, CopyHandler.class); - SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl(); - ch.copyToClipboard(graph, clipboard); - return clipboard; - } - }); - for (Set object : clipboard.getContents()) { - TransferableGraph1 tg = ClipboardUtils.accept(object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH); - String filename = d.getName()+".diagram"; - try { - byte[] data = DataContainers.writeFile( - new DataContainer("aprosDiagram", 1, new Variant(TransferableGraph1.BINDING, tg)) - ); - PdfFileSpecification fs = PdfFileSpecification.fileEmbedded( - writer, - "/Diagram", filename, data, true, "application/simantics/diagram", - fileParameter); - writer.addFileAttachment(d.getName()+".diagram", fs); - } catch ( NullPointerException npe ) { - throw new PdfException("Experiment must be activated to export attachments"+npe.getMessage(), npe); - } - } - } + { + final Resource composite = d.getDefiningResources().iterator().next(); + final Session session = exportPlan.sessionContext.getSession(); + + SimanticsClipboard clipboard = session.syncRequest(new Read() { + @Override + public SimanticsClipboard perform(ReadGraph graph) throws DatabaseException { + CopyHandler ch = graph.adapt(composite, CopyHandler.class); + SimanticsClipboardImpl clipboard = new SimanticsClipboardImpl(); + ch.copyToClipboard(graph, clipboard); + return clipboard; + } + }); + for (Set object : clipboard.getContents()) { + TransferableGraph1 tg = ClipboardUtils.accept(object, SimanticsKeys.KEY_TRANSFERABLE_GRAPH); + String filename = d.getName()+".diagram"; + try { + byte[] data = DataContainers.writeFile( + new DataContainer("aprosDiagram", 1, new Variant(TransferableGraph1.BINDING, tg)) + ); + PdfFileSpecification fs = PdfFileSpecification.fileEmbedded( + writer, + "/Diagram", filename, data, true, "application/simantics/diagram", + fileParameter); + writer.addFileAttachment(d.getName()+".diagram", fs); + } catch ( NullPointerException npe ) { + throw new PdfException("Experiment must be activated to export attachments"+npe.getMessage(), npe); + } + } + } } catch (DatabaseException e) { e.printStackTrace(); @@ -215,66 +272,50 @@ public class DiagramPrinter { } */ ////////////////////////// - + String diagramName = formDiagramName(d, true); - String subTask = "Page (" + i + "/" + flattened.size() + "): " + diagramName; + String subTask = "Page (" + i + "/" + flattenedNodes.size() + "): " + diagramName; Resource diagram = d.getDiagramResource(); if (diagram == null) { // No diagram, skip page. subTask += " skipped, no diagram."; - System.out.println(subTask); + LOGGER.info(subTask); continue; } - System.out.println(subTask); + LOGGER.info(subTask); progress.subTask(subTask); try { - PDFPainter.render(workerThread, sessionContext, exportPlan, d, writer, mapper, + PDFPainter.render(workerThread, exportPlan, d, writer, mapper, pageSize, d.getPageDesc(), exportPlan.fitContentToPageMargins, 10000); - } catch (InterruptedException e) { - e.printStackTrace(); - } catch (DatabaseException e) { - e.printStackTrace(); + ++exportedPages; + } catch (DatabaseException | InterruptedException e) { + LOGGER.error("PDF rendering failed.", e); } - // Paint diagram path/name on the page - // TODO: remove this hard coded diagram name printing and - // replace it with a page templates that is loaded along with - // the rest of the diagram - - int w = (int) pageSize.getWidth(); - int h = (int) pageSize.getHeight(); - - // Write Page Number - PdfContentByte cb = writer.getDirectContent(); - -// PdfTemplate tp = cb.createTemplate(w, h); -// Graphics2D g2d = tp.createGraphics(w, h, mapper); -// g2d.setColor(Color.black); -// java.awt.Font thisFont = new java.awt.Font("Arial", java.awt.Font.ITALIC, 10); -// g2d.setFont(thisFont); -// FontMetrics metrics = g2d.getFontMetrics(); -// int width = metrics.stringWidth(diagramName); -// g2d.drawString(diagramName, (w - width) / 2, document.getPageSize().getHeight() - PageDesc.toPoints(5)); -// g2d.dispose(); -// cb.addTemplate(tp, 0, 0); - /// ATTACHMENTS - Write WIKI /// if ( exportPlan.attachWiki && !d.getDefiningResources().isEmpty() ) { - final Session session = exportPlan.sessionContext.getSession(); + int w = (int) pageSize.getWidth(); + int h = (int) pageSize.getHeight(); + PdfContentByte cb = writer.getDirectContent(); + Session session = exportPlan.sessionContext.getSession(); Resource composite = d.getDefiningResources().iterator().next(); DocumentUtils du = new DocumentUtils(); StringBuilder wiki = new StringBuilder(); StringBuilder css = new StringBuilder(); du.getDocumentWikiTextRecursive(session, composite, wiki, css); - DocumentSettings settings = du.getDocumentSettings(session, composite); + DocumentSettings settings = du.getDocumentSettings(session, composite); PdfTemplate tp_ = cb.createTemplate(w, h); if ( wiki.length()>0 ) { String wikiText = wiki.toString(); String cssText = css.toString(); - du.print(session, composite, wikiText, cssText, settings, tp_.getPdfWriter(), document); + try { + exportedPages += du.print(session, composite, wikiText, cssText, settings, tp_.getPdfWriter(), document); + } catch (DatabaseException | DocumentException e) { + LOGGER.error("Wiki documentation to PDF rendering failed.", e); + } } cb.addTemplate(tp_, 0, 0); } @@ -286,29 +327,27 @@ public class DiagramPrinter { if (progress.isCanceled()) throw new OperationCanceledException(); - System.out.println("GC"); + LOGGER.trace("GC"); SVGCache.getSVGUniverse().clearUnreferenced(); - SessionGarbageCollection.gc(null, sessionContext.getSession(), true, null); + SessionGarbageCollection.gc(null, exportPlan.sessionContext.getSession(), true, null); System.gc(); - System.out.println("GC finished"); + LOGGER.trace("GC finished"); progress.worked(1); } - } catch (DatabaseException e) { - throw new PdfException(e); - } catch (FileNotFoundException e) { - throw new PdfException(e); - } catch (DocumentException e) { - throw new PdfException(e); - } finally { + + return exportedPages; + } catch (DatabaseException | FileNotFoundException | DocumentException | ExceptionConverter e) { + throw new PdfException(e); + } finally { workerThread.stopDispatchingEvents(true); - System.out.println("closing document"); + LOGGER.trace("closing document"); try { - if ( document!=null ) document.close(); - if ( writer!=null ) writer.close(); - } catch(RuntimeException e) { - e.printStackTrace(); + if ( document != null ) document.close(); + if ( writer != null ) writer.close(); + LOGGER.trace("document closed"); + } catch (RuntimeException e) { + LOGGER.error("Error closing PDF document writer", e); } - System.out.println("document closed"); SessionGarbageCollectorJob.getInstance().setEnabled(true).scheduleAfterQuietTime(); } } @@ -341,23 +380,23 @@ public class DiagramPrinter { return ret; } - public static String getCreator() { - String creator = null; - IProduct product = Platform.getProduct(); - if (product != null) { - creator = product.getDescription(); - if (creator == null) { - creator = product.getName(); - } - } - if (creator == null) { - creator = "Simantics"; - } - return creator; - } + public static String getCreator() { + String creator = null; + IProduct product = Platform.getProduct(); + if (product != null) { + creator = product.getDescription(); + if (creator == null) { + creator = product.getName(); + } + } + if (creator == null) { + creator = "Simantics"; + } + return creator; + } static { - Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); + Security.addProvider(new org.bouncycastle.jce.provider.BouncyCastleProvider()); } } \ No newline at end of file