---
title: "Save as PDF in C#: HTML, images and generated content"
url: https://recursiveai.org/onepdf/cookbook/save-as-pdf/
description: "Save as PDF in C#: HTML to PDF, an image to PDF, or content you generate in code. A short, runnable program for each, with OneRender and OnePDF."
version: "1.15.0"
---

# Save as PDF in C#: HTML, images and generated content

Which call saves your content as a PDF depends on what you start from. Each section below is a complete program you can run. Start with a new console project:

```shell
dotnet new console -o SaveAsPdf && cd SaveAsPdf
dotnet add package RecursiveAI.OneRender.Pdf --version 1.3.1
dotnet add package RecursiveAI.OnePdf --version 1.15.0
```

## HTML to PDF

OneRender lays out HTML and CSS for print, with no browser, and writes a tagged PDF with real, selectable text. Put this in `Program.cs` and run `dotnet run`:

```csharp
using OneRender.Pdf;

string html = """
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <title>Invoice 2026-118</title>
      <style>
        body { font: 11pt/1.4 sans-serif }
        h1 { color: #2F5D8A }
        table { width: 100%; border-collapse: collapse }
        th, td { border-bottom: 1px solid #ccc; padding: 4pt; text-align: left }
      </style>
    </head>
    <body>
      <h1>Invoice 2026-118</h1>
      <p>Bill to: Example Co., 100 Main Street, Springfield</p>
      <table>
        <tr><th>Item</th><th>Amount</th></tr>
        <tr><td>Support hours</td><td>$950.00</td></tr>
      </table>
    </body>
    </html>
    """;

using FileStream file = File.Create("invoice.pdf");
var options = new HtmlPdfOptions { Page = PdfPageSetup.Letter };
HtmlPdfResult result = HtmlPdf.ToPdf(html, file, options);
Console.WriteLine($"pages {result.PageCount}, warnings {result.Diagnostics.Count}");
```

```text
pages 1, warnings 0
```

The title and language come from `<title>` and `<html lang>`, the heading and table are tagged for screen readers, and the text is set in fonts that come with the package. For an HTML file, pass `File.ReadAllText("page.html")`, and set `BaseUrl` so its images and style sheets are found.

Scripts don’t run, so render the final HTML first, for example from a Razor view. What OneRender supports, from `@page` rules to page breaks, is in its [HTML to PDF recipe](https://recursiveai.org/onerender/cookbook/html-to-pdf/).

## An image to PDF

Make an empty document, add a page the size of the image, and draw the image on it:

```shell
curl -o logo.png https://recursiveai.org/assets/brand/icon-512.png
```

```csharp
using OnePdf;

using PdfDocument doc = PdfDocument.CreateEmpty();
// AddJpegImage for a JPEG
PdfCreatedImage image = doc.AddPngImage(File.ReadAllBytes("logo.png"));

// The page is the image's size at 96 pixels per inch.
// PDF sizes are in points, 72 per inch.
double width = image.Width * 72.0 / 96, height = image.Height * 72.0 / 96;
PdfPage page = doc.InsertBlankPage(0, width, height);
using (PdfPageContentBuilder b = page.BeginContent())
{
    b.DrawImage(image, 0, 0, width, height);
    b.Commit();
}

doc.Save("logo.pdf");
Console.WriteLine($"logo.pdf: one page, {width} x {height} points");
```

```text
logo.pdf: one page, 384 x 384 points
```

A JPEG is embedded as it is, without recompressing; a PNG is stored losslessly with its transparency. For several images, insert one page per image. To put the image on a standard page with margins, see [Create a PDF](https://recursiveai.org/onepdf/cookbook/create-pdf/), whose layout takes `Image(bytes)`.

## Content you generate in code

For reports, invoices and letters built from your data, describe the document with OnePdf.Layout:

```shell
dotnet add package RecursiveAI.OnePdf.Layout --version 1.15.0
```

```csharp
using OnePdf.Layout;

LayoutDocument.Compose(doc =>
{
    doc.Title("Report").Language("en-US");
    doc.Page(page =>
    {
        page.Size(PageSize.A4);
        page.Margin(54);
        page.Content().Column(col =>
        {
            col.Spacing(8);
            col.Item().Text("Quarterly report").FontSize(20).Bold();
            col.Item().Text("Revenue grew 12% on the previous quarter.");
        });
    });
}).Save("report.pdf");

Console.WriteLine("Saved report.pdf");
```

```text
Saved report.pdf
```

Tables that break across pages, headers, page numbers and logos are in [Create a PDF](https://recursiveai.org/onepdf/cookbook/create-pdf/) and [Generate a PDF table](https://recursiveai.org/onepdf/cookbook/generate-tables/).

## Limits

- **No Word, Excel or PowerPoint.** These libraries don’t read Office files. Convert them with Office itself or LibreOffice, or rebuild the content as HTML or layout code.
- **HTML without JavaScript.** Pages that build their content with scripts need to be rendered to final HTML first.
- **.NET 10.** All three packages target .NET 10.

To archive the result, see [Convert a PDF to PDF/A](https://recursiveai.org/onepdf/cookbook/convert-pdf-to-pdfa/); for accessible output, [Create an accessible PDF](https://recursiveai.org/onepdf/cookbook/create-pdf-ua/).
