I am using Java PDFBox version 2.0. I want to know how to add a back ground image to the pdf. I can not find any good example in the pdfbox.apache.org
Asked
Active
Viewed 3,650 times
3 Answers
1
Do this with each page, i.e. from 0 to doc.getNumberOfPages():
PDPage pdPage = doc.getPage(page);
InputStream oldContentStream = pdPage.getContents();
byte[] ba = IOUtils.toByteArray(oldContentStream);
oldContentStream.close();
// brings a warning because a content stream already exists
PDPageContentStream newContentStream = new PDPageContentStream(doc, pdPage, false, true);
// createFromFile is the easiest way with an image file
// if you already have the image in a BufferedImage,
// call LosslessFactory.createFromImage() instead
PDImageXObject pdImage = PDImageXObject.createFromFile(imagePath, doc);
newContentStream.saveGraphicsState();
newContentStream.drawImage(pdImage, 0, 0);
newContentStream.restoreGraphicsState();
newContentStream.close();
// append the saved existing content stream
PDPageContentStream newContentStream2 = new PDPageContentStream(doc, pdPage, true, true);
newContentStream2.appendRawCommands(ba); // deprecated... needs to be rediscussed among devs
newContentStream2.close();
There is another way to do it which is more painful IMHO, getting a iterator of PDStream objects from the page with getContentStreams(), build a List, and insert the new stream at the beginning, and reassign this PDStream list to the page with setContents(). I can add this as an alternative solution if needed.

Tilman Hausherr
- 17,731
- 7
- 58
- 97
-
IMO it would be nice if there also was a `PDPageContentStream` constructor adding the stream as first page content stream. – mkl Nov 02 '15 at 14:48
-
@mkl I don't have a good idea for a constructor API addition. There are already a lot of constructors. – Tilman Hausherr Nov 02 '15 at 18:46
-
*I don't have a good idea for a constructor API addition.* - probably a constructor with an enum set of options instead of yet another boolean. – mkl Nov 02 '15 at 19:33
-
Please create an issue... I'm skeptical about changing the API now that we're close to releasing 2.0... Hmm, while writing this (and slowly waking up), the new method could be parallel to the old ones, thus not breaking anything. – Tilman Hausherr Nov 03 '15 at 07:32
-
*Please create an issue* - cf. [PDFBOX-3084](https://issues.apache.org/jira/browse/PDFBOX-3084). – mkl Nov 03 '15 at 10:27
-
*There is another way to do it which is more painful IMHO* - example code for prepending a `PDPageContentStream` can be found in [this answer](http://stackoverflow.com/a/28619285/1729265). That code there has been created for PDFBox version 1.8.x, so minor changes might be necessary for use with PDFBox 2.0. – mkl Nov 03 '15 at 10:31
-
Is there a way to use _the same single image_ as background for _multiple_ pages without just writing it each time, though, so it's only saved once in the final pdf? I have a situation where file size / memory usage becomes a concern. – Nyerguds Jun 14 '21 at 12:29
-
1Yes you can (and should!) reuse the PDImageXObject within the same document. You will still have to draw it for each page. – Tilman Hausherr Jun 14 '21 at 13:02
1
This worked best for me... (Please note the use of AppendMode.PREPEND)
InputStream is = getClass().getResourceAsStream("/yourImageFileNameWithExtenstion");
PDImageXObject pdImageXObject = PDImageXObject.createFromByteArray(document, is.readAllBytes(), "");
for (int i = 0; i < document.getNumberOfPages(); i++) {
PDPage page = document.getPage(i);
PDPageContentStream cos = new PDPageContentStream(document, page, AppendMode.PREPEND, true);
cos.drawImage(pdImageXObject, 0, 0, page.getMediaBox().getWidth(), page.getMediaBox().getHeight());
cos.close();
}

Pioneer
- 1,530
- 1
- 11
- 11
-
You create a new image Xobject for each page. If you created it once before the loop and reused it on each page, your result pdf would be smaller. – mkl Sep 26 '22 at 05:46
-
0
Call PDPageContentStream.drawImage
:
val document = PDDocument()
val page = PDPage()
document.addPage(page)
val contentStream = PDPageContentStream(document, page)
val imageBytes = this::class.java.getResourceAsStream("/image.jpg").readAllBytes()
val image = PDImageXObject.createFromByteArray(document, imageBytes, "background")
contentStream.drawImage(image, 0f, 0f, page.mediaBox.width, page.mediaBox.height)
contentStream.close()
page.close()

Cristan
- 12,083
- 7
- 65
- 69