Reduce File Size with Base64 Image Headers and Footers

Adding a Base64 image to a header or footer on a large multi-page PDF can inflate the output file dramatically. The fix is to embed the image once instead of on every page, while still letting per-page text like {page} render normally.

The bloat happens because of how the renderer handles a combined fragment. When a single fragment holds both the image and dynamic content such as {page}, the engine treats all of the HTML as dynamic and re-embeds the Base64 image on every page. Splitting the work into two passes keeps the image static and the page-number layer small.

Solution

Separate the content into a static fragment and a dynamic one. Put the image and any text that never changes in the static fragment. Put per-page content such as {page} in the dynamic fragment. Give both fragments the same table layout and cell widths so the dynamic text lands correctly over the static layer.

2. Add the static fragment first

Call AddHtmlHeadersAndFooters with only the static fragment. The Base64 image is rendered and embedded a single time.

3. Add the dynamic fragment in a second pass

Call AddHtmlHeadersAndFooters again with only the dynamic fragment. Since this pass carries no image, the per-page content stays small.

using IronPdf;

var pdf = PdfDocument.FromFile("input.pdf");

// Static layer: holds the Base64 image. The page-number cell is left empty.
string staticFooter = @"
<table style='width:100%; table-layout:fixed;'>
  <tr>
    <td style='width:20%;'>
      <img src='data:image/png;base64,iVBORw0KGg...' style='width:150px;' />
    </td>
    <td style='width:80%; text-align:right;'></td>
  </tr>
</table>";

// Dynamic layer: holds only {page}. Same layout, but no image.
string dynamicFooter = $@"
<table style='width:100%; table-layout:fixed;'>
  <tr>
    <td style='width:20%;'></td>
    <td style='width:80%; text-align:right; font-size:10px;'>Page {{page}} of {pdf.PageCount}</td>
  </tr>
</table>";

// Pass 1: add the static image footer (image embedded once).
pdf.AddHtmlHeadersAndFooters(new ChromePdfRenderOptions
{
    HtmlFooter = new HtmlHeaderFooter { HtmlFragment = staticFooter, MaxHeight = 40 }
});

// Pass 2: add the dynamic page-number footer (no image, stays small).
pdf.AddHtmlHeadersAndFooters(new ChromePdfRenderOptions
{
    HtmlFooter = new HtmlHeaderFooter { HtmlFragment = dynamicFooter, MaxHeight = 40 }
});

pdf.SaveAs("output.pdf");
using IronPdf;

var pdf = PdfDocument.FromFile("input.pdf");

// Static layer: holds the Base64 image. The page-number cell is left empty.
string staticFooter = @"
<table style='width:100%; table-layout:fixed;'>
  <tr>
    <td style='width:20%;'>
      <img src='data:image/png;base64,iVBORw0KGg...' style='width:150px;' />
    </td>
    <td style='width:80%; text-align:right;'></td>
  </tr>
</table>";

// Dynamic layer: holds only {page}. Same layout, but no image.
string dynamicFooter = $@"
<table style='width:100%; table-layout:fixed;'>
  <tr>
    <td style='width:20%;'></td>
    <td style='width:80%; text-align:right; font-size:10px;'>Page {{page}} of {pdf.PageCount}</td>
  </tr>
</table>";

// Pass 1: add the static image footer (image embedded once).
pdf.AddHtmlHeadersAndFooters(new ChromePdfRenderOptions
{
    HtmlFooter = new HtmlHeaderFooter { HtmlFragment = staticFooter, MaxHeight = 40 }
});

// Pass 2: add the dynamic page-number footer (no image, stays small).
pdf.AddHtmlHeadersAndFooters(new ChromePdfRenderOptions
{
    HtmlFooter = new HtmlHeaderFooter { HtmlFragment = dynamicFooter, MaxHeight = 40 }
});

pdf.SaveAs("output.pdf");
Imports IronPdf

Dim pdf = PdfDocument.FromFile("input.pdf")

' Static layer: holds the Base64 image. The page-number cell is left empty.
Dim staticFooter As String = "
<table style='width:100%; table-layout:fixed;'>
  <tr>
    <td style='width:20%;'>
      <img src='data:image/png;base64,iVBORw0KGg...' style='width:150px;' />
    </td>
    <td style='width:80%; text-align:right;'></td>
  </tr>
</table>"

' Dynamic layer: holds only {page}. Same layout, but no image.
Dim dynamicFooter As String = $"
<table style='width:100%; table-layout:fixed;'>
  <tr>
    <td style='width:20%;'></td>
    <td style='width:80%; text-align:right; font-size:10px;'>Page {{page}} of {pdf.PageCount}</td>
  </tr>
</table>"

' Pass 1: add the static image footer (image embedded once).
pdf.AddHtmlHeadersAndFooters(New ChromePdfRenderOptions With {
    .HtmlFooter = New HtmlHeaderFooter With {.HtmlFragment = staticFooter, .MaxHeight = 40}
})

' Pass 2: add the dynamic page-number footer (no image, stays small).
pdf.AddHtmlHeadersAndFooters(New ChromePdfRenderOptions With {
    .HtmlFooter = New HtmlHeaderFooter With {.HtmlFragment = dynamicFooter, .MaxHeight = 40}
})

pdf.SaveAs("output.pdf")
$vbLabelText   $csharpLabel

The two table-layout:fixed fragments share identical cell widths, so the page number in the second pass sits exactly where the empty cell was in the first. The same technique applies to headers: keep the image in the static pass, and place any dynamic header text in the second pass.

WarningIf both fragments do not share the same table structure and cell widths, the dynamic text such as the page number will not line up over the static layer.

Option: Reference an external image or SVG

If you do not need the image inlined as Base64, pointing the <img> at an external file or using an SVG can shrink the output size further than a Base64 string.

Curtis Chau
Technical Writer

Curtis Chau holds a Bachelor’s degree in Computer Science (Carleton University) and specializes in front-end development with expertise in Node.js, TypeScript, JavaScript, and React. Passionate about crafting intuitive and aesthetically pleasing user interfaces, Curtis enjoys working with modern frameworks and creating well-structured, visually appealing manuals.

...

Read More
Ready to Get Started?
Nuget Downloads 19,820,650 | Version: 2026.7 just released
Still Scrolling Icon

Still Scrolling?

Want proof fast? PM > Install-Package IronPdf
run a sample watch your HTML become a PDF.