Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Some links on this page are affiliate links: if you buy through them we may earn a commission, at no extra cost to you.

Use Apache PDFBox to open the existing PDF, iterate over its pages, append a text content stream, and save a new file. The essential details are the watermark transform, each page’s size and rotation, drawing order, and graphics-state settings such as opacity. The example below targets the PDFBox 3.x API; match it to the version declared in your build rather than copying APIs between major versions.

Choose the library and version first

Apache PDFBox has a documented Java example for placing diagonal text on every page. The project homepage lists PDFBox 3.0.8, released July 11, 2026, and 2.0.37, released July 15, 2026. The loader and content-stream APIs differ between major versions, so use one version consistently in your dependency configuration and source.

This article uses the 3.x style, including Loader.loadPDF. PDFBox is available under the Apache License 2.0. iText is another established option: its Java watermark guidance uses an extended graphics state for transparency, but iText states that a commercial license is available for software or services unable to comply with AGPL terms. Check the current license terms against your distribution model before selecting it.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Add PDFBox to the project

Maven

<dependency>
  <groupId>org.apache.pdfbox</groupId>
  <artifactId>pdfbox</artifactId>
  <version>3.0.8</version>
</dependency>

If your project must remain on the 2.0 line, consult that version’s API documentation and change the loading call accordingly. Do not combine a 3.x example with 2.x jars.

Complete example: watermark every page

The following program reads input.pdf, writes watermarked.pdf, and places a gray, semi-transparent “DRAFT” diagonally across every page. It saves the original by writing to a separate destination. The 100-point text size is only an illustrative starting point; long labels require measurement and a smaller size.

import java.io.IOException;
import java.nio.file.Path;

import org.apache.pdfbox.Loader;
import org.apache.pdfbox.cos.COSName;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.pdmodel.PDPage;
import org.apache.pdfbox.pdmodel.PDPageContentStream;
import org.apache.pdfbox.pdmodel.common.PDRectangle;
import org.apache.pdfbox.pdmodel.font.PDType1Font;
import org.apache.pdfbox.pdmodel.font.Standard14Fonts;
import org.apache.pdfbox.pdmodel.graphics.state.PDExtendedGraphicsState;
import org.apache.pdfbox.util.Matrix;

public final class PdfTextWatermark {
    private PdfTextWatermark() {}

    public static void main(String[] args) throws IOException {
        Path source = Path.of("input.pdf");
        Path destination = Path.of("watermarked.pdf");
        String label = "DRAFT";
        float fontSize = 100f;
        float opacity = 0.20f;

        try (PDDocument document = Loader.loadPDF(source.toFile())) {
            PDExtendedGraphicsState state = new PDExtendedGraphicsState();
            state.setNonStrokingAlphaConstant(opacity);
            state.setStrokingAlphaConstant(opacity);

            for (PDPage page : document.getPages()) {
                PDRectangle box = page.getMediaBox();
                float width = box.getWidth();
                float height = box.getHeight();
                int rotation = ((page.getRotation() % 360) + 360) % 360;

                // Center the text in the page's unrotated coordinate system.
                float angle = (float) Math.toRadians(45);
                float textWidth = PDType1Font.HELVETICA_BOLD
                        .getStringWidth(label) / 1000f * fontSize;
                float x = (width - textWidth) / 2f;
                float y = height / 2f;

                try (PDPageContentStream stream = new PDPageContentStream(
                        document, page, PDPageContentStream.AppendMode.APPEND,
                        true, true)) {
                    stream.saveGraphicsState();
                    stream.setGraphicsStateParameters(state);
                    stream.setNonStrokingColor(0.45f, 0.45f, 0.45f);

                    // Compensate for the page's /Rotate value before drawing.
                    Matrix pageRotation = switch (rotation) {
                        case 90 -> new Matrix(0, 1, -1, 0, height, 0);
                        case 180 -> new Matrix(-1, 0, 0, -1, width, height);
                        case 270 -> new Matrix(0, -1, 1, 0, 0, width);
                        default -> new Matrix();
                    };
                    stream.transform(pageRotation);
                    stream.beginText();
                    stream.setFont(new PDType1Font(Standard14Fonts.FontName.HELVETICA_BOLD), fontSize);
                    stream.setTextMatrix(Matrix.getRotateInstance(angle, x, y));
                    stream.showText(label);
                    stream.endText();
                    stream.restoreGraphicsState();
                }
            }
            document.save(destination.toFile());
        }
    }
}

The two boolean arguments in the content-stream constructor request reset-context behavior while appending. The watermark is therefore added after existing page content and normally appears in front. If it must sit behind existing marks, use the applicable PREPEND mode for your PDFBox version and verify the result by rendering sample pages.

How the placement code works

Text, font, color and opacity

PDType1Font with Helvetica Bold avoids shipping a font file. For a brand typeface or non-Latin script, embed a suitable TrueType or OpenType font and use its actual metrics. The text width calculation keeps the label approximately centered. For very long text, reduce the font size or compute a scale from the page diagonal.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The extended graphics state sets separate stroking and non-stroking alpha values. Text is non-stroking in this example, so setNonStrokingAlphaConstant controls its transparency. Save and restore graphics state around every change; otherwise a later content operation can inherit the watermark’s alpha, color or transform.

