---
title: "Convert HTML to PNG"
url: https://recursiveai.org/onerender/cookbook/html-to-png/
description: "Render HTML and CSS to a PNG in C# with OneRender: a 1200 by 630 social card with a gradient and a logo, and a badge on a transparent background at three…"
version: "1.0.0"
---

# Convert HTML to PNG

Render HTML and CSS to a PNG in C# with OneRender: a 1200 by 630 social card with a gradient and a logo, and a badge on a transparent background at three times the pixel density.

```csharp
using OneRender.Image;
using OneRender.Painting;

string title = "Shipping weekly: 444 orders";
string html = $$"""
<!DOCTYPE html>
<html lang="en">
<style>
  body { margin: 0; width: 1200px; height: 630px; display: flex; flex-direction: column; justify-content: space-between;
         box-sizing: border-box; padding: 72px; font-family: sans-serif; color: #fff;
         background: linear-gradient(135deg, #16202c, #1d4ed8) }
  h1 { font-size: 64px; line-height: 1.1; margin: 0; max-width: 900px }
  footer { display: flex; align-items: center; gap: 20px; font-size: 28px; opacity: .85 }
</style>
<body>
  <h1>{{System.Net.WebUtility.HtmlEncode(title)}}</h1>
  <footer><img src="logo.png" width="64" height="64" alt=""> example.com/blog</footer>
</body>
</html>
""";

RgbaImage card = HtmlRender.ToImage(html, new HtmlRenderOptions
{
    Width = 1200,
    Height = 630,
    BaseUrl = "file:///cards/",
    Resources = url => url == "file:///cards/logo.png" ? File.ReadAllBytes("logo.png") : null,
});
File.WriteAllBytes("card.png", card.ToPng());
Console.WriteLine($"card.png: {card.Width}x{card.Height}");

// A badge on a transparent background, at 3x for high-density screens.
RgbaImage badge = HtmlRender.ToImage(
    "<body style='margin:0'><span style='display:inline-block;padding:4px 10px;border-radius:999px;background:#16a34a;color:#fff;font:600 14px sans-serif'>Passing</span>",
    new HtmlRenderOptions { Width = 80, Height = 27, DevicePixelRatio = 3, PageColor = PaintColor.Transparent });
File.WriteAllBytes("badge.png", badge.ToPng());
Console.WriteLine($"badge.png: {badge.Width}x{badge.Height}, corner alpha {badge.Pixels[3]}");
```

```text
card.png: 1200x630
badge.png: 240x81, corner alpha 0
```

## The options

- **`Width` and `Height`** are the viewport in CSS pixels, from 1 to 16,384. The image shows exactly the viewport; content below it is cut off. To capture a whole page, measure it first: see [Replace a headless browser](https://recursiveai.org/onerender/cookbook/replace-headless-browser/#full-page-screenshots).
- **`DevicePixelRatio`** scales the pixels, not the layout: the badge is laid out at 80 by 27 and drawn at 240 by 81.
- **`PageColor`** is painted where the document paints no background. The default is opaque white; `PaintColor.Transparent` leaves those pixels clear.
- **`Resources`** supplies images, style sheets and fonts by absolute address, and `BaseUrl` is what relative references resolve against. The engine fetches nothing itself.
- **`AnimationTime`** shows CSS animations and transitions as they look that many milliseconds in. Without it, the page is drawn with no animation applied.

## The image

`RgbaImage` holds `Width * Height * 4` bytes of 8-bit RGBA in `Pixels`, row by row from the top left, ready to hand to another library or a texture upload. `ToPng()` encodes it.

## Good to know

- Images in the page are decoded by OneImage (PNG, JPEG, WebP, GIF, TIFF, BMP and ICO), and inline `<svg>` is drawn. An `<img>` pointing to an SVG file isn’t drawn in 1.0.0; inline the SVG instead.
- Rendering is deterministic: the same HTML, resources and fonts give the same pixels on every machine, so snapshot tests can compare bytes.
- Text uses the bundled fonts unless you add more: see [Fonts](https://recursiveai.org/onerender/cookbook/fonts/).

The rasterizer and everything it draws are described in [the overview](https://recursiveai.org/onerender/docs/overview/) and [the display list](https://recursiveai.org/onerender/docs/display-list/).
