Migrating HTML to PDF from HiQPdf Classic to HiQPdf Next

HiQPdf Next HTML to PDF Converter for .NET Logo

An application can move to HiQPdf Next in two ways: keep its Classic code and run it on the Next engine through the HiQPdf platform packages, or port the code to the native HiQPdf Next API.

Either way the application gets the Chromium rendering engine and runs on every platform HiQPdf Next supports. Your HiQPdf license works with both editions.

Download Now
Online Demo
Documentation

Two Ways to Migrate

Option 1: Keep the Classic Code

  • Replace the HiQPdf or HiQPdf.NG package with the package of your platform: HiQPdf.Windows, HiQPdf.Linux, HiQPdf.MacOS or the .Arm64 variants
  • The HiQPdf namespace, the classes and the members stay the same, so the code compiles and runs as it is
  • The PDF documents keep the Classic page layout
  • The new options of HiQPdf Next, such as PDF/UA and electronic invoices, are available from the Classic code through the Next converter behind each Classic converter
  • Suited to applications with PDF code spread over many projects, or when the move has to be quick

The package change

Option 2: Port the Code to the Next API

  • Replace the Classic package with the HiQPdf Next package of your platform and use the HiQPdf.Next namespace
  • The shape of a conversion stays the same; the changes are in the serial number, the page sizing options and the headers and footers
  • The application uses the native API of HiQPdf Next directly, with all its options
  • Suited to new code and to applications you develop further

The porting steps

The two can be combined. Start with the platform packages and port the code one file at a time: each Classic converter gives access to the HiQPdf Next converter it uses and both produce the PDF as a byte array, so Classic and Next code work side by side in the same application. The Classic library runs on Windows only; with either option the application also runs on Linux (x64 and ARM64) and macOS (Apple Silicon) and directly in Azure App Service for Windows.

Option 1: Keep the Classic Code with the Platform Packages

The HiQPdf.Windows, HiQPdf.Linux and HiQPdf.MacOS packages, with their .Arm64 variants, carry the Classic API with the HiQPdf namespace and render with the engine of HiQPdf Next. Replace the HiQPdf or HiQPdf.NG package with the package of your platform; the code stays as it is and the output keeps the Classic page layout. The porting steps of option 2 are not needed.
Project file
dotnet remove package HiQPdf
dotnet add package HiQPdf.Windows
Classic code with an option of HiQPdf Next
using HiQPdf;

HtmlToPdf converter = new HtmlToPdf();
converter.SerialNumber = "...";
converter.WaitBeforeConvert = 2;

// optional: an option the Classic API has no setting for, set on the HiQPdf Next converter
converter.NextConverterCreated += next =>
    next.Document.PdfStandard = HiQPdf.Next.PdfStandard.PdfUa1;

byte[] pdf = converter.ConvertUrlToMemory(url);
The Classic classes and members are kept. Each converter exposes the HiQPdf Next converter it creates: NextConverterCreated hands it over before each conversion and the Next property holds the converter of the last conversion, so the new options, such as PDF/UA or electronic invoices, can be used from the Classic code. The results are plain PDF data, so the Classic code and the native Next API, PdfEditor included, work on the same documents and the application can move to the native API one file at a time. The packages bring the engine of their platform; a multi-platform application references two of them, for example HiQPdf.Windows and HiQPdf.Linux. The Classic demo application on the Next engine shows the packages at work.

Option 2: Port the Code to the Next API

The class is still called HtmlToPdf and a conversion has the same shape: create the converter, set the options, call ConvertUrlToMemory or ConvertHtmlToMemory. What changes is the way the PDF page is sized and the way headers and footers are described. The three steps below list the differences you will actually hit, with the Classic and Next code side by side. These parts of the code stay the same:

The conversion calls

  • ConvertUrlToMemory(url), ConvertHtmlToMemory(html, baseUrl), ConvertUrlToFile and ConvertHtmlToFile
  • WaitBeforeConvert, TriggerMode and HtmlLoadedTimeout
  • RunJavaScript and MediaType

The option groups

  • BrowserWidth, the browser window width
  • Document with PageSize, PageOrientation and Margins in points
  • Document.Security, Document.Viewer and Document.Properties

Licensing

  • The same license works with HiQPdf Classic and HiQPdf Next
  • Same serial number, set in a different place (see below)
  • Demo mode without a serial number, with a watermark on the output

Authentication, cookies and HTTP headers

  • Pages behind a login: Authentication Handling
  • Authentication, HttpCookies, HttpHeaders and HttpPostFields are set on the converter as before

Option 2 · Step 1: Packages, Namespace and Serial Number

Replace the HiQPdf or HiQPdf.NG package with the Next package for your deployment target, change the using directive and move the serial number from the converter object to the static Licensing class.
HiQPdf Classic
using HiQPdf;

