import org.simantics.db.common.request.ResourceRead;
import org.simantics.db.common.request.UniqueRead;
import org.simantics.db.common.request.WriteResultRequest;
-import org.simantics.db.common.utils.Logger;
import org.simantics.db.exception.DatabaseException;
import org.simantics.db.layer0.variable.Variable;
import org.simantics.db.layer0.variable.Variables;
}
}
- public void print(RequestProcessor processor, Resource res, String wiki, String css, DocumentSettings settings, final PdfWriter writer, final Document document) throws DocumentException {
- try {
- Exportable exp = processor.syncRequest(new UniqueRead<Exportable>() {
-
- @Override
- public Exportable perform(ReadGraph graph) throws DatabaseException {
- return new Exportable(graph, res, wiki, css, settings, true);
- }
-
- });
- exp.export(document, writer);
- } catch (DocumentException e) {
- Logger.defaultLogError(e);
- } catch (DatabaseException e) {
- Logger.defaultLogError(e);
- }
+ public int print(RequestProcessor processor, Resource res, String wiki, String css, DocumentSettings settings, final PdfWriter writer, final Document document)
+ throws DocumentException, DatabaseException {
+ Exportable exp = processor.syncRequest(new UniqueRead<Exportable>() {
+ @Override
+ public Exportable perform(ReadGraph graph) throws DatabaseException {
+ return new Exportable(graph, res, wiki, css, settings, true);
+ }
+ });
+ return exp.export(document, writer);
}
public static String indexRootPath(ReadGraph graph, Variable selection) throws DatabaseException {
}
@Override
- public void export(Document document, PdfWriter writer) throws DocumentException {
+ public int export(Document document, PdfWriter writer) throws DocumentException {
File temp = Simantics.getTempfile("wikiPdfExport", "pdf");
try {
temp.getParentFile().mkdirs();
PhantomJSDriver.print(html, settings, temp);
+ int result = 0;
PdfContentByte cb = writer.getDirectContent();
PdfReader reader = new PdfReader(new BufferedInputStream(new FileInputStream(temp)));
for (int i = 1; i <= reader.getNumberOfPages(); i++) {
//add the page to the destination pdf
float pts = Utilities.millimetersToPoints(10);
cb.addTemplate(page, pts, pts);
+ ++result;
}
+ return result;
} catch (IOException e) {
throw new DocumentException(e);
import com.lowagie.text.DocumentException;
import com.lowagie.text.FontFactory;
import com.lowagie.text.Rectangle;
-import com.lowagie.text.pdf.DefaultFontMapper;
import com.lowagie.text.pdf.PdfBoolean;
import com.lowagie.text.pdf.PdfCopy;
import com.lowagie.text.pdf.PdfName;
writer.fos = new FileOutputStream(writer.outputFile);
writer.pdfCopy = new PdfCopy(writer.document, writer.fos);
writer.pdfCopy.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
- writer.fontMapper = new DefaultFontMapper();
+ writer.fontMapper = FontMapping.defaultFontMapper();
writer.options = options;
writer.ctx = ctx;
try {
int n = reader.getNumberOfPages();
- for (int i = 0; i < n; ) {
- Rectangle pageSize = reader.getPageSizeWithRotation(n);
+ for (int i = 1; i <= n; ++i) {
+ Rectangle pageSize = reader.getPageSizeWithRotation(i);
- PdfImportedPage imp = pdfCopy.getImportedPage(reader, ++i);
+ PdfImportedPage imp = pdfCopy.getImportedPage(reader, i);
PdfCopy.PageStamp ps = pdfCopy.createPageStamp(imp);
PdfContentByte over = ps.getOverContent();
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 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
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.export.core.pdf;
+
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import com.lowagie.text.FontFactory;
+import com.lowagie.text.pdf.DefaultFontMapper;
+import com.lowagie.text.pdf.FontMapper;
+
+/**
+ * A utility class for constructing properly initialize iText {@link FontMapper}
+ * instances.
+ *
+ * @author Tuukka Lehtonen
+ * @since 1.28.0
+ */
+public class FontMapping {
+
+ private static final AtomicBoolean fontFactoryInitialized = new AtomicBoolean();
+
+ public static FontMapper defaultFontMapper() {
+ // NOTE: recreation is intentional because users might add fonts between exports.
+ // At some point, perhaps we could listen to file system changes in these locations
+ // and only then recreate the mapper.
+ return createDefaultFontMapper();
+ }
+
+ public static FontMapper createDefaultFontMapper() {
+ initializeFontFactory();
+ DefaultFontMapper mapper = new DefaultFontMapper();
+ insertDirectories(mapper);
+ return mapper;
+ }
+
+ private static void insertDirectories(DefaultFontMapper mapper) {
+ switch (OSType.calculate()) {
+ case APPLE:
+ mapper.insertDirectory("/Library/Fonts");
+ mapper.insertDirectory("/System/Library/Fonts");
+
+ case LINUX:
+ case SUN:
+ mapper.insertDirectory("/usr/share/X11/fonts");
+ mapper.insertDirectory("/usr/X/lib/X11/fonts");
+ mapper.insertDirectory("/usr/openwin/lib/X11/fonts");
+ mapper.insertDirectory("/usr/share/fonts");
+ mapper.insertDirectory("/usr/X11R6/lib/X11/fonts");
+ break;
+
+ case WINDOWS:
+ String windir = System.getenv("WINDIR");
+ if (windir != null && !windir.isEmpty()) {
+ mapper.insertDirectory(windir + "\\Fonts");
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ private static void initializeFontFactory() {
+ if (!fontFactoryInitialized.compareAndSet(false, true))
+ return;
+
+ switch (OSType.calculate()) {
+ case APPLE:
+ FontFactory.registerDirectory("/Library/Fonts");
+ FontFactory.registerDirectory("/System/Library/Fonts");
+
+ case LINUX:
+ case SUN:
+ FontFactory.registerDirectory("/usr/share/X11/fonts", true);
+ FontFactory.registerDirectory("/usr/X/lib/X11/fonts", true);
+ FontFactory.registerDirectory("/usr/openwin/lib/X11/fonts", true);
+ FontFactory.registerDirectory("/usr/share/fonts", true);
+ FontFactory.registerDirectory("/usr/X11R6/lib/X11/fonts", true);
+ break;
+
+ case WINDOWS:
+ String windir = System.getenv("WINDIR");
+ if (windir != null && !windir.isEmpty()) {
+ FontFactory.registerDirectory(windir + "\\Fonts");
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ static enum OSType {
+ APPLE, LINUX, SUN, WINDOWS, UNKNOWN;
+
+ public static OSType calculate() {
+ String osName = System.getProperty("os.name");
+ assert osName != null;
+ osName = osName.toLowerCase();
+ if (osName.startsWith("mac os x"))
+ return APPLE;
+ if (osName.startsWith("windows"))
+ return WINDOWS;
+ if (osName.startsWith("linux"))
+ return LINUX;
+ if (osName.startsWith("sun"))
+ return SUN;
+ return UNKNOWN;
+ }
+ }
+
+}
--- /dev/null
+/*******************************************************************************
+ * Copyright (c) 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
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v10.html
+ *
+ * Contributors:
+ * Semantum Oy - initial API and implementation
+ *******************************************************************************/
+package org.simantics.export.core.pdf;
+
+import java.awt.geom.Point2D;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Files;
+import java.nio.file.Path;
+
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.SubMonitor;
+
+import com.lowagie.text.Document;
+import com.lowagie.text.DocumentException;
+import com.lowagie.text.Element;
+import com.lowagie.text.Font;
+import com.lowagie.text.Phrase;
+import com.lowagie.text.Rectangle;
+import com.lowagie.text.pdf.BadPdfFormatException;
+import com.lowagie.text.pdf.ColumnText;
+import com.lowagie.text.pdf.PdfContentByte;
+import com.lowagie.text.pdf.PdfCopy;
+import com.lowagie.text.pdf.PdfImportedPage;
+import com.lowagie.text.pdf.PdfReader;
+import com.lowagie.text.pdf.PdfWriter;
+
+/**
+ * PDF page numbering related post-processing utilities using iText.
+ *
+ * @author Tuukka Lehtonen
+ * @since 1.28.0
+ */
+public class PageNumbering {
+
+ public static enum NumberingFormat {
+ PAGE_SLASH_TOTAL_PAGES
+ }
+
+ public static enum Position {
+ BOTTOM_LEFT,
+ BOTTOM_RIGHT,
+ TOP_LEFT,
+ TOP_RIGHT,
+ }
+
+ private static int pageNumberAlignment(Position positioning) {
+ switch (positioning) {
+ case BOTTOM_LEFT:
+ case TOP_LEFT: return Element.ALIGN_LEFT;
+
+ case BOTTOM_RIGHT:
+ case TOP_RIGHT:
+ default: return Element.ALIGN_RIGHT;
+ }
+ }
+
+ private static Point2D.Float pageNumberPosition(Position positioning, Rectangle pageSize, Font font) {
+ switch (positioning) {
+ case TOP_LEFT:
+ return new Point2D.Float(12, pageSize.getHeight() - 12 - font.getCalculatedSize()*0.8f);
+ case TOP_RIGHT:
+ return new Point2D.Float(pageSize.getWidth() - 12, pageSize.getHeight() - 12 - font.getCalculatedSize()*0.8f);
+ case BOTTOM_LEFT:
+ return new Point2D.Float(12, 12);
+ case BOTTOM_RIGHT:
+ default:
+ return new Point2D.Float(pageSize.getWidth() - 12, 12);
+ }
+ }
+
+ public static String formatPageNumber(NumberingFormat format, int pageNumber, int totalPages) {
+ switch (format) {
+ case PAGE_SLASH_TOTAL_PAGES: return String.format("%d / %d", pageNumber, totalPages);
+ default:
+ throw new UnsupportedOperationException("Unsupported numbering format: " + format);
+ }
+ }
+
+ public static void addPageNumber(
+ PdfCopy pdfCopy,
+ PdfReader sourceReader,
+ int sourcePageNumber,
+ int currentPageNumber,
+ int totalPages,
+ Font font,
+ Position positioning,
+ NumberingFormat format)
+ throws IOException, BadPdfFormatException
+ {
+ Rectangle pageSize = sourceReader.getPageSizeWithRotation(sourcePageNumber);
+ PdfImportedPage imp = pdfCopy.getImportedPage(sourceReader, sourcePageNumber);
+ PdfCopy.PageStamp ps = pdfCopy.createPageStamp(imp);
+ PdfContentByte over = ps.getOverContent();
+ String text = formatPageNumber(format, currentPageNumber, totalPages);
+ Point2D.Float pos = pageNumberPosition(positioning, pageSize, font);
+ int alignment = pageNumberAlignment(positioning);
+ ColumnText.showTextAligned(over, alignment, new Phrase(text, font), pos.x, pos.y, 0);
+ ps.alterContents();
+ pdfCopy.addPage(imp);
+ }
+
+ public static void addPageNumbers(
+ IProgressMonitor monitor,
+ Path inputFile,
+ Path outputFile,
+ Position positioning,
+ NumberingFormat format,
+ Font pageNumberFont)
+ throws IOException, DocumentException
+ {
+ PdfReader reader = null;
+ try {
+ reader = new PdfReader(inputFile.toString());
+ int totalPages = reader.getNumberOfPages();
+ int currentPage = 1;
+
+ SubMonitor mon = SubMonitor.convert(monitor, totalPages);
+
+ try (OutputStream fos = Files.newOutputStream(outputFile)) {
+ Document document = new Document();
+ PdfCopy pdfCopy = new PdfCopy(document, fos);
+ pdfCopy.setPdfVersion(PdfWriter.PDF_VERSION_1_7);
+ document.open();
+ try {
+ for (int i = 1; i <= totalPages; ++i) {
+ mon.subTask(i + "/" + totalPages);
+ PageNumbering.addPageNumber(pdfCopy, reader, i,
+ currentPage++, totalPages,
+ pageNumberFont,
+ positioning,
+ format);
+ }
+ } finally {
+ if (document != null && document.isOpen())
+ document.close();
+ if (pdfCopy != null)
+ pdfCopy.close();
+ }
+ }
+ } finally {
+ if (reader != null)
+ reader.close();
+ }
+
+ }
+
+ public static void addPageNumbers(
+ IProgressMonitor monitor,
+ Path inputFile,
+ Path outputFile,
+ Position positioning,
+ NumberingFormat format)
+ throws IOException, DocumentException
+ {
+ addPageNumbers(monitor, inputFile, outputFile, positioning, format, new Font(Font.HELVETICA, 8));
+ }
+
+}
\ No newline at end of file
/*******************************************************************************
- * 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
*
* 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;
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;
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
* @throws FileNotFoundException
*/
public static void printToPdf(
- IProgressMonitor monitor,
- PDFExportPlan exportPlan,
- String exportPath,
- Collection<Node> flattenedNodes,
- ISessionContext sessionContext)
- throws PdfException {
- Collection<Node> flattened = flattenedNodes;
+ IProgressMonitor monitor,
+ PDFExportPlan exportPlan,
+ String exportPath,
+ Collection<Node> 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 <code>null</code>, 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<Node> 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);
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<String> 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<String> 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<SimanticsClipboard>() {
- @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<Representation> 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<SimanticsClipboard>() {
+ @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<Representation> 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();
}
*/
//////////////////////////
-
+
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);
}
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();
}
}
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
@Override
public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException {
try {
- // Print pdf
- DiagramPrinter.printToPdf(monitor, exportPlan, exportPlan.exportLocation.toString(), exportPlan.selectedNodes, exportPlan.sessionContext);
-
+ DiagramPrinter.printToPdf(monitor, exportPlan, exportPlan.exportLocation.toString(), exportPlan.selectedNodes);
} catch (PdfException e) {
throw new InvocationTargetException(e);
} finally {
/*******************************************************************************
- * 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
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
+ * Semantum Oy - (#7084) page numbering
*******************************************************************************/
package org.simantics.modeling.ui.pdf;
import org.simantics.db.common.NamedResource;
import org.simantics.db.management.ISessionContext;
+import org.simantics.export.core.pdf.PageNumbering;
import org.simantics.modeling.requests.CollectionResult;
import org.simantics.modeling.requests.Node;
import org.simantics.project.IProject;
* <code>true</code> to attach Wiki page.
*/
public boolean attachWiki = false;
-
-
+
+ /**
+ * Whether or not to add page numbers to the exported PDF. Default value is
+ * {@value #addPageNumbers}.
+ *
+ * @since 1.28.0
+ */
+ public boolean addPageNumbers = true;
+
+ /**
+ * This is ignored if {@link #addPageNumbers} is <code>false</code>.
+ */
+ public PageNumbering.Position pageNumberPosition = PageNumbering.Position.BOTTOM_RIGHT;
+
+ /**
+ * This is ignored if {@link #addPageNumbers} is <code>false</code>.
+ */
+ public PageNumbering.NumberingFormat pageNumberFormat = PageNumbering.NumberingFormat.PAGE_SLASH_TOTAL_PAGES;
+
+
public PDFExportPlan(ISessionContext sessionContext, Collection<String> recentLocations) {
this.sessionContext = sessionContext;
this.recentLocations = recentLocations;
/*******************************************************************************
- * 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
*
* Contributors:
* VTT Technical Research Centre of Finland - initial API and implementation
+ * Semantum Oy - (#7084) refactoring
*******************************************************************************/
package org.simantics.modeling.ui.pdf;
import java.util.concurrent.Semaphore;
-import java.util.concurrent.atomic.AtomicReference;
import org.simantics.db.ReadGraph;
import org.simantics.db.Resource;
+import org.simantics.db.Session;
import org.simantics.db.common.request.PossibleIndexRoot;
import org.simantics.db.common.request.UniqueRead;
import org.simantics.db.common.utils.NameUtils;
import org.simantics.db.exception.ValidationException;
import org.simantics.db.layer0.variable.Variable;
import org.simantics.db.layer0.variable.Variables;
-import org.simantics.db.management.ISessionContext;
+import org.simantics.db.request.Read;
import org.simantics.diagram.elements.DiagramNodeUtil;
import org.simantics.diagram.stubs.DiagramResource;
import org.simantics.g2d.canvas.Hints;
import org.simantics.g2d.scenegraph.ICanvasSceneGraphProvider;
import org.simantics.modeling.requests.Node;
import org.simantics.structural.stubs.StructuralResource2;
-import org.simantics.utils.DataContainer;
import org.simantics.utils.datastructures.Pair;
import org.simantics.utils.page.PageDesc;
import org.simantics.utils.threads.IThreadWorkQueue;
*/
public class PDFPainter {
- public static boolean render(
+ public static void render(
final IThreadWorkQueue thread,
- final ISessionContext sessionContext,
PDFExportPlan exportModel,
final Node node,
final PdfWriter writer,
final PageDesc pageDesc,
final boolean fitDiagramContentsToPageMargins,
long timeout)
- throws InterruptedException, DatabaseException
+ throws InterruptedException, DatabaseException
{
- final DataContainer<Boolean> result = new DataContainer<Boolean>(false);
- final DataContainer<DatabaseException> exception = new DataContainer<DatabaseException>();
+ DatabaseException[] exception = { null };
+ ICanvasSceneGraphProvider[] sgProvider = { null };
- final CanvasContext ctx = new CanvasContext(thread);
- final AtomicReference<ICanvasSceneGraphProvider> sgProvider = new AtomicReference<ICanvasSceneGraphProvider>();
+ CanvasContext ctx = new CanvasContext(thread);
try {
final Semaphore done = new Semaphore(0);
// IMPORTANT: Load diagram in a different thread than the canvas context thread!
- ThreadUtils.getBlockingWorkExecutor().execute(new Runnable() {
- @Override
- public void run() {
- try {
- Pair<Resource, String> modelAndRVI = sessionContext.getSession().syncRequest(new UniqueRead<Pair<Resource, String>>() {
- @Override
- public Pair<Resource, String> perform(ReadGraph graph) throws DatabaseException {
- return new Pair<Resource, String>( resolveModel(graph, node), resolveRVI(graph, node) );
- }
- });
-
- final Boolean isSymbol = sessionContext.getSession().syncRequest(new UniqueRead<Boolean>() {
- @Override
- public Boolean perform(ReadGraph graph) throws DatabaseException {
- StructuralResource2 STR = StructuralResource2.getInstance(graph);
- DiagramResource DIA = DiagramResource.getInstance(graph);
- Resource possibleSymbol = graph.getPossibleObject(node.getDiagramResource(), STR.Defines);
- return possibleSymbol != null && graph.isInstanceOf(possibleSymbol, DIA.ElementClass);
- }
- });
-
- ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(ctx, modelAndRVI.first, node.getDiagramResource(), modelAndRVI.second, 5000);
- sgProvider.set( provider );
- ctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, pageDesc);
-
-// StringBuilder b = new StringBuilder();
-// NodeUtil.printTreeNodes(ctx.getCanvasNode(), b);
-// System.err.println(b.toString());
-
- ThreadUtils.asyncExec(thread, new Runnable() {
- @Override
- public void run() {
- try {
- PDFBuilder chassis = new PDFBuilder(writer, mapper, pageSize, pageDesc, fitDiagramContentsToPageMargins || isSymbol);
-
- chassis.paint(ctx, true);
- } finally {
- done.release();
- }
- }
- });
- } catch (DatabaseException e) {
- done.release();
- exception.set(e);
- } catch (Throwable e) {
- done.release();
- exception.set(new DatabaseException(e));
- } finally {
- done.release();
- }
+ ThreadUtils.getBlockingWorkExecutor().execute(() -> {
+ try {
+ Session s = exportModel.sessionContext.getSession();
+
+ Pair<Resource, String> modelAndRVI = s.syncRequest( modelAndRVI(node) );
+ Boolean isSymbol = s.syncRequest( isSymbol(node) );
+
+ ICanvasSceneGraphProvider provider = DiagramNodeUtil.loadSceneGraphProvider(
+ ctx,
+ modelAndRVI.first,
+ node.getDiagramResource(),
+ modelAndRVI.second,
+ 5000);
+ sgProvider[0] = provider;
+ ctx.getDefaultHintContext().setHint(Hints.KEY_PAGE_DESC, pageDesc);
+
+// System.err.println(NodeUtil.printTreeNodes(ctx.getCanvasNode(), new StringBuilder()).toString());
+
+ ThreadUtils.asyncExec(thread, () -> {
+ try {
+ PDFBuilder chassis = new PDFBuilder(writer, mapper, pageSize, pageDesc, fitDiagramContentsToPageMargins || isSymbol);
+ chassis.paint(ctx, true);
+ } catch (Throwable e) {
+ exception[0] = new DatabaseException(e);
+ } finally {
+ done.release();
+ }
+ });
+ } catch (DatabaseException e) {
+ done.release();
+ exception[0] = e;
+ } catch (Throwable e) {
+ done.release();
+ exception[0] = new DatabaseException(e);
+ } finally {
+ done.release();
}
});
done.acquire(2);
- if (exception.get() != null)
- throw exception.get();
- return result.get();
+ if (exception[0] != null)
+ throw exception[0];
} finally {
- if (sgProvider.get() != null)
- sgProvider.get().dispose();
+ if (sgProvider[0] != null)
+ sgProvider[0].dispose();
ctx.dispose();
}
}
+ private static Read<Pair<Resource, String>> modelAndRVI(Node node) {
+ return new UniqueRead<Pair<Resource, String>>() {
+ @Override
+ public Pair<Resource, String> perform(ReadGraph graph) throws DatabaseException {
+ return Pair.make( resolveModel(graph, node), resolveRVI(graph, node) );
+ }
+ };
+ }
+
+ private static Read<Boolean> isSymbol(Node node) {
+ return new UniqueRead<Boolean>() {
+ @Override
+ public Boolean perform(ReadGraph graph) throws DatabaseException {
+ StructuralResource2 STR = StructuralResource2.getInstance(graph);
+ DiagramResource DIA = DiagramResource.getInstance(graph);
+ Resource possibleSymbol = graph.getPossibleObject(node.getDiagramResource(), STR.Defines);
+ return possibleSymbol != null && graph.isInstanceOf(possibleSymbol, DIA.ElementClass);
+ }
+ };
+ }
+
private static Resource resolveModel(ReadGraph graph, Node node) throws DatabaseException {
Resource composite = node.getDefiningResources().head();
Resource model = graph.syncRequest(new PossibleIndexRoot(composite));
-// Resource model = StructuralVariables.getModel(graph, composite);
if (model == null)
throw new ValidationException("no model found for composite " + NameUtils.getSafeName(graph, composite));
return model;
}
-// private static String resolveModelURI(ReadGraph graph, final Node node) throws DatabaseException {
-// return graph.getURI(resolveModel(graph, node));
-// }
-
private static String resolveRVI(ReadGraph graph, final Node node) throws DatabaseException {
- String RVI = node.getRVI();
- if(RVI != null) return RVI;
+ String RVI = node.getRVI();
+ if (RVI != null) return RVI;
Resource composite = node.getDefiningResources().head();
Variable var = Variables.getVariable(graph, composite);
org.simantics.db.layer0.variable.RVI rvi = var.getPossibleRVI(graph);
- if(rvi == null) return null;
- return rvi.toString();
-// final ResourceArray compositePath = StructuralVariables.getCompositeArray(graph, composite);
-// final ResourceArray variablePath = compositePath.removeFromBeginning(1);
-// return StructuralVariables.getRVI(graph, variablePath);
+ return rvi != null ? rvi.toString() : null;
}
-}
+}
\ No newline at end of file
return result;
}
- public static final void printTreeNodes(INode node, StringBuilder builder) {
+ public static final StringBuilder printTreeNodes(INode node, StringBuilder builder) {
printTreeNodes(node, 0, builder);
+ return builder;
}
- public static final void printTreeNodes(INode node, int indent, StringBuilder builder) {
+ public static final StringBuilder printTreeNodes(INode node, int indent, StringBuilder builder) {
for (int i = 0; i < indent; i++)
builder.append(" ");
builder.append(node.toString() + "\n");
printTreeNodes(n, indent+2, builder);
}
}
+ return builder;
}
public static final <T extends INode> Set<T> collectNodes(INode node, Class<T> clazz) {
import com.lowagie.text.pdf.PdfWriter;
public interface IExportable {
- public void export(Document doc, PdfWriter writer) throws DocumentException;
+ /**
+ * @param doc
+ * @param writer
+ * @return the amount of PDF pages exported
+ * @throws DocumentException
+ */
+ public int export(Document doc, PdfWriter writer) throws DocumentException;
}