From 3679f37f129b16daadb490d6987fdd038b096bfc Mon Sep 17 00:00:00 2001 From: Jakob Heher Date: Mon, 8 Aug 2022 13:32:30 +0200 Subject: cached asynchronous pdf-as placeholders --- .../pdfover/gui/composites/SignaturePanel.java | 2 + .../SimpleConfigurationComposite.java | 73 ++++++++++------------ .../gui/workflow/states/PositioningState.java | 7 ++- .../signer/pdfas/PdfAs4SignatureParameter.java | 2 +- .../signer/pdfas/PdfAs4SignaturePlaceholder.java | 70 +++++++++++++++++++++ 5 files changed, 112 insertions(+), 42 deletions(-) create mode 100644 pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SignaturePlaceholder.java diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/SignaturePanel.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/SignaturePanel.java index 879a3e98..02b1e21e 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/SignaturePanel.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/SignaturePanel.java @@ -156,6 +156,8 @@ public class SignaturePanel extends JPanel { this.sigPageWidth = placeholder.getWidth(null) / 4; this.sigPageHeight = placeholder.getHeight(null) / 4; this.sigPlaceholderTransparency = transparency; + renderPageToImage(); + repaint(); } /** diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/SimpleConfigurationComposite.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/SimpleConfigurationComposite.java index 28baa158..6a074187 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/SimpleConfigurationComposite.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/composites/configuration/SimpleConfigurationComposite.java @@ -15,7 +15,6 @@ */ package at.asit.pdfover.gui.composites.configuration; -import java.awt.image.BufferedImage; // Imports import java.io.File; import java.util.Arrays; @@ -34,7 +33,6 @@ import org.eclipse.swt.events.PaintEvent; import org.eclipse.swt.events.SelectionAdapter; import org.eclipse.swt.events.SelectionEvent; import org.eclipse.swt.graphics.Image; -import org.eclipse.swt.graphics.ImageData; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.graphics.Rectangle; import org.eclipse.swt.layout.FormLayout; @@ -58,13 +56,13 @@ import at.asit.pdfover.gui.controls.Dialog.BUTTONS; import at.asit.pdfover.gui.controls.ErrorDialog; import at.asit.pdfover.gui.controls.ErrorMarker; import at.asit.pdfover.gui.exceptions.InvalidEmblemFile; -import at.asit.pdfover.gui.utils.ImageConverter; import at.asit.pdfover.gui.utils.SWTUtils; -import at.asit.pdfover.gui.workflow.config.ConfigurationManager; import at.asit.pdfover.gui.workflow.config.ConfigurationDataInMemory; +import at.asit.pdfover.gui.workflow.config.ConfigurationManager; import at.asit.pdfover.gui.workflow.states.State; import at.asit.pdfover.signator.Emblem; import at.asit.pdfover.signer.pdfas.PdfAs4SignatureParameter; +import at.asit.pdfover.signer.pdfas.PdfAs4SignaturePlaceholder; /** * @@ -338,41 +336,9 @@ public class SimpleConfigurationComposite extends ConfigurationCompositeBase { reloadResources(); } - boolean needSigPreviewUpdate = true; + private PdfAs4SignatureParameter sigPreviewParam = null; private Image sigPreview = null; void paintSignaturePreview(PaintEvent evt) { - if (needSigPreviewUpdate) - { - String image = this.configurationContainer.getEmblemPath(); - ImageData img = null; - - try { - PdfAs4SignatureParameter param = new PdfAs4SignatureParameter(); - param.signatureProfile = this.configurationContainer.getSignatureProfile(); - if(this.configurationContainer.signatureNote != null && !this.configurationContainer.signatureNote.isEmpty()) { - param.signatureNote = this.configurationContainer.signatureNote; - } - - param.signatureLanguage = this.configurationContainer.signatureLocale.getLanguage(); - param.enablePDFACompat = this.configurationContainer.signaturePDFACompat; - if (image != null && !image.trim().isEmpty()) { - param.emblem = new Emblem(image); - } - - // TODO getPlaceholder is super slow, can we async this somehow? - img = ImageConverter.convertToSWT((BufferedImage) param.getPlaceholder()); - } catch (Exception e) { - log.error("Failed to load image for display...", e); - } - - if (img != null) { - this.sigPreview = new Image(this.getDisplay(), img); - } else { - this.sigPreview = null; - } - needSigPreviewUpdate = false; - } - if (this.sigPreview == null) return; Rectangle r = this.sigPreview.getBounds(); @@ -443,8 +409,37 @@ public class SimpleConfigurationComposite extends ConfigurationCompositeBase { } void signatureBlockPreviewChanged() { - needSigPreviewUpdate = true; - this.cSigPreview.redraw(); + try { + PdfAs4SignatureParameter param = new PdfAs4SignatureParameter(); + param.signatureProfile = this.configurationContainer.getSignatureProfile(); + if(this.configurationContainer.signatureNote != null && !this.configurationContainer.signatureNote.isEmpty()) { + param.signatureNote = this.configurationContainer.signatureNote; + } + + param.signatureLanguage = this.configurationContainer.signatureLocale.getLanguage(); + param.enablePDFACompat = this.configurationContainer.signaturePDFACompat; + String image = this.configurationContainer.getEmblemPath(); + if (image != null && !image.trim().isEmpty()) { + param.emblem = new Emblem(image); + } + + this.sigPreviewParam = param; + PdfAs4SignaturePlaceholder.For(param, (p) -> { + if (this.isDisposed()) + return; + + this.getDisplay().syncExec(() -> { + if (this.sigPreviewParam != param) + return; + if (this.sigPreview != null) + this.sigPreview.dispose(); + this.sigPreview = new Image(this.getDisplay(), p.getSWTImage()); + this.cSigPreview.redraw(); + }); + }); + } catch (Exception e) { + log.error("Failed to load image for display...", e); + } } void processEmblemChanged(String filename) { diff --git a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/PositioningState.java b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/PositioningState.java index f814bd85..1a4767dd 100644 --- a/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/PositioningState.java +++ b/pdf-over-gui/src/main/java/at/asit/pdfover/gui/workflow/states/PositioningState.java @@ -37,6 +37,7 @@ import at.asit.pdfover.gui.workflow.config.ConfigurationManager; import at.asit.pdfover.signator.Emblem; import at.asit.pdfover.signator.SignaturePosition; import at.asit.pdfover.signer.pdfas.PdfAs4SignatureParameter; +import at.asit.pdfover.signer.pdfas.PdfAs4SignaturePlaceholder; /** * Decides where to position the signature block @@ -117,9 +118,11 @@ public class PositioningState extends State { param.signatureLanguage = config.getSignatureLocale().getLanguage(); param.enablePDFACompat = config.getSignaturePdfACompat(); - this.positionComposite.setPlaceholder( - param.getPlaceholder(), + PdfAs4SignaturePlaceholder.For(param, (p) -> { + this.positionComposite.setPlaceholder( + p.getAWTImage(), config.getPlaceholderTransparency()); + }); if (this.previousPosition != null && !this.previousPosition.useAutoPositioning()) { diff --git a/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SignatureParameter.java b/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SignatureParameter.java index 4356f1e0..78dda185 100644 --- a/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SignatureParameter.java +++ b/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SignatureParameter.java @@ -83,7 +83,7 @@ public class PdfAs4SignatureParameter { /** The signature profile in use */ public Profile signatureProfile = Profile.getDefaultProfile(); - public Image getPlaceholder() { + Image getPlaceholder() { String sigProfile = getPdfAsSignatureProfileId(); String sigEmblem = (this.emblem == null ? null : this.emblem.getCachedFileName()); diff --git a/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SignaturePlaceholder.java b/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SignaturePlaceholder.java new file mode 100644 index 00000000..b944bf24 --- /dev/null +++ b/pdf-over-signer/src/main/java/at/asit/pdfover/signer/pdfas/PdfAs4SignaturePlaceholder.java @@ -0,0 +1,70 @@ +package at.asit.pdfover.signer.pdfas; + +import java.util.ArrayList; +import java.util.Comparator; +import java.util.TreeMap; +import java.util.function.Consumer; + +import at.asit.pdfover.commons.utils.ImageUtil; + +/** + * caches placeholders for signature parameters (placeholder generation is pretty slow) + */ +public final class PdfAs4SignaturePlaceholder implements Runnable { + private static TreeMap cache = new TreeMap<>( + Comparator + .comparing(PdfAs4SignatureParameter::getPdfAsSignatureProfileId) + .thenComparing((p) -> { return (p.emblem != null) ? p.emblem.getOriginalFileHash() : ""; }) + .thenComparing((p) -> { return p.signatureNote; }, Comparator.nullsFirst(String::compareTo)) + ); + + /** + * request a placeholder for the specified parameter asynchronously + * @param callback the callback to be invoked on completion (may also be invoked before this function returns!) + */ + public static void For(PdfAs4SignatureParameter param, Consumer callback) { + synchronized(cache) { + cache.computeIfAbsent(param, (p) -> new PdfAs4SignaturePlaceholder(p)).AddCallback(callback); + } + } + + private final PdfAs4SignatureParameter param; + private PdfAs4SignaturePlaceholder(PdfAs4SignatureParameter param) { + this.param = param; + new Thread(this).start(); + } + + private java.awt.image.BufferedImage awtImageData; + /** AWT image data for the placeholder */ + public java.awt.image.BufferedImage getAWTImage() { return this.awtImageData; } + private org.eclipse.swt.graphics.ImageData swtImageData; + /** SWT image data for the placeholder */ + public org.eclipse.swt.graphics.ImageData getSWTImage() { return this.swtImageData; } + + private ArrayList> callbacks = new ArrayList<>(); + private void AddCallback(Consumer c) { + synchronized (this) { + if (this.callbacks != null) + { + this.callbacks.add(c); + return; + } /* else... */ + } + /* ... else, not synchronized */ + c.accept(this); + } + + + @Override + public void run() { + this.awtImageData = (java.awt.image.BufferedImage) this.param.getPlaceholder(); + this.swtImageData = ImageUtil.convertToSWT(this.awtImageData); + ArrayList> _callbacks; + synchronized (this) { + _callbacks = this.callbacks; + this.callbacks = null; + } + _callbacks.forEach((c) -> c.accept(this)); + } + +} -- cgit v1.2.3