-
Notifications
You must be signed in to change notification settings - Fork 365
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
Is there a replacement for onEndPage(...) to add a Watermark for every page without an additional loop through the pages #472
Comments
…iple pages. This test is to make sure we don't break this functionality while trying to fix custom object drawer in fixed position.
…tiple page documents. This confirms that the issue for fixed position elements being in the wrong place in the output is confined to custom object drawers.
Otherwise, an environment font may be embedded, breaking the test on different platforms.
… right. Forgot to commit the actual test proof!
You can do such stuff using the ObjectDrawer (which are still underdocumentated...). I added some explanation in #475. I did a ObjectDrawer in the objects package that just puts on every page a background PDF. After registering the ObjectDrawer Factory from the objects package you can just place this object in the page footer or header, so that it gets drawn every page:
If you would like to generate the contents dynamic instead of using a predefined PDF you can just take MergeBackgroundPdfDrawer.java as a base. For registering custom drawers see #475. The Map/SoftReference stuff I do there is just to try to reuse the background PDF, which is imported as XForm, on every page. So that it gets not duplicated all the time. |
How do you get it to render on every page? I can only get it to render on the first page. The problem is that I don't know in advance how long the PDF will be since I'm using a template and populate the predefined tags with data. For that I use jsoup to insert data into a jsoup Document and then feed it to the renderer with this code: PdfRendererBuilder builder = new PdfRendererBuilder();
builder.useFastMode();
MergeBackgroundPdfDrawer pdfDrawer = new MergeBackgroundPdfDrawer();
StandardObjectDrawerFactory objectDrawerFactory = new StandardObjectDrawerFactory();
objectDrawerFactory.registerDrawer("pdf/background", pdfDrawer);
builder.useObjectDrawerFactory(objectDrawerFactory);
builder.withHtmlContent(doc.html(), uri);
builder.toStream(os);
builder.run(); This is how my HTML starts: <div id="invoice">
<div class="invoice" style="height: 750px;-fs-page-break-min-height:400px">
<object type="pdf/background"
pdfsrc="background.pdf"
style="width:1px;height:1px;-fs-page-break-min-height:400px">
</object> Also is there a way to bring it to the front? I would like to add a watermark and for that I would like it to be on the front transparent. I have also tried to add an image as watermark and adding it to the first page is fine. But how do I make it be added to every page? |
Where does the PDDocument come from? And how do you insert it into the builder? I've tried this but nothing happens. Nothing gets added to the PDF. try {
PdfRendererBuilder builder = new PdfRendererBuilder();
builder.useFastMode();
builder.withHtmlContent(doc.html(), uri);
PdfBoxRenderer renderer = builder.buildPdfRenderer();
PDDocument document = renderer.getPdfDocument();
printTextWatermark(document);
builder.usePDDocument(document);
builder.toStream(os);
builder.run();
} finally {
os.close();
} |
From memory, I think you can use the object as a running element:
This will pull it out of normal flow and place it on every page. |
Ok that seems to be working, sortof. But can I place it on top? Right now if I place something it gets on top of it. z-index is not working. |
…a baseclass, and add ForegroundPdfDrawer which always puts the PDF in front of the page.
… a base class, and add ForegroundPdfDrawer which always puts the PDF in front of the page.
I've made a PullRequest #577 with an object drawer which puts the PDF into the "foreground". There is no such a thing as a z-index in PDF. You only have a "ContentStream" which consists of all different kind of draw commands. What is drawn first is in the background, the stuff drawn last is in the foreground... So to have the watermark in the foreground it needs the be drawn last. In the PullRequest is a sample, which shows that. Or you can look here on page 3 |
That looks amazing! Is it possible to get the full HTML/CSS and maybe even Java code for that PDF file? |
@sillen102 The background and the foreground are PDFs. I made the foreground with Inkscape. You can set the opacity of the layer to get a transparency effect. If you look at the pull request you will also see the sources of the featuredocumentation.pdf. See featuredocumentation.ftl and FreeMarkerGenerator.java. If your plan is to generate the watermark dynamically, you can use outputDevice.drawWithGraphics() in your custom object and set a AlphaComposite on the Graphics2D. All you draw on the Graphics2D after setting the AlphaComposite will have the opacity set in the AlphaComposite. As an example how to use drawWithGraphics() you can look here at the class SampleObjectDrawerBinaryTree. The problem here is, that the XForm generated by drawWithGraphics() will be placed inside the stream. If you don't call your object drawer in the footer it might get under all the content of the page. It might even not work when called in the footer - didn't test. If you want to generate the content but have it for sure drawn over everything on the page, you should look at #577 in the class ForegroundPdfDrawer. But instead of importing an existing PDF page as XForm you would generate a XForm using PdfBoxGraphics2D, see the example in the readme here. |
@sillen102, you could also try |
Scratch this for now. The whole promblem is that fixed position custom object drawers are not positioning correctly on subsequent pages. I'll have another go at debugging now. |
…t (watermark). It turns out it only needed the left and top properties defined in the html.
It tuns out it only needed the <html>
<head>
<style>
@page {
size: 300px 300px;
margin: 10px;
}
object[type="watermark"] {
position: fixed;
display: block;
width: 100%;
height: 100%;
transform: rotate(45deg);
z-index: 1000;
left: 0;
top: 0;
}
</style>
</head>
<body>
<object type="watermark"></object>
Other multiple page content here...
</body>
</html> private static class WatermarkDrawer implements FSObjectDrawer {
@Override
public Map<Shape, String> drawObject(Element e, double x, double y, double width, double height,
OutputDevice outputDevice, RenderingContext ctx, int dotsPerPixel) {
outputDevice.drawWithGraphics((float) x, (float) y, (float) width / dotsPerPixel,
(float) height / dotsPerPixel, (Graphics2D g2d) -> {
double realWidth = width / dotsPerPixel;
double realHeight = height / dotsPerPixel;
Font font;
try {
Font parent = Font.createFont(Font.TRUETYPE_FONT, new File("target/test/visual-tests/Karla-Bold.ttf"));
font = parent.deriveFont(20f);
} catch (FontFormatException | IOException e1) {
e1.printStackTrace();
throw new RuntimeException(e1);
}
Rectangle2D bounds = font.getStringBounds("OpenHTMLToPDF", g2d.getFontRenderContext());
g2d.setFont(font);
g2d.setPaint(Color.RED);
g2d.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f));
g2d.drawString("OpenHTMLToPDF",
(float) ((realWidth - bounds.getWidth()) / 2),
(float) ((realHeight - bounds.getHeight()) / 2));
});
return null;
}
}
private static class WatermarkDrawerFactory implements FSObjectDrawerFactory {
@Override
public FSObjectDrawer createDrawer(Element e) {
if (isReplacedObject(e)) {
return new WatermarkDrawer();
}
return null;
}
@Override
public boolean isReplacedObject(Element e) {
return e.getAttribute("type").equals("watermark");
}
} |
Hello,
We are currently in the process of rebuilding our PDF generator with Open HTML to PDF.
Formerly we were using the Flying Saucer library. The underlying IText has the functionality
to set a page event.
We used that to print a string as a watermark on every page during creation of
the pdf.
old version:
Unfortunately we weren't able to find such functionality with Open HTML to PDF and PDFBox.
So we came up with our current solution that takes the final document (after the conversion process)
and iterates through all pages once again. There it adds the watermark.
current method:
Despite this working kind of well our problem with this solution is that it needs to loop all pages again.
This might become very time and memory consuming when it comes to converting a document with a vast number of pages.
We would prefere a solution that adds the watermark during the conversion where the PDF pages are touched the first time.
What would you suggest is the preferred way to achieve such a behaviour?
Thanks
The text was updated successfully, but these errors were encountered: