DEV Community

IronSoftware
IronSoftware

Posted on

Data URIs for PDF Images in C# (.NET Guide)

External images in HTML-to-PDF conversion can fail silently—wrong paths, network issues, permission problems. Data URIs solve this by embedding images directly in your HTML as Base64 strings.

using IronPdf;
// Install via NuGet: Install-Package IronPdf

byte[] imageBytes = File.ReadAllBytes("logo.png");
string base64 = Convert.ToBase64String(imageBytes);
string dataUri = $"data:image/png;base64,{base64}";

var html = $@"
    <html>
    <body>
        <img src='{dataUri}' width='200'>
        <h1>Invoice</h1>
    </body>
    </html>";

var renderer = new [ChromePdfRenderer](https://ironpdf.com/blog/videos/how-to-render-html-string-to-pdf-in-csharp-ironpdf/)();
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("invoice.pdf");
Enter fullscreen mode Exit fullscreen mode

The image travels with the HTML. No external files to resolve, no paths to configure.

Why Use Data URIs in PDFs?

External image references break for several reasons:

  • Relative paths - The PDF renderer doesn't know your working directory
  • File permissions - Server can't access local paths
  • Network latency - Remote images slow down rendering
  • Missing assets - Files deleted or moved after development

Data URIs eliminate these failure modes. The image data is part of the HTML string itself.

How Do I Convert an Image to Data URI?

The pattern is: data:[mime-type];base64,[encoded-data]

using IronPdf;
// Install via NuGet: Install-Package IronPdf

public static string ImageToDataUri(string filePath)
{
    byte[] bytes = File.ReadAllBytes(filePath);
    string base64 = Convert.ToBase64String(bytes);

    // Determine MIME type from extension
    string extension = Path.GetExtension(filePath).ToLower();
    string mimeType = extension switch
    {
        ".png" => "image/png",
        ".jpg" or ".jpeg" => "image/jpeg",
        ".gif" => "image/gif",
        ".svg" => "image/svg+xml",
        ".webp" => "image/webp",
        _ => "application/octet-stream"
    };

    return $"data:{mimeType};base64,{base64}";
}
Enter fullscreen mode Exit fullscreen mode

Use this helper throughout your PDF generation code:

var logoDataUri = ImageToDataUri("assets/logo.png");
var signatureDataUri = ImageToDataUri("signatures/john-doe.png");

var html = $@"
    <img src='{logoDataUri}'>
    <p>Signed by:</p>
    <img src='{signatureDataUri}'>";
Enter fullscreen mode Exit fullscreen mode

How Do I Embed Images from URLs?

Download remote images and convert them:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

public static async Task<string> UrlToDataUri(string imageUrl)
{
    using var client = new HttpClient();
    byte[] bytes = await client.GetByteArrayAsync(imageUrl);

    // Get MIME type from URL or response
    string extension = Path.GetExtension(new Uri(imageUrl).AbsolutePath);
    string mimeType = extension.ToLower() switch
    {
        ".png" => "image/png",
        ".jpg" or ".jpeg" => "image/jpeg",
        ".gif" => "image/gif",
        _ => "image/png"
    };

    string base64 = Convert.ToBase64String(bytes);
    return $"data:{mimeType};base64,{base64}";
}

// Usage
var avatarDataUri = await UrlToDataUri("https://example.com/user/avatar.png");
Enter fullscreen mode Exit fullscreen mode

This pre-fetches images, so PDF rendering doesn't depend on network availability.

How Do I Handle Multiple Images?

For documents with many images, build a dictionary of data URIs:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var imageFolder = @"C:\reports\images";
var images = new Dictionary<string, string>();

foreach (var file in Directory.GetFiles(imageFolder, "*.png"))
{
    var filename = Path.GetFileName(file);
    images[filename] = ImageToDataUri(file);
}

// Use in HTML template
var html = $@"
    <img src='{images["header.png"]}'>
    <img src='{images["chart-q1.png"]}'>
    <img src='{images["chart-q2.png"]}'>
    <img src='{images["footer.png"]}'>";

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
Enter fullscreen mode Exit fullscreen mode

Pre-converting all images avoids repeated disk reads.

What Are the Size Limits?

Base64 encoding increases data size by roughly 33%. A 1MB image becomes ~1.33MB as Base64.

Browser limits (which affect PDF renderers):

  • Chromium/Firefox: 512MB per data URI
  • Safari/WebKit: 2GB per data URI

For practical PDF generation, keep individual images under 10MB. Larger images should be resized or compressed first.

How Do I Compress Images Before Embedding?

Reduce PDF size by compressing images:

using System.Drawing;
using System.Drawing.Imaging;
using IronPdf;
// Install via NuGet: Install-Package IronPdf

public static string CompressAndEmbed(string imagePath, int quality = 75)
{
    using var original = Image.FromFile(imagePath);
    using var stream = new MemoryStream();

    // Set JPEG quality
    var encoder = ImageCodecInfo.GetImageEncoders()
        .First(c => c.FormatID == ImageFormat.Jpeg.Guid);
    var encoderParams = new EncoderParameters(1);
    encoderParams.Param[0] = new EncoderParameter(
        System.Drawing.Imaging.Encoder.Quality, (long)quality);

    original.Save(stream, encoder, encoderParams);

    string base64 = Convert.ToBase64String(stream.ToArray());
    return $"data:image/jpeg;base64,{base64}";
}
Enter fullscreen mode Exit fullscreen mode

A quality setting of 75-80 typically reduces file size by 60-70% with minimal visual impact.

How Do I Embed CSS Background Images?

Data URIs work in CSS too:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

var backgroundDataUri = ImageToDataUri("background-pattern.png");

var html = $@"
    <html>
    <head>
        <style>
            body {{
                background-image: url('{backgroundDataUri}');
                background-repeat: repeat;
            }}
            .watermark {{
                background-image: url('{ImageToDataUri("watermark.png")}');
                opacity: 0.3;
            }}
        </style>
    </head>
    <body>
        <h1>Document Title</h1>
    </body>
    </html>";

var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PrintHtmlBackgrounds = true;
var pdf = renderer.RenderHtmlAsPdf(html);
Enter fullscreen mode Exit fullscreen mode

Remember to enable PrintHtmlBackgrounds for background images to appear.

How Do I Embed Fonts as Data URIs?

Custom fonts can be embedded the same way:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

byte[] fontBytes = File.ReadAllBytes("fonts/CustomFont.woff2");
string fontBase64 = Convert.ToBase64String(fontBytes);

var html = $@"
    <html>
    <head>
        <style>
            @font-face {{
                font-family: 'CustomFont';
                src: url('data:font/woff2;base64,{fontBase64}') format('woff2');
            }}
            body {{
                font-family: 'CustomFont', sans-serif;
            }}
        </style>
    </head>
    <body>
        <p>Text in custom font</p>
    </body>
    </html>";
Enter fullscreen mode Exit fullscreen mode

This ensures the font renders correctly regardless of what's installed on the server.

What About Performance?

Data URIs trade network requests for larger HTML payloads:

Advantages:

  • No HTTP requests during rendering
  • Guaranteed asset availability
  • Simpler deployment (no asset folders)
  • Works in memory-only scenarios

Disadvantages:

  • Larger HTML string size
  • No browser caching (irrelevant for PDF generation)
  • Initial encoding overhead

For PDF generation, the advantages usually win. You're rendering once, not serving repeatedly.

How Do I Debug Missing Images?

If images aren't appearing:

using IronPdf;
// Install via NuGet: Install-Package IronPdf

// Verify the data URI is valid
var dataUri = ImageToDataUri("test.png");
Console.WriteLine($"Data URI length: {dataUri.Length}");
Console.WriteLine($"Starts with: {dataUri.Substring(0, 50)}...");

// Test in a simple HTML
var testHtml = $"<img src='{dataUri}' style='border:1px solid red;'>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(testHtml);
pdf.SaveAs("test-image.pdf");
Enter fullscreen mode Exit fullscreen mode

Common issues:

  • Wrong MIME type
  • Corrupted Base64 (check encoding)
  • Missing data: prefix
  • Image too large for renderer

Complete Example: Report with Embedded Assets

using IronPdf;
// Install via NuGet: Install-Package IronPdf

public class ReportGenerator
{
    private readonly Dictionary<string, string> _assets = new();

    public ReportGenerator()
    {
        // Pre-load common assets
        _assets["logo"] = ImageToDataUri("assets/logo.png");
        _assets["footer"] = ImageToDataUri("assets/footer.png");
    }

    public byte[] GenerateReport(ReportData data)
    {
        // Convert report-specific images
        var chartDataUri = ImageToDataUri(data.ChartPath);

        var html = $@"
            <html>
            <body>
                <img src='{_assets["logo"]}' class='logo'>
                <h1>{data.Title}</h1>
                <img src='{chartDataUri}' class='chart'>
                <div class='content'>{data.Body}</div>
                <img src='{_assets["footer"]}' class='footer'>
            </body>
            </html>";

        var renderer = new ChromePdfRenderer();
        var pdf = renderer.RenderHtmlAsPdf(html);
        return pdf.BinaryData;
    }

    private static string ImageToDataUri(string path)
    {
        var bytes = File.ReadAllBytes(path);
        var ext = Path.GetExtension(path).ToLower();
        var mime = ext == ".png" ? "image/png" : "image/jpeg";
        return $"data:{mime};base64,{Convert.ToBase64String(bytes)}";
    }
}
Enter fullscreen mode Exit fullscreen mode

Data URIs make PDF generation self-contained. Your HTML carries everything it needs to render correctly.

For more details on asset handling, see the IronPDF Data URI documentation.


Written by Jacob Mellor, CTO at Iron Software. Jacob created IronPDF and leads a team of 50+ engineers building .NET document processing libraries.

Top comments (0)