Migrating an HTML to PDF integration from Classic to Next
The class is still called HtmlToPdfConverter and the shape of a conversion (create, set options, call ConvertUrl or ConvertHtml) is the same. The rendering engine behind it is what changes and with it the way the PDF page is sized and the way headers and footers are described. This guide lists the differences you will actually hit, with the Classic and Next code side by side. Your existing HTML to PDF license covers both editions.
What stays the same
The conversion calls
ConvertUrl(url),ConvertHtml(html, baseUrl), the…ToFilevariants- One converter instance per conversion
ConversionDelay,NavigationTimeout
The option groups
HtmlViewerWidth,HtmlViewerHeight,HtmlViewerZoomPdfDocumentOptionswithPdfPageSize,PdfPageOrientation, margins in points- Security, viewer preferences, digital signatures
Licensing
- The HTML to PDF license and the Toolkit license cover Classic and Next
- Same key, set in a different place (see below)
- Demo mode without a key, with watermarked output
Authentication, redirects and cookies
- Pages behind a login: Convert HTML Pages with Authentication
- Custom headers and cookies are set on the converter as before; check the property names in the API reference
Packages, namespace, license key
Replace the Classic package with the Next package for your deployment target, change the using and move the license key from the converter instance to the static Licensing class.
using EvoPdf; var converter = new HtmlToPdfConverter(); converter.LicenseKey = "…"; converter.ConversionDelay = 2; byte[] pdf = converter.ConvertUrl(url);
using EvoPdf.Next; Licensing.LicenseKey = "…"; // once per process var converter = new HtmlToPdfConverter(); converter.ConversionDelay = 2; byte[] pdf = converter.ConvertUrl(url);
EvoPdf.Next.HtmlToPdf.Windows, .Linux, .MacOS, or the .Arm64 variants. Windows and macOS need nothing else; on Linux a few system packages are required; see Getting Started on Linux. Classic runs on Windows only.The page sizing model is different
This is the change most likely to alter the look of your PDFs, because the two editions start from opposite defaults.
HtmlViewerWidth is the browser window width in pixels and the HTML is laid out at that width. The PDF page is PdfPageSize (A4 by default) and, because FitWidth is true by default, the rendered content is scaled down to fit the fixed page width. With FitWidth = false, AutoSizePdfPage instead grows the page to show the content unscaled; ClipHtmlView forces the content to exactly the viewer width.
converter.HtmlViewerWidth = 1024; converter.PdfDocumentOptions.PdfPageSize = PdfPageSize.A4; converter.PdfDocumentOptions.FitWidth = true; // default converter.PdfDocumentOptions.AutoSizePdfPage = true;
HtmlViewerWidth (default 1024 px) is again the browser window width. By default the page is a fixed A4 with that window scaled to it: the HTML is laid out at 1024 pixels and drawn at 77.47 percent, the same scale Classic applied, so a new converter gives the Classic output with no settings. FitBrowserWindowToPage(PdfPageSize.A4) makes the same settings explicitly, for another page size or after changing the margins. With AutoResizePdfPageWidth = true the page instead follows the window: HtmlViewerWidth × 0.75 points wide (768 pt for 1024 px) with the HTML drawn 1:1, the PageWidthFromBrowserWindow layout.
// the default: an A4 page, the 1024 px window // scaled to it at 77.47 percent converter.FitBrowserWindowToPage(PdfPageSize.A4); // another page size and orientation converter.FitBrowserWindowToPage(PdfPageSize.Letter, PdfPageOrientation.Landscape); // the page follows the window, content drawn 1:1 converter.PageWidthFromBrowserWindow(1024);
Pages wider than the browser window
Classic scaled the rendering to the width the HTML actually had, so a 1024 pixel layout on A4 came out at 78 percent and a 1600 pixel page at 50 percent. Next scales the browser window, 1024 pixels by default, which gives the same result for a page designed for a desktop screen. Content wider than the window is laid out at its own width and scaled to the page, so nothing is cut; for a 1:1 rendering, give the window the width of the page. A 1600 pixel page on A4 therefore needs FitBrowserWindowToPage(PdfPageSize.A4, PdfPageOrientation.Portrait, 1600), zoom 49.58, or a page as wide as the content with PageWidthFromBrowserWindow(1600).
Practical rule
Decide once whether you want the content to follow the page (the default, FitBrowserWindowToPage with a standard PdfPageSize) or the page to follow the content (PageWidthFromBrowserWindow). When replacing Classic, the default is the answer: it reproduces the Classic page size, layout width and scale, so your users see what they see today. HTML templates designed for A4 or Letter use LayoutAtPageWidth instead and are laid out 1:1. PageWidthFromBrowserWindow(1024, singlePage: true) is the Next equivalent of the Classic single-page output. Compare a few documents before switching. The zoom values for other page sizes and margins are in HTML to PDF Page Setup and Scaling and the full comparison in Migrate HTML to PDF Page Setup and Headers from EvoPdf Classic.
Headers and footers are described as HTML, not drawn as elements
In Classic a header is a container you add elements to (HtmlToPdfElement, TextElement, LineElement), with per-page visibility decided in the PrepareRenderPdfPageEvent handler. In Next a header is an HTML document with its own options object; page numbers are variables inside that HTML and per-page visibility is three booleans.
converter.PdfDocumentOptions.ShowHeader = true; converter.PdfHeaderOptions.HeaderHeight = 60; converter.PdfHeaderOptions.HeaderBackColor = Color.White; HtmlToPdfElement headerHtml = new HtmlToPdfElement(headerUrl); headerHtml.FitHeight = true; converter.PdfHeaderOptions.AddElement(headerHtml); // line under the header LineElement line = new LineElement(0, 59, headerWidth, 59); line.ForeColor = Color.Gray; converter.PdfHeaderOptions.AddElement(line); // page numbers: a TextElement with &p; and &P; placeholders converter.PdfFooterOptions.AddElement( new TextElement(0, 20, "Page &p; of &P;", font)); // hide on the first page, from an event handler converter.PrepareRenderPdfPageEvent += (p) => { if (p.PageNumber == 1) p.Page.ShowHeader = false; };
var header = converter.PdfDocumentOptions.PdfHtmlHeader; // or header.Html with header.HtmlBaseUrl header.HtmlSourceUrl = headerUrl; // or header.AutoSizeContentHeight = true header.Height = 60; header.FitHeight = true; // make room in the top margin header.AutoResizePdfMargins = true; // line under the header: CSS in the header HTML // page numbers: variables in the footer HTML var footer = converter.PdfDocumentOptions.PdfHtmlFooter; footer.Html = "<div style=\"text-align:center\">" + "Page {page_number} of {total_pages}</div>"; // per-page visibility: no event handler header.ShowInFirstPage = false; header.ShowInOddPages = true; header.ShowInEvenPages = true; // keep the space on the pages without header header.ReserveSpaceAlways = true;
TextElement, ImageElement or LineElement becomes markup in the header or footer HTML. Header and footer HTML is rendered by the same engine as the page, so web fonts, CSS and images work there too. Full sample: HTML Header and Footer with Page Numbers.Option map
| Classic | Next | Note |
|---|---|---|
using EvoPdf; | using EvoPdf.Next; | Namespace |
converter.LicenseKey | Licensing.LicenseKey | Static, set once |
PdfDocumentOptions.FitWidth = true (default) | FitBrowserWindowToPage(PdfPageSize.A4) (default) | Fixed page width, the 1024 pixel layout scaled to it, zoom 77.47 on A4 and 79.69 on Letter |
PdfDocumentOptions.AutoSizePdfPage | PageWidthFromBrowserWindow() | Page width follows the viewer width, content drawn 1:1 |
PdfDocumentOptions.SinglePage | PageWidthFromBrowserWindow(1024, singlePage: true) | Whole content on one page |
PdfDocumentOptions.ShowHeader + PdfHeaderOptions | PdfDocumentOptions.PdfHtmlHeader | Same for footer |
PdfHeaderOptions.HeaderHeight | PdfHtmlHeader.Height / AutoSizeContentHeight | Min/Max content height available |
PdfHeaderOptions.AddElement(HtmlToPdfElement) | PdfHtmlHeader.Html or HtmlSourceUrl | One HTML document per header/footer |
TextElement with &p; / &P; | {page_number} / {total_pages} in the HTML | SkipVariablesParsing when not used |
PdfFooterOptions.PageNumberingStartIndex | PdfHtmlFooter.PageNumberOffset / TotalPagesOffset | Offsets for the page counters |
PrepareRenderPdfPageEvent → Page.ShowHeader | PdfHtmlHeader.ShowInFirstPage / ShowInOddPages / ShowInEvenPages | No event handler |
PdfDocumentOptions.TopSpacing | PdfHtmlHeader.Margins | The template margins are part of the header height; with AutoResizePdfMargins the top margin becomes the header height |
StretchToFit | HtmlViewerZoom above 100 | A 600 pixel page fills an A4 page at zoom 132 |
ClipHtmlView | none | Content wider than the browser window is laid out at its own width and scaled to the page (AutoResizeHtmlViewerWidth, true by default) |
Beyond the API: what the new rendering engine changes in layout, fonts, JavaScript and image loading
Both engines render with the screen media type by default and both expose MediaType, so that part does not change. What changes is the engine underneath: Next renders exactly like a current Chrome, so pages look the way your browser shows them and a few things Classic handled its own way now follow the browser.
Layout follows current web standards
- Flexbox, CSS grid, custom properties, modern selectors and ES2015+ JavaScript render as in Chrome. Layouts that carried workarounds for the old engine can drop them and pages that looked "acceptable" only because a rule was ignored may now look different
- Print CSS is honored:
@page,break-before/after/inside,page-break-*, so page breaks you controlled from the API can move into the stylesheet - Content is laid out at 96 DPI in a browser window
HtmlViewerWidthpixels wide, 1024 by default; step 2 shows how that window is placed on the page
Text and fonts
- Font fallback, hinting and metrics are Chrome's. Line breaks and therefore page breaks, can shift by a line compared with Classic output on the same document
- Web fonts (including WOFF2) are downloaded and embedded as subsets; PDFs with many fonts or large images can differ in size from Classic output
- Text stays selectable and searchable; with PDF/UA output it is also tagged
JavaScript and dynamic content
- Scripts run in a real browser engine: charts, frameworks and async data that the old engine could not execute now render and pages that finish loading late need
ConversionDelayorTriggeringMode, as before JavaScriptEnabled,NavigationTimeoutandHtmlViewerWidthkeep their role
Resources and security defaults
- Lazy-loaded images are fetched by default (
LoadLazyImages); images that the old engine skipped will appear - Local files, insecure content and blocked hosts are governed by explicit options (
LocalFilesEnabledand the template-level equivalents). Check them if your HTML references file paths or mixed content - Sites served only over HTTP/2 or TLS 1.3 load directly; no need to download the HTML yourself and convert it as a string, as some Classic integrations did
Suggested order: run the Next demo application on your own pages first (online or the downloaded project), settle the page sizing options on two or three representative documents, then port the headers and footers. Most integrations need changes in exactly those two places and nowhere else. If you work with an AI coding assistant, the EvoPdf agent skills on GitHub include a migration skill that applies these steps to your code.
Try your pages on the Next engine
The demo application runs without a license key, with a stamp on the output, so you can compare Classic and Next side by side before changing anything in production.