Rotation and mixed page sizes

PDF pages can carry a /Rotate value while retaining portrait-oriented media-box coordinates. The example normalizes rotation to 0, 90, 180 or 270 degrees and applies a corresponding matrix. It also reads each page’s media-box width and height inside the loop, so a landscape page is not positioned using the dimensions of a preceding portrait page.

Some documents use crop boxes, offsets or unusual page boxes. If the visible page is defined by a crop box, base placement on that box and its lower-left coordinates rather than assuming an origin of (0, 0). Render rotated and mixed-size samples before processing a large batch.

Over versus under existing content

Appending places the new operators after existing operators, which generally makes the watermark visible over page content. Prepending places them before existing operators and can let opaque page artwork cover the mark. Neither mode makes the watermark a security control: it is ordinary page content and may be hidden, edited or removed by a capable PDF editor.

Free tools Windows power users keep installed

One-click scans. No signup required.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Customizing a production watermark

Choose a readable label

  • Use short labels such as DRAFT, CONFIDENTIAL or an internal document identifier.
  • Use a light gray and moderate opacity so body text remains readable.
  • Test both dark and light page backgrounds; one fixed color may not contrast well everywhere.

Place one watermark or a repeated pattern

A single centered diagonal label is easiest to inspect. A tiled pattern requires repeated text matrices at calculated x/y positions and increases content-stream size. Keep the same rotation compensation and graphics-state boundaries for each tile.

Use a selected page range

Instead of iterating over every page, track an index and apply the stream only when it falls within your required range. Keep the original page order and write a new output file unless you have an explicit, recoverable replacement procedure.

Validation checklist

  • Render at least one portrait, landscape, rotated and mixed-size page.
  • Check that the label is not clipped at any edge.
  • Inspect readability over dense text, images and dark backgrounds.
  • Open the output with more than one PDF viewer.
  • Confirm that forms, annotations, links and existing page content remain usable.
  • Compare file size and processing time on representative documents; no performance benchmark is established here.

Troubleshooting

“Cannot find symbol: Loader”

You are probably compiling a 2.0 dependency with a 3.x example. Use the loader API supplied by your installed major version, or align the dependency and source to PDFBox 3.x.

The watermark is sideways or displaced

Inspect page.getRotation(), page-box dimensions and the transform order. Normalize the rotation, apply the page matrix before the text matrix, and test 90- and 270-degree pages separately.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

The watermark is invisible

It may be behind opaque page artwork, fully transparent, outside the crop box or too close in color to the background. Try append mode, temporarily set opacity to 1.0 for diagnosis, and render the output.

Text is clipped

The label’s measured width, rotation and origin may extend beyond the page. Reduce the font size, calculate bounds for the rotated string, and position relative to the actual crop or media box.

The output overwrites the source

Use distinct source and destination paths, as in the example. If replacement is required, save to a temporary file, close it successfully, then atomically replace the original and retain a backup.

Later page content has the wrong transparency or transform

A missing restoreGraphicsState() can leak settings. Pair every saveGraphicsState() with a restore, including paths that throw exceptions; try-with-resources closes the stream, but it does not replace explicit graphics-state restoration.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.
Independent reader supportYour contribution helps us test, update, and keep practical guides available for everyone.Support on Ko-Fi

Alternative with iText

iText’s watermark guidance places text or images on existing pages and uses an extended graphics state for transparency, with a documented 50% opacity example. Its save/restore operations serve the same isolation purpose. Compare PDFBox and iText on license fit, API compatibility with your codebase, font and transparency needs, rotation and placement control, and the support your team requires. Available sources establish usage examples and license statements, not a speed ranking.

Or skip the browser setup

If your workflow also needs clean captures of the watermarked PDF’s web preview or documentation page, ScreenshotNeo provides a single screenshot request. It accepts cookie and consent banners before capture and removes more than 60 known consent platforms, newsletter popups and chat widgets. Bot checks, blank pages, timeouts, failed loads and cache hits are not billed, and response headers report the page verdict and billing status. Its MCP server exposes take_screenshot, get_page_info and capture_pdf to Claude, Cursor and other MCP clients.

See the ScreenshotNeo API documentation for options such as full-page capture, CSS selectors, device presets, custom CSS or JavaScript, waits, request blocking, authentication headers, cookies, geolocation, PDF output, signed links, asynchronous jobs and bulk capture.

curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp

The free plan includes 1,000 screenshots each month with no card; paid plans start at $5 for 3,000 shots. Create a free ScreenshotNeo account.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.

Frequently Asked Questions

Does a PDFBox watermark prevent copying or editing?

No. The watermark is ordinary page content, not tamper-proof protection or a digital signature.

Can I watermark only selected pages?

Yes. Keep a page index in the iteration and create the content stream only for the indexes or range you choose.

Should I overwrite the original PDF?

Prefer a separate destination file. Replace the original only through a deliberate temporary-file and backup workflow.

Product prices and availability are accurate as of the date/time indicated and are subject to change. Any price and availability information displayed on Amazon at the time of purchase will apply.

Special offer. See more information about Outbyte and uninstall instructions. Please review EULA and Privacy policy.