From ff94744715ae55cd71b227f00f9e833520d60eb9 Mon Sep 17 00:00:00 2001 From: Emmeran Seehuber Date: Fri, 16 Oct 2020 10:52:52 +0200 Subject: [PATCH] #472 Refactor functionality of MergeBackgroundPdfDrawer into a base class, and add ForegroundPdfDrawer which always puts the PDF in front of the page. --- .../freemarker/featuredocumentation.ftl | 10 +- .../main/resources/freemarker/watermark.pdf | Bin 0 -> 22577 bytes .../objects/StandardObjectDrawerFactory.java | 2 + .../objects/pdf/ForegroundPdfDrawer.java | 67 +++++++++ .../objects/pdf/MergeBackgroundPdfDrawer.java | 141 ++++++------------ .../objects/pdf/PdfDrawerBase.java | 99 ++++++++++++ 6 files changed, 220 insertions(+), 99 deletions(-) create mode 100644 openhtmltopdf-examples/src/main/resources/freemarker/watermark.pdf create mode 100644 openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/ForegroundPdfDrawer.java create mode 100644 openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/PdfDrawerBase.java diff --git a/openhtmltopdf-examples/src/main/resources/freemarker/featuredocumentation.ftl b/openhtmltopdf-examples/src/main/resources/freemarker/featuredocumentation.ftl index f258ed70b..62d8cd71e 100644 --- a/openhtmltopdf-examples/src/main/resources/freemarker/featuredocumentation.ftl +++ b/openhtmltopdf-examples/src/main/resources/freemarker/featuredocumentation.ftl @@ -288,6 +288,14 @@ lower corner.
  • pdfpage: Page to import from the PDF file.
  • +If you want to have this watermark in the foreground you should use +[@htmlCode] + +[/@htmlCode] + + +To have this placed on every page, you should put the object into the header of the page. + [@h3]JFreeGraph[/@h3] For simple charts you can use the builtin objects for JFreeGraph. Note: You must specify the dependency to JFreeMarker @@ -341,4 +349,4 @@ Note: This only works in Acrobat Reader, all other PDF Viewer ignore this featur - \ No newline at end of file + diff --git a/openhtmltopdf-examples/src/main/resources/freemarker/watermark.pdf b/openhtmltopdf-examples/src/main/resources/freemarker/watermark.pdf new file mode 100644 index 0000000000000000000000000000000000000000..d867731dad82c04ee8177da750723a62f78422d3 GIT binary patch literal 22577 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 literal 0 HcmV?d00001 diff --git a/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/StandardObjectDrawerFactory.java b/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/StandardObjectDrawerFactory.java index b14c5af4a..21bbc0b7f 100644 --- a/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/StandardObjectDrawerFactory.java +++ b/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/StandardObjectDrawerFactory.java @@ -3,6 +3,7 @@ import com.openhtmltopdf.objects.jfreechart.JFreeChartBarDiagramObjectDrawer; import com.openhtmltopdf.objects.jfreechart.JFreeChartPieDiagramObjectDrawer; import com.openhtmltopdf.objects.pdf.MergeBackgroundPdfDrawer; +import com.openhtmltopdf.objects.pdf.ForegroundPdfDrawer; import com.openhtmltopdf.render.DefaultObjectDrawerFactory; /** @@ -14,6 +15,7 @@ public static void registerStandardObjects(DefaultObjectDrawerFactory factory) { factory.registerDrawer("jfreechart/pie", new JFreeChartPieDiagramObjectDrawer()); factory.registerDrawer("jfreechart/bar", new JFreeChartBarDiagramObjectDrawer()); factory.registerDrawer("pdf/background",new MergeBackgroundPdfDrawer()); + factory.registerDrawer("pdf/foreground", new ForegroundPdfDrawer()); } public StandardObjectDrawerFactory() { diff --git a/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/ForegroundPdfDrawer.java b/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/ForegroundPdfDrawer.java new file mode 100644 index 000000000..5da1cb53d --- /dev/null +++ b/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/ForegroundPdfDrawer.java @@ -0,0 +1,67 @@ +package com.openhtmltopdf.objects.pdf; + +import com.openhtmltopdf.extend.OutputDevice; +import com.openhtmltopdf.pdfboxout.PdfBoxOutputDevice; +import com.openhtmltopdf.render.RenderingContext; +import org.apache.pdfbox.cos.COSArray; +import org.apache.pdfbox.cos.COSName; +import org.apache.pdfbox.cos.COSStream; +import org.apache.pdfbox.multipdf.LayerUtility; +import org.apache.pdfbox.pdmodel.PDPage; +import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; +import org.apache.pdfbox.util.Charsets; +import org.w3c.dom.Element; + +import java.awt.*; +import java.io.IOException; +import java.io.OutputStream; +import java.util.Map; + +public class ForegroundPdfDrawer extends PdfDrawerBase +{ + @Override + public Map drawObject(Element e, double x, double y, double width, double height, + OutputDevice outputDevice, RenderingContext ctx, int dotsPerPixel) + { + + /* + * We can only do something if this is a PDF. + */ + if (!(outputDevice instanceof PdfBoxOutputDevice)) + return null; + + PdfBoxOutputDevice pdfBoxOutputDevice = (PdfBoxOutputDevice) outputDevice; + + try + { + LayerUtility layerUtility = new LayerUtility(pdfBoxOutputDevice.getWriter()); + PDFormXObject pdFormXObject = importPageAsXForm(ctx, e, pdfBoxOutputDevice, + layerUtility); + PDPage page = pdfBoxOutputDevice.getPage(); + + /* + * This ensures that the Contents of the page is a COSArray. The first entry in + * the array is just a save state (e.g. 'q'), the last one is just a restore 'Q'. + * We can override that to add the XForm. + */ + layerUtility.wrapInSaveRestore(page); + COSArray cosArray = (COSArray) page.getCOSObject() + .getDictionaryObject(COSName.CONTENTS); + + COSStream restoreStateAndPlaceWatermark = (COSStream) cosArray.get(cosArray.size() - 1); + OutputStream watermarkOutputStream = restoreStateAndPlaceWatermark.createOutputStream(); + watermarkOutputStream.write("Q\nq\n".getBytes(Charsets.US_ASCII)); + COSName name = page.getResources().add(pdFormXObject); + name.writePDF(watermarkOutputStream); + watermarkOutputStream.write(' '); + watermarkOutputStream.write("Do\n".getBytes(Charsets.US_ASCII)); + watermarkOutputStream.write("Q\n".getBytes(Charsets.US_ASCII)); + watermarkOutputStream.close(); + } + catch (IOException e1) + { + e1.printStackTrace(); + } + return null; + } +} diff --git a/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/MergeBackgroundPdfDrawer.java b/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/MergeBackgroundPdfDrawer.java index 024bb995f..d68d0f13e 100644 --- a/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/MergeBackgroundPdfDrawer.java +++ b/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/MergeBackgroundPdfDrawer.java @@ -2,126 +2,71 @@ import java.awt.*; import java.io.IOException; -import java.io.InputStream; import java.io.OutputStream; -import java.lang.ref.SoftReference; -import java.lang.ref.WeakReference; -import java.net.MalformedURLException; -import java.net.URL; -import java.util.HashMap; import java.util.Map; import org.apache.pdfbox.cos.COSArray; import org.apache.pdfbox.cos.COSName; import org.apache.pdfbox.cos.COSStream; -import org.apache.pdfbox.io.RandomAccessBuffer; import org.apache.pdfbox.multipdf.LayerUtility; -import org.apache.pdfbox.pdfparser.PDFParser; import org.apache.pdfbox.pdmodel.PDPage; import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; import org.apache.pdfbox.util.Charsets; import org.w3c.dom.Element; -import com.openhtmltopdf.extend.FSObjectDrawer; import com.openhtmltopdf.extend.OutputDevice; import com.openhtmltopdf.pdfboxout.PdfBoxOutputDevice; import com.openhtmltopdf.render.RenderingContext; -public class MergeBackgroundPdfDrawer implements FSObjectDrawer { - private final Map>> formMap = new HashMap>>(); +public class MergeBackgroundPdfDrawer extends PdfDrawerBase +{ - @Override - public Map drawObject(Element e, double x, double y, double width, double height, - OutputDevice outputDevice, RenderingContext ctx, int dotsPerPixel) { + @Override + public Map drawObject(Element e, double x, double y, double width, double height, + OutputDevice outputDevice, RenderingContext ctx, int dotsPerPixel) + { - /* - * We can only do something if this is a PDF. - */ - if (!(outputDevice instanceof PdfBoxOutputDevice)) - return null; + /* + * We can only do something if this is a PDF. + */ + if (!(outputDevice instanceof PdfBoxOutputDevice)) + return null; - String pdfsrc = e.getAttribute("pdfsrc"); - String pdfpageValue = e.getAttribute("pdfpage"); - if (pdfpageValue == null || pdfpageValue.isEmpty()) - pdfpageValue = "1"; - int pdfpage = Integer.parseInt(pdfpageValue); + PdfBoxOutputDevice pdfBoxOutputDevice = (PdfBoxOutputDevice) outputDevice; - PdfBoxOutputDevice pdfBoxOutputDevice = (PdfBoxOutputDevice) outputDevice; - String url = ctx.getUac().resolveURI(pdfsrc); - SoftReference> mapWeakReference = formMap - .get(new PDFBoxDeviceReference(pdfBoxOutputDevice)); - Map map = null; - if (mapWeakReference != null) - map = mapWeakReference.get(); - if (map == null) { - map = new HashMap(); - formMap.put(new PDFBoxDeviceReference(pdfBoxOutputDevice), - new SoftReference>(map)); - } - try { - PDFormXObject pdFormXObject = map.get(url); - LayerUtility layerUtility = new LayerUtility(pdfBoxOutputDevice.getWriter()); - if (pdFormXObject == null) { - InputStream inputStream = new URL(url).openStream(); - try { - PDFParser pdfParser = new PDFParser(new RandomAccessBuffer(inputStream)); - pdfParser.parse(); - pdFormXObject = layerUtility.importPageAsForm(pdfParser.getPDDocument(), pdfpage - 1); - pdfParser.getPDDocument().close(); - } finally { - inputStream.close(); - } - map.put(url, pdFormXObject); - } - PDPage page = pdfBoxOutputDevice.getPage(); + try + { + LayerUtility layerUtility = new LayerUtility(pdfBoxOutputDevice.getWriter()); + PDFormXObject pdFormXObject = importPageAsXForm(ctx,e, pdfBoxOutputDevice, layerUtility); + PDPage page = pdfBoxOutputDevice.getPage(); - /* - * This ensures that the Contents of the page is a COSArray. The first entry in - * the array is just a save state (e.g. 'q'). We can override it to add the - * XForm. - */ - layerUtility.wrapInSaveRestore(page); - COSArray cosArray = (COSArray) page.getCOSObject().getDictionaryObject(COSName.CONTENTS); - COSStream saveStateAndPlacePageBackgroundStream = (COSStream) cosArray.get(0); - OutputStream saveAndPlaceStream = saveStateAndPlacePageBackgroundStream.createOutputStream(); - saveAndPlaceStream.write("q\n".getBytes(Charsets.US_ASCII)); - COSName name = page.getResources().add(pdFormXObject); - name.writePDF(saveAndPlaceStream); - saveAndPlaceStream.write(' '); - saveAndPlaceStream.write("Do\n".getBytes(Charsets.US_ASCII)); - saveAndPlaceStream.write("Q\n".getBytes(Charsets.US_ASCII)); - saveAndPlaceStream.write("q\n".getBytes(Charsets.US_ASCII)); - saveAndPlaceStream.close(); + /* + * This ensures that the Contents of the page is a COSArray. The first entry in + * the array is just a save state (e.g. 'q'). We can override it to add the + * XForm. + */ + layerUtility.wrapInSaveRestore(page); + COSArray cosArray = (COSArray) page.getCOSObject() + .getDictionaryObject(COSName.CONTENTS); + COSStream saveStateAndPlacePageBackgroundStream = (COSStream) cosArray.get(0); + OutputStream saveAndPlaceStream = saveStateAndPlacePageBackgroundStream + .createOutputStream(); + saveAndPlaceStream.write("q\n".getBytes(Charsets.US_ASCII)); + COSName name = page.getResources().add(pdFormXObject); + name.writePDF(saveAndPlaceStream); + saveAndPlaceStream.write(' '); + saveAndPlaceStream.write("Do\n".getBytes(Charsets.US_ASCII)); + saveAndPlaceStream.write("Q\n".getBytes(Charsets.US_ASCII)); + saveAndPlaceStream.write("q\n".getBytes(Charsets.US_ASCII)); + saveAndPlaceStream.close(); - } catch (MalformedURLException e1) { - e1.printStackTrace(); - } catch (IOException e1) { - e1.printStackTrace(); - } + } + catch (IOException e1) + { + e1.printStackTrace(); + } + return null; + } - return null; - } - - private static class PDFBoxDeviceReference extends WeakReference { - PDFBoxDeviceReference(PdfBoxOutputDevice referent) { - super(referent); - } - - @Override - public boolean equals(Object obj) { - if (obj instanceof PDFBoxDeviceReference) { - return ((PDFBoxDeviceReference) obj).get() == get(); - } - return super.equals(obj); - } - - @Override - public int hashCode() { - PdfBoxOutputDevice pdfBoxOutputDevice = get(); - if (pdfBoxOutputDevice != null) - return pdfBoxOutputDevice.hashCode(); - return 0; - } - } } diff --git a/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/PdfDrawerBase.java b/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/PdfDrawerBase.java new file mode 100644 index 000000000..f3d03f7d6 --- /dev/null +++ b/openhtmltopdf-objects/src/main/java/com/openhtmltopdf/objects/pdf/PdfDrawerBase.java @@ -0,0 +1,99 @@ +package com.openhtmltopdf.objects.pdf; + +import com.openhtmltopdf.extend.FSObjectDrawer; +import com.openhtmltopdf.pdfboxout.PdfBoxOutputDevice; +import com.openhtmltopdf.render.RenderingContext; +import org.apache.pdfbox.io.RandomAccessBuffer; +import org.apache.pdfbox.multipdf.LayerUtility; +import org.apache.pdfbox.pdfparser.PDFParser; +import org.apache.pdfbox.pdmodel.graphics.form.PDFormXObject; +import org.w3c.dom.Element; + +import java.io.IOException; +import java.io.InputStream; +import java.lang.ref.SoftReference; +import java.lang.ref.WeakReference; +import java.net.URL; +import java.util.HashMap; +import java.util.Map; + +public abstract class PdfDrawerBase implements FSObjectDrawer +{ + private final Map>> formMap = new HashMap>>(); + + protected PDFormXObject importPageAsXForm(RenderingContext ctx, Element e, + PdfBoxOutputDevice pdfBoxOutputDevice, LayerUtility layerUtility) throws IOException + { + + Map map = getFormCacheMap(pdfBoxOutputDevice); + int pdfpage = getPageNumber(e); + String pdfsrc = e.getAttribute("pdfsrc"); + String url = ctx.getUac().resolveURI(pdfsrc); + + PDFormXObject pdFormXObject = map.get(url); + if (pdFormXObject == null) + { + try (InputStream inputStream = new URL(url).openStream()) + { + PDFParser pdfParser = new PDFParser(new RandomAccessBuffer(inputStream)); + pdfParser.parse(); + pdFormXObject = layerUtility + .importPageAsForm(pdfParser.getPDDocument(), pdfpage - 1); + pdfParser.getPDDocument().close(); + } + map.put(url, pdFormXObject); + } + return pdFormXObject; + } + + protected Map getFormCacheMap(PdfBoxOutputDevice pdfBoxOutputDevice) + { + SoftReference> mapWeakReference = formMap + .get(new PDFBoxDeviceReference(pdfBoxOutputDevice)); + Map map = null; + if (mapWeakReference != null) + map = mapWeakReference.get(); + if (map == null) + { + map = new HashMap(); + formMap.put(new PDFBoxDeviceReference(pdfBoxOutputDevice), + new SoftReference>(map)); + } + return map; + } + + protected int getPageNumber(Element e) + { + String pdfpageValue = e.getAttribute("pdfpage"); + if (pdfpageValue == null || pdfpageValue.isEmpty()) + pdfpageValue = "1"; + return Integer.parseInt(pdfpageValue); + } + + private static class PDFBoxDeviceReference extends WeakReference + { + PDFBoxDeviceReference(PdfBoxOutputDevice referent) + { + super(referent); + } + + @Override + public boolean equals(Object obj) + { + if (obj instanceof PDFBoxDeviceReference) + { + return ((PDFBoxDeviceReference) obj).get() == get(); + } + return super.equals(obj); + } + + @Override + public int hashCode() + { + PdfBoxOutputDevice pdfBoxOutputDevice = get(); + if (pdfBoxOutputDevice != null) + return pdfBoxOutputDevice.hashCode(); + return 0; + } + } +}