Search code examples
javaoverlaypdfboxwatermark

How can I add watermark with apache pdfbox


I am adding watermark on an existing pdf. As far as I know there are 2ways to achieve the goal.

  • Make transparent image to the Text
  • Add Overlay pdf to the original pdf

But I either way just cover all the original contents.

Follow is what I wrote till now

The Service

public class TestPdf {

    // Method #1. This method will add overlay pdf to the original one
    public PDDocument addWatermark(PDDocument originalDocument, PDDocument overlayDocument) throws IOException {
        Overlay overlay = new Overlay();
        overlay.setOverlayPosition(Overlay.Position.BACKGROUND);
        overlay.setInputPDF(originalDocument);
        overlay.setAllPagesOverlayPDF(overlayDocument);
        PDDocument markedDocument = overlay.overlay(Collections.emptyMap());
        overlay.close();
        return markedDocument;
    }

    // Method #2. This method will add transparent image to the original pdf
    public PDDocument addImage(PDDocument originalDocument, String watermarkPath, float x, float y, float alpha) throws IOException {
        PDImageXObject watermarkImage = PDImageXObject.createFromFile(watermarkPath, originalDocument);
        PDExtendedGraphicsState pdExtendedGraphicsState = new PDExtendedGraphicsState();
        pdExtendedGraphicsState.setNonStrokingAlphaConstant(alpha);

        for (int i = 0; i < originalDocument.getNumberOfPages(); i++) {
            PDPage page = originalDocument.getPage(i);
            PDPageContentStream contentStream = new PDPageContentStream(originalDocument, page);
            contentStream.setGraphicsStateParameters(pdExtendedGraphicsState);
            contentStream.drawImage(watermarkImage, x, y);
            contentStream.close();
        }
        return originalDocument;
    }
}

And Test method like

public class TestRunner {
    private void writeFile(String outPath, PDDocument document) throws IOException {
        File outFile = new File(outPath);
        FileOutputStream fileOutputStream = new FileOutputStream(outFile);
        document.saveIncremental(fileOutputStream);
    }
    
    @Test
    public void addWatermark() throws Exception {
        TestPdf sut = new TestPdf();
        File inFile = new File(UNSIGNED_PDF_FILE);
        PDDocument document = Loader.loadPDF(inFile);
        File overlayFile = new File(WATERMARK_PDF_FILE);
        PDDocument overlay = Loader.loadPDF(overlayFile);
        PDDocument markedDocument = sut.addWatermark(document, overlay);
        writeFile(WATERMARKED_FILE, markedDocument);
    }
    
    @Test
    public void addTransparentImage() throws ExportException {
        TestPdf sut = new TestPdf();        
        File inFile = new File(UNSIGNED_PDF_FILE);
        PDDocument document = Loader.loadPDF(inFile);
        PDDocument watermarkAddedDocument = sut.addImage(document, WATERMARK_PNG_FILE, 200, 200, 0.1F);
        writeFile(IMAGED_APPENDED_FILE, watermarkAddedDocument);
    }
}

This code makes 2 pdf files. one with overlay pdf and the other one with transparent image.

The problem is the original contents does not show up

  • overlay pdf is just cover all of the original contents(when I set overlay.setPosition(Position.FOREGROUND), I can see overlay pdf)
  • Image can be adjust by alpha value, but the text on the original pdf has gone.

Is there anything wrong with setting image or overlay?

==== Updated ====

Setting overlay.setOverlayPosition(Overlay.Position.FOREGROUND) makes work.

However still got no clue about adding image.


Solution

  • You want to add content to the page. But the way you construct a PDPageContentStream

    new PDPageContentStream(originalDocument, page);
    

    replaces the current page content by your new content. Thus, you have to use a different constructor here with parameters that allow you to append new content. As you found out in response to a comment to that effect, using

    new PDPageContentStream(originalDocument, page, PDPageContentStream.AppendMode.APPEND, true, true)
    

    makes your code work as intended.