---
title: "Add an image or watermark to a PDF in C#"
url: https://recursiveai.org/onepdf/articles/add-image-to-pdf-csharp/
description: "Add a PNG or JPEG to an existing PDF in C#, stamp a text or image watermark on every page, and write text onto pages, with pure .NET code. MIT or Apache-2.0."
date: 2026-10-26
author: OnePDF team
---

# Add an image or watermark to a PDF in C#

Add a PNG or JPEG to an existing PDF in C#, stamp a text or image watermark on every page, and write text onto pages, with pure .NET code. MIT or Apache-2.0.

October 26, 2026 · OnePDF team

To add an image to a PDF in C#, open the file for editing with OnePDF, add the image to the document with `AddPngImage` or `AddJpegImage`, and draw it on a page with `DrawImage` at a position and size in points. For a watermark, `AddTextStamp` and `AddImageStamp` place text or an image on every page, rotated, at any opacity, over or under the content. The page’s existing content stays byte for byte as it was. OnePDF is pure C# with no native binaries, licensed MIT OR Apache-2.0. Every sample was compiled and run against OnePDF 1.11.0 on .NET 10, and each output passes `qpdf --check`.

## Before you start

*Terminal · NuGet*

```
dotnet new console -o PdfStamp
cd PdfStamp
dotnet add package RecursiveAI.OnePdf --version 1.11.0
```

OnePDF targets .NET 10. The samples edit `report.pdf`, a six-page US Letter report, and the IRS Form W-9 ([fw9.pdf](https://www.irs.gov/pub/irs-pdf/fw9.pdf)). `logo.png` is a 240 × 240 PNG with transparency and `photo.jpg` an 800 × 500 JPEG. Any PDF and images will do.

## Add an image to an existing PDF

*Program.cs · OnePDF 1.11.0 · .NET 10*

```
using OnePdf;
 
using PdfDocument doc = PdfDocument.Open("report.pdf", new PdfOpenOptions { AllowEditing = true });
 
// Add each image to the document once; it can then be drawn on any page.
PdfCreatedImage logo = doc.AddPngImage(File.ReadAllBytes("logo.png"));      // alpha channel kept as a soft mask
PdfCreatedImage photo = doc.AddJpegImage(File.ReadAllBytes("photo.jpg"));   // embedded as is, no recompression
 
PdfPage page = doc.Pages[0];
Console.WriteLine($"page 1 is {page.MediaBox.Width} x {page.MediaBox.Height} points");
 
using (PdfPageContentBuilder b = page.BeginContent())   // drawn over the existing content
{
    b.DrawImage(logo, 522, 726, 36, 36);                  // x, y of the lower left corner, width, height
    b.DrawImage(photo, 54, 72, 240, 150);                 // 800 x 500 px scaled to 240 x 150 pt
    b.Commit();                                           // nothing is written before Commit
}
 
doc.Save("report-images.pdf");
```

*Output · Console*

```
page 1 is 612 x 792 points
```

The logo now sits in the top right corner of page 1 and the photo near the bottom left. `pdfimages -list` shows what went into the file: the logo as a 240 × 240 RGB image with a separate gray soft mask, which keeps its transparency, and the photo as a `jpeg` image, 800 × 500. The JPEG bytes in the PDF are byte for byte the bytes of `photo.jpg`.

### Coordinates and sizes

- Positions are in points (1/72 inch) from the **lower left** corner of the page, with y going up. A US Letter page is 612 × 792 points and A4 is 595 × 842. `page.MediaBox` gives the size of any page.
- `DrawImage(image, x, y, width, height)` stretches the image to the box. To keep the aspect ratio, compute one side from the other: an 800 × 500 photo drawn 240 points wide is 150 points high.
- An image’s resolution on paper is its pixel width divided by the box width in inches. The photo, 800 pixels across 240 points (3.33 inches), prints at 240 dpi.
- Content you draw doesn’t turn with a page that has `/Rotate` set. The stamp helpers below compensate for it.

### JPEG, PNG and everything else

- `AddJpegImage` embeds the JPEG file as it is, without decoding or recompressing. Baseline and progressive JPEGs with 1, 3 or 4 components work. Arithmetic-coded and lossless JPEGs are refused.
- `AddPngImage` reads a PNG and stores it losslessly. An alpha channel becomes a soft mask.
- Add an image once and draw it on as many pages as you like. It is stored once.
- Other formats need converting first, as below, or raw samples through `AddRawImage`.

## Add a watermark to every page

A watermark is the same content repeated on each page. The stamp helpers draw it once into a shared form and place that form on the pages you choose, all of them by default, centered on the visible area of each page:

*Program.cs · OnePDF 1.11.0 · .NET 10*

```
using OnePdf;
 
using PdfDocument doc = PdfDocument.Open("report.pdf", new PdfOpenOptions { AllowEditing = true });
 
// A diagonal text watermark on every page, red at 15% opacity, centered on each page.
PdfCreatedFont bold = doc.AddStandardFont("Helvetica-Bold");
doc.AddTextStamp("CONFIDENTIAL", bold, 72,
    new PdfStampOptions { Opacity = 0.15, RotationDegrees = 45, Color = (0.7, 0.1, 0.1) });
 
// A faint logo under the text of the first page only.
PdfCreatedImage logo = doc.AddPngImage(File.ReadAllBytes("logo.png"));
doc.AddImageStamp(logo, 300, 300,
    new PdfStampOptions { Opacity = 0.08, Placement = PdfContentPlacement.Underlay }, pageIndexes: [0]);
 
doc.Save("report-watermarked.pdf");
Console.WriteLine($"watermarked {doc.PageCount} pages");
```

*Output · Console*

```
watermarked 6 pages
```

Every page now has “CONFIDENTIAL” across it at 45 degrees in light red, and the first page has the logo, large and faint, behind its text. The watermark is one shared form, stored once however many pages show it.

`PdfStampOptions` sets:

- `Opacity` from 0 to 1, and a `BlendMode`,
- `RotationDegrees`, counterclockwise as the reader sees the page, and `Color` as RGB components from 0 to 1,
- `Placement`: `Overlay` (the default) draws on top, `Underlay` under the page’s content, so the page’s text and images sit on top of it,
- `CenterX` and `CenterY` to put the stamp somewhere other than the middle of the page.

The text stamp uses Helvetica Bold, one of the standard PDF fonts that viewers supply, so no font is embedded. That keeps the file small, but a standard font can’t go into a PDF/A file or show characters beyond its Latin set. For either, embed a TrueType or OpenType font with `doc.AddFont(File.ReadAllBytes("YourFont.ttf"))` and pass that instead.

A watermark drawn this way is part of the page content: anyone with a PDF editor can delete it again, and text extraction will return it with the page text. If the goal is to stop the information leaking, [redact](https://recursiveai.org/onepdf/articles/redact-pdf-csharp/) it instead.

## Add text to an existing PDF

The same page builder writes text. Here every page of the W-9 gets a received date and a page number in its bottom margin, plus a right-aligned label:

*Program.cs · OnePDF 1.11.0 · .NET 10*

```
using OnePdf;
 
using PdfDocument doc = PdfDocument.Open("fw9.pdf", new PdfOpenOptions { AllowEditing = true });
PdfCreatedFont font = doc.AddStandardFont("Helvetica");
 
// Text in the bottom margin of every page: a line, and a box that wraps.
for (int i = 0; i < doc.PageCount; i++)
{
    using PdfPageContentBuilder b = doc.Pages[i].BeginContent();
    b.SetFillRgb(0.1, 0.2, 0.6);
    b.SetFont(font, 8);
    b.DrawText($"Received 2026-10-26 · page {i + 1} of {doc.PageCount}", 36, 14);
    b.DrawTextAligned("Example Co. vendor file", 36, 14, 540, PdfTextAlignment.Right);
    b.Commit();
}
 
doc.Save("fw9-received.pdf");
Console.WriteLine("stamped");
```

*Output · Console*

```
stamped
```

`DrawText` places a line with its baseline starting at `x`, `y`. `DrawTextAligned` aligns one line inside a span, and `DrawTextBox` wraps a paragraph into a box, left, centered, right or justified, and returns any text that didn’t fit. `MeasureText` gives the width of a string in the current font and size, so you can place things exactly.

This text isn’t shaped: the characters are drawn one after another, with no ligatures and no right-to-left reordering. That is right for Latin, Greek and Cyrillic. For Arabic, Hebrew, Hindi and other complex scripts, lay the text out with OnePdf.Layout, which shapes it: see [Arabic and Hindi text in a C# PDF](https://recursiveai.org/onepdf/articles/arabic-text-pdf-csharp/).

## Add a WebP, TIFF, GIF or BMP image

OnePDF reads JPEG and PNG itself. For anything else, decode it with an image library and hand OnePDF a PNG. With [OneImage](https://oneimage.dev/), our pure C# image library, which reads PNG, JPEG, WebP, GIF, TIFF, BMP and ICO, that is one line. Add `RecursiveAI.OneImage` (1.10.2 here) to the project:

*Program.cs · OnePDF 1.11.0 · OneImage 1.10.2*

```
using OneImage;
using OnePdf;
 
// OnePDF takes JPEG and PNG directly. Convert anything else (WebP, TIFF, GIF, BMP) to PNG first.
using var png = new MemoryStream();
Image.Load("harbor.webp").Save(png, PngFormat.Instance);
 
using PdfDocument doc = PdfDocument.Open("report.pdf", new PdfOpenOptions { AllowEditing = true });
PdfCreatedImage picture = doc.AddPngImage(png.ToArray());
using (PdfPageContentBuilder b = doc.Pages[1].BeginContent())
{
    b.DrawImage(picture, 54, 72, 240, 150);
    b.Commit();
}
doc.Save("report-webp.pdf");
Console.WriteLine($"{png.Length:N0} bytes of PNG placed on page 2");
```

*Output · Console*

```
27,214 bytes of PNG placed on page 2
```

A photo converted this way is stored losslessly, so it takes more room than the JPEG it might have been. For photos, converting to JPEG and using `AddJpegImage` gives a smaller file.

## Images in a new document

To put images into a PDF you are generating, use OnePdf.Layout instead of coordinates: `col.Item().Width(120).Image(bytes).AltText("Company logo")` places an image in the flow, scaled to fit, and tags it for screen readers. SVG goes in as vector graphics with `Svg(...)`. See [create a PDF in C#](https://recursiveai.org/onepdf/articles/create-pdf-csharp/).

## Where next

- [Add an image or a watermark](https://recursiveai.org/onepdf/cookbook/add-image-watermark/), the short cookbook recipe.
- [Content creation](https://recursiveai.org/onepdf/docs/content-creation/): every drawing call, fonts, gradients and coordinates.
- [Merge PDF files in C#](https://recursiveai.org/onepdf/articles/merge-pdf-csharp/), to add a cover page before stamping.
- [Redact a PDF in C#](https://recursiveai.org/onepdf/articles/redact-pdf-csharp/), to remove content rather than cover it.