HtmlToPdf converter = new HtmlToPdf();
converter.SerialNumber = "...";
converter.WaitBeforeConvert = 2;
byte[] pdf = converter.ConvertUrlToMemory(url);
HiQPdf Next
using HiQPdf.Next;

Licensing.SerialNumber = "...";   // once per process
HtmlToPdf converter = new HtmlToPdf();
converter.WaitBeforeConvert = 2;
byte[] pdf = converter.ConvertUrlToMemory(url);
HiQPdf Next is a .NET Standard 2.0 library with a platform-specific runtime inside the package: HiQPdf.Next.HtmlToPdf.Windows, .Linux, .MacOS or the .Windows.Arm64 and .Linux.Arm64 variants. Windows and macOS need nothing else; on Linux a few system packages are required, see Getting Started on Linux.
In Next a converter object serves a single conversion, so create a new HtmlToPdf for each call.

Option 2 · Step 2: The Page Sizing Model Is Different

This is the change most likely to alter the look of your PDFs, because the default browser window is narrower in Next and the page layout is chosen with a method instead of a set of flags.

HiQPdf Classic

BrowserWidth is the browser window width in pixels (1200 by default) and the HTML is laid out at that width. The PDF page is Document.PageSize (A4 by default) and, because Document.FitPageWidth is true by default, the rendered content is scaled down to fit the fixed page width: 66.11 percent on A4. With FitPageWidth = false, ResizePageWidth (true by default) instead grows the page to show the content unscaled and PostCardMode puts the whole content on a single page.
converter.BrowserWidth = 1200; // default
converter.Document.PageSize = PdfPageSize.A4;
converter.Document.FitPageWidth = true; // default

// the page follows the content, drawn 1:1
converter.Document.FitPageWidth = false;
converter.Document.ResizePageWidth = true; // default

HiQPdf Next

BrowserWidth is again the browser window width, 1024 pixels by default. 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. Because the Classic window was 1200 pixels wide, a new converter draws the same page a little larger than Classic did: a 16 px font becomes 9.3 points instead of 7.9 points. To keep the Classic output, pass 1200 as the window width of FitBrowserWindowToPage. With PageWidthFromBrowserWindow the page instead follows the window: the window width × 0.75 points wide (900 pt for 1200 px) with the HTML drawn 1:1.
// the default: an A4 page, the 1024 px window
// scaled to it at 77.47 percent
converter.FitBrowserWindowToPage(PdfPageSize.A4,
    PdfPageOrientation.Portrait, 1024);

// the Classic output: the 1200 px window
// scaled to A4 at 66.11 percent
converter.FitBrowserWindowToPage(PdfPageSize.A4,
    PdfPageOrientation.Portrait, 1200);

// the page follows the window, content drawn 1:1
converter.PageWidthFromBrowserWindow(1200);

Pages wider than the browser window

Both editions lay out content wider than the browser window at its own width and scale it to the page, so nothing is cut: Classic unless TrimToBrowserWidth is true, Next unless AutoResizeBrowserWidth is false. A page designed for a fixed width is laid out the same way from the start when the window has that width: a 1600 pixel page on A4 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 (FitBrowserWindowToPage with a standard PdfPageSize) or the page to follow the content (PageWidthFromBrowserWindow). When replacing Classic, FitBrowserWindowToPage with a 1200 pixel window reproduces the Classic page size, layout width and scale, so your users see what they see today; the 1024 pixel default gives slightly larger text. HTML templates designed for A4 or Letter use LayoutAtPageWidth instead and are laid out 1:1. PageWidthFromBrowserWindow(1200, singlePage: true) is the Next equivalent of PostCardMode. 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 HiQPdf Classic.

Option 2 · Step 3: Headers and Footers Are Described as HTML

In Classic a header is a canvas you lay out objects in (PdfHtml, PdfText, PdfLine), with page numbers in a PdfHtmlWithPlaceHolders object and per-page visibility decided in the PageCreatingEvent 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, or the OnPageRendering callback for other rules.
HiQPdf Classic
converter.Document.Header.Enabled = true;
converter.Document.Header.Height = 60;
converter.Document.Header.BackgroundColor = Color.White;

PdfHtml headerHtml = new PdfHtml(headerUrl);
headerHtml.FitDestHeight = true;
converter.Document.Header.Layout(headerHtml);

// line under the header
PdfLine line = new PdfLine(new PointF(0, 59),
    new PointF(headerWidth, 59));
line.ForeColor = Color.Gray;
converter.Document.Header.Layout(line);

// page numbers: {CrtPage} and {PageCount} placeholders
converter.Document.Footer.Enabled = true;
converter.Document.Footer.Height = 40;
converter.Document.Footer.Layout(new PdfHtmlWithPlaceHolders(
    0, 20, "Page {CrtPage} of {PageCount}", null));

