Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#472 Refactor functionality of MergeBackgroundPdfDrawer into a basecla… #577

Merged
merged 1 commit into from
Oct 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,14 @@ lower corner.
<li><b>pdfpage</b>: Page to import from the PDF file.</li>
</ul>

If you want to have this watermark in the foreground you should use
[@htmlCode]
<object type="pdf/foreground" pdfsrc="watermark.pdf" pdfpage="1" style="width:1px;height:1px"></object>
[/@htmlCode]
<object type="pdf/foreground" pdfsrc="watermark.pdf" pdfpage="1" style="width:1px;height:1px"></object>

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
Expand Down Expand Up @@ -341,4 +349,4 @@ Note: This only works in Acrobat Reader, all other PDF Viewer ignore this featur
</div>

</body>
</html>
</html>
Binary file not shown.
Original file line number Diff line number Diff line change
Expand Up @@ -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;

/**
Expand All @@ -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() {
Expand Down
Original file line number Diff line number Diff line change
@@ -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<Shape, String> 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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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<PDFBoxDeviceReference, SoftReference<Map<String, PDFormXObject>>> formMap = new HashMap<PDFBoxDeviceReference, SoftReference<Map<String, PDFormXObject>>>();
public class MergeBackgroundPdfDrawer extends PdfDrawerBase
{

@Override
public Map<Shape, String> drawObject(Element e, double x, double y, double width, double height,
OutputDevice outputDevice, RenderingContext ctx, int dotsPerPixel) {
@Override
public Map<Shape, String> 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<Map<String, PDFormXObject>> mapWeakReference = formMap
.get(new PDFBoxDeviceReference(pdfBoxOutputDevice));
Map<String, PDFormXObject> map = null;
if (mapWeakReference != null)
map = mapWeakReference.get();
if (map == null) {
map = new HashMap<String, PDFormXObject>();
formMap.put(new PDFBoxDeviceReference(pdfBoxOutputDevice),
new SoftReference<Map<String, PDFormXObject>>(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<PdfBoxOutputDevice> {
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;
}
}
}
Original file line number Diff line number Diff line change
@@ -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<PDFBoxDeviceReference, SoftReference<Map<String, PDFormXObject>>> formMap = new HashMap<PDFBoxDeviceReference, SoftReference<Map<String, PDFormXObject>>>();

protected PDFormXObject importPageAsXForm(RenderingContext ctx, Element e,
PdfBoxOutputDevice pdfBoxOutputDevice, LayerUtility layerUtility) throws IOException
{

Map<String, PDFormXObject> 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<String, PDFormXObject> getFormCacheMap(PdfBoxOutputDevice pdfBoxOutputDevice)
{
SoftReference<Map<String, PDFormXObject>> mapWeakReference = formMap
.get(new PDFBoxDeviceReference(pdfBoxOutputDevice));
Map<String, PDFormXObject> map = null;
if (mapWeakReference != null)
map = mapWeakReference.get();
if (map == null)
{
map = new HashMap<String, PDFormXObject>();
formMap.put(new PDFBoxDeviceReference(pdfBoxOutputDevice),
new SoftReference<Map<String, PDFormXObject>>(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<PdfBoxOutputDevice>
{
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;
}
}
}