ScreenshotNeo

BlogHTML to image & PDF

How to Add an Image Watermark to a PDF in Ruby

Add a logo to every page of an existing PDF in Ruby with HexaPDF, or stamp a prepared watermark PDF with CombinePDF. Includes code, tradeoffs, and troubleshooting.

By the ScreenshotNeo team30 September 20263 min read

How to Add an Image Watermark to a PDF in Ruby

For an existing PDF, use HexaPDF: make a one-page PDF containing your image, then apply that page as a background or stamp. This keeps image placement separate from the operation on the source document. If you are generating a new PDF, Prawn can place a PNG or JPG directly on each page. If you already have a watermark as a one-page PDF and want a pure-Ruby overlay, CombinePDF can append that page to each target page.

The examples below use a transparent PNG logo. Prepare it at a useful resolution, with whitespace trimmed if you want its visible artwork to align predictably. You can use JPG when transparency is unnecessary. The watermark page’s dimensions and the image’s position determine where it lands; inspect the result on representative pages before using it in a production workflow.

1. Choose the right Ruby approach

Situation Recommended approach Why
Modify an existing PDF HexaPDF CLI Its watermark command applies a PDF page below or above source content and supports choosing and repeating watermark pages.
Generate a new PDF with a logo Prawn Its image method places JPG or PNG files in the page-generation flow.
Already have a watermark PDF page; want a Ruby overlay CombinePDF Its documented page << operator appends the imported page to each source page.

HexaPDF is the direct fit for this title because it can read and modify existing PDFs, while Prawn focuses on generating PDF content. The HexaPDF command accepts a watermark PDF, input PDF, and output PDF. See the CLI reference for watermark page selection, repetition, ordering, and password options.

2. Create a watermark PDF from an image

Install HexaPDF and use its image-to-PDF command to prepare a one-page watermark document. The following commands assume logo.png is in the current directory and write watermark.pdf beside it:

Prepare the image as a watermark page, then apply it to the source PDF with the desired overlay order.
Prepare the image as a watermark page, then apply it to the source PDF with the desired overlay order.
gem install hexapdf
hexapdf image2pdf logo.png watermark.pdf

Confirm the generated page size and image placement suit the source document. If your source uses a different page size, create a watermark page with matching dimensions and position the logo within it as needed. The HexaPDF image API demonstrates placing an image at coordinates and sizing it by width or height; refer to the HexaPDF API documentation for the current API details. Image-to-PDF conversion and watermarking are separate steps, so you can reuse the same prepared watermark page across multiple PDFs.

3. Apply the image watermark to an existing PDF

Run the watermark command with the prepared page, source PDF, and destination path:

HexaPDF can place the watermark below page content as a background or above it as a stamp.
HexaPDF can place the watermark below page content as a background or above it as a stamp.
hexapdf watermark -w watermark.pdf input.pdf output.pdf

By default, HexaPDF applies the first watermark page as a background to all pages. Background placement is usually suitable when the watermark should sit behind page content. To put it over the content, select stamp mode:

hexapdf watermark -w watermark.pdf -t stamp input.pdf output.pdf

The tool’s documented behavior is to apply watermark PDF pages as a background or stamp based on --type. It can also select pages from the watermark PDF and repeat them across the input. For example, select watermark pages 2 through 5 and cycle through them:

hexapdf watermark -w watermark.pdf -i 2-5 -r all input.pdf output.pdf

With fewer watermark pages than source pages, the default repeat mode reuses the last selected watermark page. The all mode cycles through the selected pages. The manual also shows -i 1,2 -t stamp to use one watermark page for the first source page and another for subsequent pages. Check the page specification in the CLI manual when using ranges or nonsequential selections.

Use it from a Ruby script

The CLI is Ruby software and can be invoked by a Ruby task or application process. Use argument arrays with system to avoid shell interpolation; check the return value so failures do not silently pass:

input = "input.pdf"
watermark = "watermark.pdf"
output = "output.pdf"

success = system(
  "hexapdf", "watermark", "-w", watermark,
  "-t", "background", input, output
)
raise "HexaPDF watermarking failed" unless success

Use "stamp" instead of "background" to place the mark above existing content. Keep input and output paths distinct while developing the workflow, and make the destination directory writable. In a job runner, capture standard output and standard error so an operator can inspect the command’s diagnostic message.

4. Put an image on pages you generate with Prawn

If you are creating the PDF yourself, Prawn can draw the image in the page-generation block. Install the gem and save this as make_pdf.rb:

# Gemfile: gem "prawn"
require "prawn"

logo = "logo.png"
Prawn::Document.generate("report.pdf", page_size: "A4") do |pdf|
  pdf.repeat(:all) do
    pdf.image logo, at: [420, 790], width: 90
  end

  pdf.text "Report content starts here", at: [50, 730]
  pdf.start_new_page
  pdf.text "Second page content", at: [50, 730]
end

Run it with bundle exec ruby make_pdf.rb after adding Prawn to your Gemfile and running bundle install. Prawn’s image method adds an image to the current page and supports JPG and PNG. If only width or height is given, it scales proportionally; if both are given, it stretches to fit both dimensions. See the Prawn image API documentation.

The coordinates in Prawn are points measured from the page’s lower-left origin. Adjust at and width for your page size and desired placement. The repeat(:all) block draws the logo on every page, including pages created after the block is declared. For a single page, call pdf.image directly in the page body instead. Use proportional sizing if the logo’s aspect ratio must stay intact.

5. Overlay a prepared watermark page with CombinePDF

When the logo is already in a one-page PDF, CombinePDF’s documented pattern imports its first page and appends it to every page in the source document:

