Recursive AI

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

All onepdf recipes

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:

Terminal
dotnet new console -o SaveAsPdf && cd SaveAsPdf
dotnet add package RecursiveAI.OneRender.Pdf --version 1.3.1
dotnet add package RecursiveAI.OnePdf --version 1.14.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:

C#
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.

An image to PDF

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

Terminal
curl -o logo.png https://recursiveai.org/assets/brand/icon-512.png
C#
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, 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:

Terminal
dotnet add package RecursiveAI.OnePdf.Layout --version 1.14.0
C#
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 and Generate a PDF table.

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; for accessible output, Create an accessible PDF.