danfickle / danfickle/openhtmltopdf

Caching and Reuse of PDFormXObject (embedded pdf via img tag)

Open
#782 3 comments 0 reactions 0 assignees View on GitHub
Dominant language
Java
Stars
2.2k
Forks
423
PR merge metrics
No merged PRs in 30d

Description

Hi,

we are rendering pdfs with multiple pages where the header of each page contains a logo. This logo comes from another pdf file. Embedding this logo.pdf via img tag works well, but the resulting PDF file grows a lot with each page, because the logo is embedded as a new XObject instance again and again.

When i looked at the code i understood that no further manipulation is done to the PDFormXObject after it has been created until it is added to the pdf dictionary.

Therefore i added a little cache so that pdfbox will receive the same PDFormXObject instance for a specified src url + page and will recognize that this element is already part of the pdf dictionary and will reuse the already existing object.

Here is my code example. For me this works and file size is way smaller. Does anyone know if this might not be a good idea?

This code is in com.openhtmltopdf.pdfboxout.PdfBoxPDFReplacedElement
See the use of pdfCache map.

```java
private static Map pdfCache = new HashMap<>();

public static PdfBoxPDFReplacedElement create(PDDocument target, byte[] pdfBytes, Element e, Box box, CssContext ctx, SharedContext shared) {
try (PDDocument srcDocument = PDDocument.load(pdfBytes)){
int pageNo = parsePage(e);
if (pageNo >= srcDocument.getNumberOfPages()) {
XRLog.log(Level.WARNING, LogMessageId.LogMessageId0Param.LOAD_PAGE_DOES_NOT_EXIST_FOR_PDF_IN_IMG_TAG);
return null;
}

PDPage page = srcDocument.getPage(pageNo);
float conversion = 96f / 72f;
float width = page.getMediaBox().getWidth() * shared.getDotsPerPixel() * conversion;
float height = page.getMediaBox().getHeight() * shared.getDotsPerPixel() * conversion;

LayerUtility util = new LayerUtility(target);

String cacheKey = e.getAttribute("src") + pageNo;

PDFormXObject formXObject = pdfCache.get(cacheKey);

if (formXObject == null){
formXObject = util.importPageAsForm(srcDocument, page);
pdfCache.put(cacheKey, formXObject);
}

return new PdfBoxPDFReplacedElement(formXObject, e, box, ctx, shared, width, height);
} catch (InvalidPasswordException e1) {
XRLog.log(Level.WARNING, LogMessageId.LogMessageId0Param.EXCEPTION_TRIED_TO_OPEN_A_PASSWORD_PROTECTED_DOCUMENT_AS_SRC_FOR_IMG, e1);
} catch (IOException e1) {
XRLog.log(Level.WARNING, LogMessageId.LogMessageId0Param.EXCEPTION_COULD_NOT_READ_PDF_AS_SRC_FOR_IMG, e1);
}

return null;
}
```
And a question on the side: Why are normale images like png automatically reused?

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.