Recursive AI

Convert SVG to PNG in C#

All oneimage recipes

Add the RecursiveAI.OneImage.Svg package, register SvgFormat in the load options, load the SVG and save it as .png. Put a Resize right after the load and the SVG is drawn at that size, not drawn small and scaled up. The program below converts Wikimedia’s public-domain flag of the United States.

Terminal
dotnet new console -o SvgToPng && cd SvgToPng
dotnet add package RecursiveAI.OneImage.Svg --version 1.10.4
curl -L -o flag.svg \
  https://commons.wikimedia.org/wiki/Special:FilePath/Flag_of_the_United_States.svg

OneImage needs the .NET 10 SDK. Put this in Program.cs and run dotnet run:

C#
using OneImage;
using OneImage.Svg;
 
// SVG is an add-on format: register it for the load.
var options = new LoadOptions
{
    Configuration = new ImageConfiguration().Add(SvgFormat.Instance),
};
 
Image svg = Image.Load("flag.svg", options);
Console.WriteLine($"natural size: {svg.Width}x{svg.Height}");
 
svg.Save("flag.png");                              // at its natural size
svg.Resize(width: 2400).Save("flag-2400.png");     // drawn at 2400 px wide
 
ImageInfo big = Image.Identify("flag-2400.png");
Console.WriteLine($"flag-2400.png: {big.Width}x{big.Height}");
Text
natural size: 1235x650
flag-2400.png: 2400x1263

The natural size comes from the root element’s width and height (here 1235 and 650), or from the viewBox when they are missing. Areas the SVG doesn’t paint are transparent; for JPEG, add .Flatten(new Rgba32(255, 255, 255, 255)) before saving. .webp, .jpg and .ico work the same way, so one SVG makes every app icon size.

An SVG string, with text in your own font

SVG is a handy way to generate badges and charts. Load the markup’s bytes, and give the renderer the fonts you ship, so the text looks the same on every machine, including containers with no fonts installed:

Terminal
fonts=https://github.com/notofonts/notofonts.github.io/raw/main/fonts
curl -L -o NotoSans-Regular.ttf $fonts/NotoSans/hinted/ttf/NotoSans-Regular.ttf
C#
using System.Text;
using OneImage;
using OneImage.Svg;
 
var fonts = new SvgFontOptions { UseSystemFonts = false };
fonts.AddFont("NotoSans-Regular.ttf");
var options = new LoadOptions
{
    Configuration = new ImageConfiguration()
        .Add(new SvgFormat(SvgLimits.Default, ["en"], fonts)),
};
 
string svg = """
    <svg xmlns="http://www.w3.org/2000/svg" width="200" height="40">
      <rect width="200" height="40" rx="6" fill="#2f6b4f"/>
      <text x="100" y="26" font-family="Noto Sans" font-size="16"
            fill="#fff" text-anchor="middle">build passing</text>
    </svg>
    """;
 
Image badge = Image.Load(Encoding.UTF8.GetBytes(svg), options).Resize(width: 600);
badge.Save("badge.png");
Console.WriteLine($"badge.png: {badge.Width}x{badge.Height}");
Text
badge.png: 600x120

AddFont takes TrueType, OpenType, collections, WOFF and WOFF2. With UseSystemFonts left on, installed fonts are used too.

Limits

  • Static SVG only. SMIL animation is ignored (you get the first frame), and scripts and foreignObject are skipped. The SVG docs list what renders: shapes, gradients, patterns, clip paths, masks, filters, CSS and embedded images.
  • Nothing external is fetched. Links to other files or URLs are treated as missing, and DTDs are rejected, so user uploads are safe to convert; size limits apply as the file is read.
  • No fonts are bundled. In a container without fonts, text needs AddFont.

For PDF pages, see Convert a PDF to an image; for smaller output, Convert to WebP.