# Gemfile: gem "combine_pdf"
require "combine_pdf"

watermark_page = CombinePDF.load("watermark.pdf").pages[0]
pdf = CombinePDF.load("input.pdf")
pdf.pages.each do |page|
  page << watermark_page
end
pdf.save("output.pdf")

This example overlays the imported page. The project documentation describes the page-level << operator and warns that it is the page, not the PDF object, that receives the overlay. See the CombinePDF project documentation. That repository currently identifies the project as unmaintained, which is a maintenance consideration when selecting it for a new application.

6. Verify the output before distributing it

  1. Open the output in at least one PDF viewer and confirm that the watermark is visible on the intended pages.
  2. Check both a page with ordinary content and pages with unusual rotation, annotations, transparency, forms, or other interactive elements.
  3. Verify that the logo is not stretched, cropped, too faint, or obscuring text. Adjust image dimensions or placement in the watermark PDF and regenerate it if necessary.
  4. Check page count and file readability after processing. Keep a copy of the source so you can rerun the transformation if you change the watermark.
  5. If the source is encrypted, use the documented password option and ensure your process handles the password appropriately.

PDF libraries and commands do not guarantee that every document feature will be preserved in every case. The research documentation specifically calls out annotations, page rotation, encryption, forms, transparency, and incremental-update behavior as areas that can affect output. Test documents representative of your actual workload; do not infer preservation from a successful command exit alone.

Or skip the browser setup

For web-page screenshots, ScreenshotNeo provides a one-request screenshot API and an MCP server for AI agents. This is a separate task from adding a watermark to an existing PDF: the API captures a URL as an image or PDF. The API accepts a URL and returns a clean screenshot, in PNG, JPEG, WebP, or PDF. See the ScreenshotNeo API documentation.

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

r = requests.get(
    "https://api.screenshotneo.com/v1/shot",
    params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"},
    timeout=90,
)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
if (!res.ok) throw new Error(`Screenshot request failed: ${res.status}`);
await Bun.write('shot.webp', res);

Cookie banners, popups, and chat widgets are removed before the shot; bot checks, blank pages, and failed loads are never billed. An MCP server lets AI agents take screenshots. The free plan includes 1,000 screenshots a month with no card, and paid plans start at $5 for 3,000. Sign up for 1,000 free screenshots a month, with no card.

Configuration, reliability, and cost considerations

  • Overlay order: choose background to place the mark beneath page content or stamp to place it above. A background can become hidden by opaque page artwork; a stamp may cover text.
  • Page mapping: specify watermark pages with -i. The default repeat behavior reuses the last selected page; choose -r all for cyclic repetition.
  • Image format: Prawn supports JPG and PNG. PNG is a practical choice when the logo needs transparency. Prawn documents note that PNGs with alpha channels can be processor- and memory-intensive.
  • Geometry: use the same intended page dimensions and coordinate system when making the watermark page. Check rotated or differently sized source pages, as a mark positioned for one geometry may not land where expected on another.
  • Memory and throughput: the dossier provides no benchmark for these libraries. Large PDFs and high-resolution transparent images can consume more resources; measure with representative files and process work in bounded jobs.
  • Licensing: HexaPDF documents AGPL and commercial licensing options. Review its current license terms for proprietary distribution. Do not choose a dependency solely from an example that happens to run locally.
  • Cost: these Ruby libraries are software dependencies rather than per-document screenshot services. Account for infrastructure, operational maintenance, and any applicable license terms; no throughput or cost-per-page benchmark is claimed here.

Troubleshooting

Symptom Likely cause Fix
hexapdf: command not found The gem executable is not installed or is absent from the process PATH. Install HexaPDF in the active Ruby environment, run through Bundler, and confirm the executable is available to the same user that runs the job.
Watermark is missing or hidden It was applied as a background beneath opaque content, or the image lies outside the visible page. Try stamp mode, inspect the watermark PDF page and its dimensions, and reposition or resize the image.
Only some pages have the expected logo The selected watermark page range or repeat mode does not match the desired page mapping. Review -i and -r; use a single reusable page or cyclic repetition as appropriate.
Logo looks stretched Both width and height were set with different aspect ratio in Prawn. Set just one dimension to preserve proportions, or compute matching dimensions before setting both.
Output differs on rotated pages or forms Document structure or page geometry affects the result. Test those pages explicitly, inspect the output in target viewers, and evaluate the document-specific behavior before processing a full batch.
Encrypted source fails A password is required to read the input. Use HexaPDF’s documented -p/--password option. For automation, avoid exposing secrets in logs or shell history.
Ruby script reports failure but no detail The wrapper checked only a generic return value or discarded diagnostics. Capture the command’s standard error and exit status; verify the output file exists and opens.

FAQ

Can I add a PNG directly to an existing PDF with Prawn?

Prawn’s image method is for pages in PDFs you generate. For an existing document, prepare a watermark PDF page and apply it with HexaPDF, or use a suitable existing-PDF workflow such as the documented CombinePDF overlay.

How do I put the logo on every page?

With HexaPDF, the default command applies its first watermark page to all input pages. With Prawn, place the image in a repeat(:all) block. With CombinePDF, iterate over pdf.pages and append the imported watermark page.

Should a watermark be a background or a stamp?

Use a background when it should sit behind content and a stamp when it should sit above. Check the result on real pages because either choice can reduce legibility depending on the artwork.

Will watermarking preserve digital signatures?

The supplied documentation does not claim universal preservation of signatures or other PDF features. Validate the output against your document requirements and signing workflow.