// hide on the first page, from an event handler
converter.PageCreatingEvent += (p) =>
    { if (p.PdfPageNumber == 1) p.PdfPage.DisplayHeader = false; };
HiQPdf Next
var header = converter.Document.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, the default
header.AutoResizePdfMargins = true;

// line under the header: CSS in the header HTML

// page numbers: variables in the footer HTML
var footer = converter.Document.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;
Anything you drew with PdfText, PdfImage or PdfLine 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: Add HTML in Header and Footer with Page Numbers.

Option Map

ClassicNextNote
using HiQPdf;using HiQPdf.Next;Namespace
converter.SerialNumberLicensing.SerialNumberStatic, set once
BrowserWidth, 1200 by defaultBrowserWidth, 1024 by defaultPass 1200 to FitBrowserWindowToPage to keep the Classic scale
BrowserHeight (whole document)BrowserHeight, 2048 by defaultNext always renders the whole content; the window height matters only for content loaded on scroll and for single page layouts
BrowserZoom, 100 by defaultBrowserZoomComputed by the layout methods, from 10 to 200; set it only to override them
Document.FitPageWidth = true (default)FitBrowserWindowToPage(PdfPageSize.A4, PdfPageOrientation.Portrait, 1200)Fixed page width, the window scaled to it, zoom 66.11 on A4 and 68.00 on Letter
Document.ForceFitPageWidthFitBrowserWindowToPage(...)A window narrower than the page is enlarged to the page width without another setting
FitPageWidth = false with ResizePageWidthPageWidthFromBrowserWindow(1200)Page width follows the window width, content drawn 1:1
Document.PostCardModePageWidthFromBrowserWindow(1200, singlePage: true)Whole content on one page
Document.FitPageHeightDocument.AutoResizePdfPageHeightThe page grows to the content height instead of scaling the content down
Document.Header.Enabled + Header.Layout(...)Document.PdfHtmlHeader.Html or HtmlSourceUrlThe header exists when it has HTML; the same for the footer
Header.HeightPdfHtmlHeader.Height / AutoSizeContentHeightMinContentHeight and MaxContentHeight limit the automatic height
PdfHtmlWithPlaceHolders with {CrtPage} / {PageCount}{page_number} / {total_pages} in the HTMLSkipVariablesParsing when not used
Header.FirstPageNumber / AdjustPageCountPdfHtmlHeader.PageNumberOffset / TotalPagesOffsetFirstPageNumber = 3 becomes PageNumberOffset = 2
PageCreatingEvent → PdfPage.DisplayHeaderPdfHtmlHeader.ShowInFirstPage / ShowInOddPages / ShowInEvenPagesNo event handler; OnPageRendering for other rules
Document.InsertPdfFileBefore / AppendPdfFileDocument.AddStartPdf / AddEndPdfA file path or a byte array
Document.BreakBeforeHtmlElements, BreakAfterHtmlElements, BreakInsideAvoidHtmlElementsCSS break-before, break-after, break-insidePage breaks are set in the stylesheet
ConvertedHtmlElementSelectorConvertedElementsSelectorSame CSS selector
HiddenHtmlElementsExcludedElementsSelectorThe array of selectors becomes one comma separated selector
TrimToBrowserWidth = trueAutoResizeBrowserWidth = falseThe window keeps its width and content wider than it is cut
MinBrowserHeight, StartBrowserHeightnoneNext always renders the whole content

Engine Behavior

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 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. This applies to both options, the platform packages and the code ported to the Next API.

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 the page breaks you set with BreakBeforeHtmlElements and the related properties move into the stylesheet
  • Content is laid out at 96 DPI in a browser window BrowserWidth pixels 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
  • 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 WaitBeforeConvert or TriggerMode, as before
  • RunJavaScript, HtmlLoadedTimeout and BrowserWidth keep their role
  • The conversion methods have Async variants, such as ConvertUrlToMemoryAsync; ConvertUrlToStream and ConvertUrlToPdfDocument have no Next counterpart, so work with the returned bytes

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 (LocalFilesEnabled, AllowInsecureContent, BlockedHosts). 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: with the platform packages, run your own pages through the Classic demo application on the Next engine and compare a few documents with the Classic output. When porting, 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.

Try Your Pages on the Next Engine

The demo applications run without a serial number, with a stamp on the output, so you can compare Classic and Next side by side before changing anything in production. The Classic demo on the Next engine runs the Classic code on the platform packages and the HiQPdf Next demo uses the Next API.
Download the Classic Demo on the Next engine · Download HiQPdf Next Demo · Online Demo · HTML to PDF in Next