<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: IronSoftware</title>
    <description>The latest articles on DEV Community by IronSoftware (@ironsoftware).</description>
    <link>https://dev.to/ironsoftware</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F714737%2F30e70529-1628-476f-9a14-3b157c0f5c82.png</url>
      <title>DEV Community: IronSoftware</title>
      <link>https://dev.to/ironsoftware</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ironsoftware"/>
    <language>en</language>
    <item>
      <title>Slow Document Loading in Aspose (Issue Fixed)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Wed, 08 Apr 2026 10:35:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/slow-document-loading-in-aspose-issue-fixed-34na</link>
      <guid>https://dev.to/ironsoftware/slow-document-loading-in-aspose-issue-fixed-34na</guid>
      <description>&lt;p&gt;Opening large PDF files with Aspose.PDF can take considerably longer than expected. Developers report that loading a 3000+ page document into memory takes 6x longer than loading the equivalent Word document, while 59MB files require nearly a minute before the first page can even be accessed. For applications that need to process existing PDFs at scale, these loading times create bottlenecks before any actual work begins.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Aspose.PDF's document loading performance degrades significantly with file size. The issue manifests at the very first step of PDF processing: instantiating the &lt;code&gt;Document&lt;/code&gt; class with an existing file. Before any operations like text extraction, page manipulation, or conversion can occur, the entire document structure must be parsed and loaded into memory.&lt;/p&gt;

&lt;p&gt;This creates a fundamental bottleneck that affects every downstream operation. A workflow that needs to extract text from page 5 of a 500-page document must wait for all 500 pages to load first. Applications that batch-process thousands of PDFs spend more time waiting for documents to open than performing actual processing.&lt;/p&gt;

&lt;p&gt;The problem compounds in memory-constrained environments. As Aspose.PDF loads large documents, memory consumption climbs rapidly. Users report that a 20MB PDF can cause memory usage to spike to 1.5GB or higher. When processing multiple large files concurrently, servers can exhaust available RAM, triggering garbage collection cycles that further degrade performance or causing outright crashes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Messages and Symptoms
&lt;/h3&gt;

&lt;p&gt;Large document loading in Aspose.PDF produces measurable symptoms before any exceptions occur:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Document Loading Metrics (Aspose.PDF):

Initial load times:
- 3000+ page PDF: 6x slower than equivalent DOCX in Aspose.Words
- 59MB PDF (18 pages): 48 seconds before first page accessible
- 20MB PDF: Memory spikes to 1.5GB+ during load
- 15MB PDF: Memory reaches 1.5GB with multiple concurrent loads
- ~130MB+ files: StackOverflowException during processing

Memory consumption patterns:
- Without Aspose: ~20% RAM usage
- With Aspose loading large files: 97-99% RAM
- After processing 10,000 documents: 6GB memory accumulated
- Two concurrent large file loads: ~3GB memory usage

Loading operation characteristics:
- Full document loaded to memory before any operation
- No incremental or lazy loading option
- Stream-based loading still requires full memory allocation
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When memory pressure becomes severe, explicit exceptions occur:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.OutOfMemoryException: Exception of type 'System.OutOfMemoryException' was thrown.
   at Aspose.Pdf.Document..ctor(Stream input)

System.StackOverflowException
   (for files greater than approximately 130MB)

ContextSwitchDeadlock detected
   (when merging large PDF files, approximately 2GB each)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;Document loading performance issues in Aspose.PDF impact developers across several scenarios.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Document Processing Services&lt;/strong&gt;: Applications that process existing PDFs for text extraction, data mining, or format conversion face throughput limitations. If loading a document takes 48 seconds, processing 1,000 documents takes over 13 hours just in load time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;PDF Viewing Applications&lt;/strong&gt;: Software that displays PDF content must load documents before rendering. Users waiting nearly a minute to view an 18-page file will find the experience unacceptable, particularly when browsers render the same file instantly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Batch Processing Workflows&lt;/strong&gt;: Enterprise systems handling document archives, legal discovery, or compliance audits process thousands of files. Loading bottlenecks multiply across the batch, turning hour-long jobs into day-long operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory-Constrained Deployments&lt;/strong&gt;: Azure App Service, Docker containers with memory limits, and serverless functions cannot accommodate the memory spikes associated with large document loading. A function allocated 1GB of memory cannot safely process 20MB PDFs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Concurrent Processing Systems&lt;/strong&gt;: Web applications and APIs handling multiple simultaneous requests face cascading failures. Two users uploading 15MB documents simultaneously consume 3GB of memory, potentially exhausting server resources.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linux and Docker Environments&lt;/strong&gt;: Users report that loading performance issues are often more pronounced in containerized environments. Combined with libgdiplus dependencies, Linux deployments face compounded challenges.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence from the Developer Community
&lt;/h2&gt;

&lt;p&gt;Document loading performance complaints have accumulated across Aspose forums and Stack Overflow, indicating a persistent limitation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Mar 2021&lt;/td&gt;
&lt;td&gt;PDF loading 6x slower than equivalent DOCX documented&lt;/td&gt;
&lt;td&gt;Aspose Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Sep 2022&lt;/td&gt;
&lt;td&gt;59MB PDF takes 48 seconds to first page render&lt;/td&gt;
&lt;td&gt;Aspose Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jul 2021&lt;/td&gt;
&lt;td&gt;ASPOSE.PDF very slow on document.save() - includes load time&lt;/td&gt;
&lt;td&gt;Stack Overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jun 2023&lt;/td&gt;
&lt;td&gt;High memory usage on pdf document object reported&lt;/td&gt;
&lt;td&gt;Aspose Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Jan 2025&lt;/td&gt;
&lt;td&gt;Production server impacted by high memory consumption&lt;/td&gt;
&lt;td&gt;Aspose Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Nov 2025&lt;/td&gt;
&lt;td&gt;OUT of memory issue when merging large files&lt;/td&gt;
&lt;td&gt;Aspose Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dec 2025&lt;/td&gt;
&lt;td&gt;Issue with Merging Large PDF Files (OutOfMemory and ContextSwitchDeadlock)&lt;/td&gt;
&lt;td&gt;Aspose Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Community Reports
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"We've noticed that loading PDF documents for conversion (var document = new Aspose.Pdf.Document(stream)) takes considerably longer compared to loading MS Office documents in Aspose.Words. For example, loading a large MS Word document (3000+ pages, text only/no images) is up to 6x faster compared to loading the same document converted to PDF."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developer comparing document loading, Aspose Forums, March 2021&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"A 59MB PDF file with only 18 pages takes a really long time to render using Aspose.PDF.dll. On our fastest machine (AMD Ryzen 7 3800X 8-Core Processor 3.90 GHz with 32 GB Ram), 48 seconds passed before the first page got rendered."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User benchmarking large file performance, Aspose Forums, September 2022&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"Without Aspose.PDF the system needs ~20% of RAM, but when Aspose.PDF starts (noticeable with larger files, ~20MB) it drains all available RAM, reaches 97-99% readings and causes server response issues."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Developer documenting memory impact, Aspose Forums, June 2023&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"When converting bigger files like about 15MB, the memory goes up to 1.5GB, and when doing multiple converts at a time it gets worse. Converting 1 file causes memory to go up, then converting another one simultaneously can result in memory usage of ~3GB."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;User experiencing concurrent processing issues, Aspose Forums, 2023&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;"We are using Aspose.PDF to convert PDFs to HTML in our application and are experiencing extremely high memory usage on our server. Memory consumption is reaching 95%."&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Production environment memory impact, Aspose Forums, January 2025&lt;/li&gt;
&lt;/ul&gt;
&lt;/blockquote&gt;

&lt;p&gt;The consistency of these reports across years suggests an architectural characteristic rather than a fixable bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;p&gt;Aspose.PDF's document loading performance stems from its approach to PDF parsing and memory management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Full Document Parsing&lt;/strong&gt;: When creating a &lt;code&gt;Document&lt;/code&gt; object, Aspose.PDF parses the entire PDF structure into an in-memory representation. This includes the page tree, cross-reference tables, all embedded resources, font definitions, and content streams. For large documents, this parsing operation becomes the primary bottleneck.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Object Instantiation Overhead&lt;/strong&gt;: PDF documents contain numerous internal objects (pages, fonts, images, annotations, form fields). Each object is instantiated as a .NET object in memory, creating allocation pressure. A document with thousands of objects creates thousands of managed allocations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Lazy Loading&lt;/strong&gt;: Unlike some PDF libraries that load content on-demand, Aspose.PDF's architecture requires the complete document structure to be available before operations can proceed. There is no option to load only specific pages or defer content stream parsing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Cross-Reference Resolution&lt;/strong&gt;: PDF files use cross-reference tables to locate objects. For large documents with complex internal linking, resolving these references requires significant processing. Damaged or non-standard cross-references compound the problem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Embedded Resource Decompression&lt;/strong&gt;: Compressed streams within the PDF (images, content streams) may be decompressed during loading, expanding memory requirements beyond the file's disk size. A 20MB PDF file with compressed images can expand to hundreds of megabytes in memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Memory Retention&lt;/strong&gt;: After loading, Aspose.PDF retains the parsed document structure in memory. Unlike streaming approaches that release memory after processing each section, the entire document persists until explicitly disposed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds
&lt;/h2&gt;

&lt;p&gt;The developer community has documented various approaches to mitigate document loading performance, each with significant limitations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workaround 1: Load from FileStream Instead of Path
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Use a FileStream with specific options instead of loading directly from a file path.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of direct path loading&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"large-file.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Use FileStream with sequential read hint&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FileStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"large-file.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;FileMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;FileAccess&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;FileShare&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Read&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bufferSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;4096&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;FileOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SequentialScan&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;document&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Process document&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Aspose.PDF still loads the entire document into memory&lt;/li&gt;
&lt;li&gt;Sequential scan hint provides minimal benefit for PDF structure&lt;/li&gt;
&lt;li&gt;Does not address the fundamental parsing overhead&lt;/li&gt;
&lt;li&gt;Memory consumption remains unchanged&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Process Documents in Separate AppDomains
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Load each document in an isolated AppDomain that can be unloaded to release memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Load document in separate AppDomain to force memory release&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;ProcessInIsolation&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;domain&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;AppDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateDomain&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PdfProcessing"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfProcessor&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateInstanceAndUnwrap&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfProcessor&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;Assembly&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;typeof&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;PdfProcessor&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="n"&gt;FullName&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;processor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;finally&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;AppDomain&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Unload&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;domain&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;AppDomain unloading is not available in .NET Core/.NET 5+&lt;/li&gt;
&lt;li&gt;Significant performance overhead for each document&lt;/li&gt;
&lt;li&gt;Serialization required to pass data across domain boundaries&lt;/li&gt;
&lt;li&gt;Adds substantial code complexity&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: Increase Memory and Accept Slow Loading
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Allocate more memory and configure longer timeouts.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Configure for large files&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;loadOptions&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfLoadOptions&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Accept that loading will be slow and memory-intensive&lt;/span&gt;
&lt;span class="c1"&gt;// Ensure adequate server resources are available&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does not improve loading speed&lt;/li&gt;
&lt;li&gt;Increases infrastructure costs&lt;/li&gt;
&lt;li&gt;Not viable for memory-constrained environments (serverless, containers)&lt;/li&gt;
&lt;li&gt;Multiple concurrent operations still exhaust resources&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 4: Split Large PDFs Before Processing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Use a lightweight tool to split large PDFs into smaller chunks before loading with Aspose.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Pre-split approach (pseudo-code)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageRanges&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;SplitIntoChunks&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"large.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;chunkSize&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;range&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pageRanges&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;smallerDoc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;range&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;FilePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process smaller document&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires additional tooling for the split operation&lt;/li&gt;
&lt;li&gt;Adds I/O overhead writing temporary files&lt;/li&gt;
&lt;li&gt;Splitting itself requires loading the source document&lt;/li&gt;
&lt;li&gt;Cross-page references (bookmarks, links) may break&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Different Approach: IronPDF
&lt;/h2&gt;

&lt;p&gt;For developers whose workflows involve loading and processing existing PDF files, IronPDF provides an architecture optimized for efficient document handling. Rather than loading entire documents into memory upfront, IronPDF uses techniques that minimize memory pressure and improve loading responsiveness.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why IronPDF Handles Large Documents Differently
&lt;/h3&gt;

&lt;p&gt;IronPDF's document loading approach addresses the bottlenecks present in Aspose.PDF's architecture:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimized Parsing&lt;/strong&gt;: The internal PDF parser is designed for efficiency, using native code optimizations where possible. Recent versions reduced loading time for large documents by up to 80%.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory-Efficient Representation&lt;/strong&gt;: Documents are represented using memory-efficient data structures that minimize allocation overhead. The internal object model uses less memory per page than full DOM-style representations.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Streaming Support&lt;/strong&gt;: IronPDF can work with streams efficiently without requiring the entire file to be buffered in memory before processing begins.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Incremental Access&lt;/strong&gt;: While the full document structure is available, IronPDF optimizes access patterns so that operations on early pages do not require complete processing of later pages.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Proper Resource Disposal&lt;/strong&gt;: Calling &lt;code&gt;Dispose()&lt;/code&gt; on IronPDF documents releases memory promptly, preventing accumulation across batch operations.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Efficient large document loading with IronPDF&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LargeDocumentLoader&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessLargeDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Load document - optimized for large files&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;filePath&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Document is ready for operations&lt;/span&gt;
            &lt;span class="c1"&gt;// Access page count without loading all content&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="c1"&gt;// Extract text from specific pages&lt;/span&gt;
            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;pageCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExtractTextFromPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="nf"&gt;ProcessPageContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pageText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Memory released when using block exits&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessFromStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Stream-based loading for memory efficiency&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputStream&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Process document&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExtractAllText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="nf"&gt;ProcessContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;BatchProcessLargeFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;filePaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;outputDirectory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Process files sequentially with proper disposal&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;filePaths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Perform operations&lt;/span&gt;
                &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AddTextHeader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TextHeaderFooter&lt;/span&gt;
                &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="n"&gt;CenterText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Processed"&lt;/span&gt;
                &lt;span class="p"&gt;});&lt;/span&gt;

                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="s"&gt;$"processed_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFileName&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;)}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// Memory released after each file&lt;/span&gt;
            &lt;span class="c1"&gt;// No accumulation across batch&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessPageContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ProcessContent&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points about this code:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;using&lt;/code&gt; pattern ensures documents are disposed properly, releasing memory&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;PdfDocument.FromFile()&lt;/code&gt; and &lt;code&gt;PdfDocument.FromStream()&lt;/code&gt; provide efficient loading options&lt;/li&gt;
&lt;li&gt;Page-by-page text extraction does not require loading all pages into active memory&lt;/li&gt;
&lt;li&gt;Batch processing releases resources between files, preventing memory accumulation&lt;/li&gt;
&lt;li&gt;No need for AppDomain isolation or process recycling&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For more details on the methods used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.PdfDocument.html" rel="noopener noreferrer"&gt;PdfDocument.FromFile&lt;/a&gt; - Load PDF from file path&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.PdfDocument.html" rel="noopener noreferrer"&gt;PdfDocument.FromStream&lt;/a&gt; - Load PDF from stream&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.PdfDocument.html" rel="noopener noreferrer"&gt;ExtractTextFromPage&lt;/a&gt; - Extract text from specific pages&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/troubleshooting/ironpdf-performance-assistance/" rel="noopener noreferrer"&gt;Performance Assistance Guide&lt;/a&gt; - Optimization techniques&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;p&gt;Moving from Aspose.PDF to IronPDF requires evaluating several factors beyond loading performance.&lt;/p&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;p&gt;IronPDF is commercial software with per-developer licensing. A free trial is available for evaluation. Pricing starts at $749 for a single developer license, compared to Aspose.PDF at $1,199. Both offer site and OEM licensing for larger deployments.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Differences
&lt;/h3&gt;

&lt;p&gt;The document loading APIs differ in their approach:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Aspose.PDF document loading&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;FileStream&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileMode&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Open&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Aspose&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// Access pages via doc.Pages collection&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Text extraction&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;absorber&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;TextAbsorber&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="nf"&gt;Accept&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;absorber&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;absorber&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// IronPDF document loading&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Access page count directly&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pageCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="c1"&gt;// Text extraction&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExtractTextFromPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Migration effort depends on which Aspose.PDF features are used. Basic document loading and text extraction map directly. Advanced features like form field manipulation, annotation handling, and digital signatures have corresponding IronPDF APIs but may require code adaptation.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Faster document loading for large files&lt;/li&gt;
&lt;li&gt;Lower memory consumption during processing&lt;/li&gt;
&lt;li&gt;Better behavior in memory-constrained environments&lt;/li&gt;
&lt;li&gt;Predictable resource release with proper disposal&lt;/li&gt;
&lt;li&gt;No need for AppDomain isolation workarounds&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;IronPDF includes an embedded Chromium engine, increasing deployment size&lt;/li&gt;
&lt;li&gt;Some advanced Aspose.PDF features may have different API patterns&lt;/li&gt;
&lt;li&gt;Testing is required to verify processing results match existing workflows&lt;/li&gt;
&lt;li&gt;IronPDF targets .NET platforms; Java applications require alternative solutions&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Aspose.PDF's document loading performance creates bottlenecks for applications processing large PDF files. The 6x slower loading compared to equivalent document formats, combined with memory consumption that can reach 97-99% of available RAM, limits throughput and creates stability risks in production environments. For teams where loading performance impacts operations, IronPDF's optimized document handling provides an alternative that maintains reasonable loading times and memory usage as file sizes increase.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by &lt;a href="https://ironsoftware.com/about-us/authors/jacobmellor/" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt;, who leads technical development at Iron Software.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/subject-loading-pdf-documents-for-conversion-in-aspose-pdf-very-slow-compared-to-ms-office-documents/226977" rel="noopener noreferrer"&gt;Subject: loading PDF documents for conversion in Aspose.Pdf very slow compared to MS Office documents&lt;/a&gt;{:rel="nofollow"} - 6x slower loading benchmark&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/slow-rendering-pdf-for-large-size-pdf-file/251834" rel="noopener noreferrer"&gt;Slow rendering PDF for large size pdf file&lt;/a&gt;{:rel="nofollow"} - 48 second first-page render time&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/high-memory-usage-on-pdf-document-object/243401" rel="noopener noreferrer"&gt;High memory usage on pdf document object&lt;/a&gt;{:rel="nofollow"} - Memory consumption reaching 97-99%&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/impact-production-server-aspose-pdf-high-memory-consumption/310646" rel="noopener noreferrer"&gt;IMPACT PRODUCTION SERVER - Aspose.PDF High Memory Consumption&lt;/a&gt;{:rel="nofollow"} - Production server memory impact&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/very-high-ram-usage/270271" rel="noopener noreferrer"&gt;Very high RAM usage&lt;/a&gt;{:rel="nofollow"} - 1.5GB memory for 15MB files&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/out-of-memory-issue-when-merging-large-files/320076" rel="noopener noreferrer"&gt;OUT of memory issue when merging large files&lt;/a&gt;{:rel="nofollow"} - Large file memory exceptions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/issue-with-merging-large-pdf-files-using-aspose-pdf-outofmemory-and-contextswitchdeadlock/322621" rel="noopener noreferrer"&gt;Issue with Merging Large PDF Files using Aspose.PDF (OutOfMemory and ContextSwitchDeadlock)&lt;/a&gt;{:rel="nofollow"} - 2GB file processing failures&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/questions/68256319/aspose-pdf-very-slow-on-document-save" rel="noopener noreferrer"&gt;ASPOSE.PDF very slow on document.save() - java&lt;/a&gt;{:rel="nofollow"} - Stack Overflow performance discussion&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/large-files-streams/161212" rel="noopener noreferrer"&gt;Large files &amp;amp; streams&lt;/a&gt;{:rel="nofollow"} - Stream-based loading challenges&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.aspose.com/t/problem-with-memory-consumption-in-aspose-pdf/87565" rel="noopener noreferrer"&gt;Problem with memory consumption in Aspose.Pdf&lt;/a&gt;{:rel="nofollow"} - Historical memory consumption issues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For the latest IronPDF documentation and tutorials, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Winnovative to IronPDF: three steps and you're done</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Wed, 08 Apr 2026 09:36:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/winnovative-to-ironpdf-three-steps-and-youre-done-4onc</link>
      <guid>https://dev.to/ironsoftware/winnovative-to-ironpdf-three-steps-and-youre-done-4onc</guid>
      <description>&lt;p&gt;The last commit to Winnovative's NuGet packages was years ago. The open GitHub issues haven't received responses in the same timeframe. The library still works — it does what it always did — but when a bug surfaces or a .NET runtime behavior changes, there's no update path. The decision isn't whether to migrate; it's when and to what.&lt;/p&gt;

&lt;p&gt;This article covers migrating from Winnovative HTML to PDF Converter for .NET to IronPDF. You'll have benchmark reference patterns and working before/after code. The comparison tables and checklist apply regardless of which replacement you choose.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Migrate (Without Drama)
&lt;/h2&gt;

&lt;p&gt;Teams migrating from Winnovative to IronPDF commonly encounter:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Maintenance signal&lt;/strong&gt; — verify current commit/release activity; outdated libraries carry growing technical risk as .NET evolves.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rendering engine age&lt;/strong&gt; — older rendering engines don't support modern CSS (flex, grid, custom properties); verify what your version supports.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;.NET version support&lt;/strong&gt; — verify .NET 6/7/8/9 compatibility at winnovative-software.com; newer runtimes may not be explicitly tested or supported.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Native component management&lt;/strong&gt; — some Winnovative versions require native binaries or COM components, adding deployment friction.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Linux/Docker gap&lt;/strong&gt; — if the rendering engine has Windows dependencies, cross-platform deployment isn't possible.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No PDF manipulation&lt;/strong&gt; — HTML-to-PDF conversion is the primary feature; merge, watermark, security, and text extraction typically require secondary libraries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Thread safety&lt;/strong&gt; — verify concurrent rendering behavior in your version; this varies across HTML-to-PDF tools.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Security updates&lt;/strong&gt; — an unmaintained library doesn't receive security patches; verify risk for your use case.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Documentation staleness&lt;/strong&gt; — outdated documentation creates friction when troubleshooting edge cases.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Support void&lt;/strong&gt; — no active maintainer means no path to resolution when bugs surface.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Comparison Table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;Winnovative HTML to PDF&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Focus&lt;/td&gt;
&lt;td&gt;HTML-to-PDF conversion&lt;/td&gt;
&lt;td&gt;HTML-to-PDF + PDF manipulation&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Pricing&lt;/td&gt;
&lt;td&gt;Commercial — verify at winnovative-software.com&lt;/td&gt;
&lt;td&gt;Commercial — verify at ironsoftware.com&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API Style&lt;/td&gt;
&lt;td&gt;&lt;code&gt;HtmlToPdfConverter.ConvertHtmlString()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChromePdfRenderer.RenderHtmlAsPdfAsync()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning Curve&lt;/td&gt;
&lt;td&gt;Low for basic use&lt;/td&gt;
&lt;td&gt;Low for .NET devs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML Rendering&lt;/td&gt;
&lt;td&gt;Verify current rendering engine&lt;/td&gt;
&lt;td&gt;Embedded Chromium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page Indexing&lt;/td&gt;
&lt;td&gt;Verify in Winnovative docs&lt;/td&gt;
&lt;td&gt;0-based&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Thread Safety&lt;/td&gt;
&lt;td&gt;Verify in Winnovative docs&lt;/td&gt;
&lt;td&gt;Verify IronPDF concurrent instance guidance&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Namespace&lt;/td&gt;
&lt;td&gt;&lt;code&gt;Winnovative.HtmlToPdfConverter.*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IronPdf&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Migration Complexity Assessment
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Effort by Feature
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;Winnovative&lt;/th&gt;
&lt;th&gt;IronPDF Equivalent&lt;/th&gt;
&lt;th&gt;Complexity&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTML string to PDF&lt;/td&gt;
&lt;td&gt;&lt;code&gt;converter.ConvertHtmlString(html)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChromePdfRenderer.RenderHtmlAsPdfAsync()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;URL to PDF&lt;/td&gt;
&lt;td&gt;&lt;code&gt;converter.ConvertUrl(url)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;renderer.RenderUrlAsPdfAsync(url)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Save to file&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;doc.Save(path)&lt;/code&gt; or byte[] + write&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pdf.SaveAs(path)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Save to stream&lt;/td&gt;
&lt;td&gt;Verify stream API&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pdf.Stream&lt;/code&gt; / &lt;code&gt;pdf.BinaryData&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom page size&lt;/td&gt;
&lt;td&gt;&lt;code&gt;converter.PdfPageSize = ...&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderingOptions.PaperSize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Margins&lt;/td&gt;
&lt;td&gt;Converter settings&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderingOptions.Margin*&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headers/footers&lt;/td&gt;
&lt;td&gt;Verify API&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderingOptions.HtmlHeader/Footer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge PDFs&lt;/td&gt;
&lt;td&gt;Verify support&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PdfDocument.Merge()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watermark&lt;/td&gt;
&lt;td&gt;Verify support&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;TextStamper&lt;/code&gt; / &lt;code&gt;ImageStamper&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Password protection&lt;/td&gt;
&lt;td&gt;Verify support&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pdf.SecuritySettings&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Low&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Text extraction&lt;/td&gt;
&lt;td&gt;Verify support&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pdf.ExtractAllText()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Decision Matrix
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Business Scenario&lt;/th&gt;
&lt;th&gt;Recommendation&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Active maintenance is the primary concern&lt;/td&gt;
&lt;td&gt;Switch — eliminates risk of unmaintained dependency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modern CSS (flex, grid) rendering needed&lt;/td&gt;
&lt;td&gt;Switch — Chromium vs older rendering engine&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux/Docker deployment&lt;/td&gt;
&lt;td&gt;Switch — verify Winnovative Linux support; likely not available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Winnovative working well, no maintenance concern&lt;/td&gt;
&lt;td&gt;Evaluate migration cost vs risk timeline&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Before You Start
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;.NET 6/7/8/9&lt;/li&gt;
&lt;li&gt;IronPDF license key — &lt;a href="https://ironpdf.com/how-to/license-keys/" rel="noopener noreferrer"&gt;get a trial&lt;/a&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Find All Winnovative References
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Find Winnovative usage (verify namespace in your version)&lt;/span&gt;
rg &lt;span class="nt"&gt;-l&lt;/span&gt; &lt;span class="s2"&gt;"Winnovative&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;HtmlToPdfConverter&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; cs
rg &lt;span class="s2"&gt;"Winnovative&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;ConvertUrl&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; cs &lt;span class="nt"&gt;-n&lt;/span&gt;

&lt;span class="c"&gt;# Find NuGet references&lt;/span&gt;
&lt;span class="nb"&gt;grep&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s2"&gt;"Winnovative"&lt;/span&gt; &lt;span class="k"&gt;*&lt;/span&gt;.csproj &lt;span class="k"&gt;**&lt;/span&gt;/&lt;span class="k"&gt;*&lt;/span&gt;.csproj 2&amp;gt;/dev/null

&lt;span class="c"&gt;# Count usage density&lt;/span&gt;
rg &lt;span class="s2"&gt;"HtmlToPdfConverter&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;ConvertUrl&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; cs | &lt;span class="nb"&gt;wc&lt;/span&gt; &lt;span class="nt"&gt;-l&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Uninstall / Install
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Remove Winnovative packages (verify exact package names at NuGet)&lt;/span&gt;
dotnet remove package Winnovative.HtmlToPdfConverter  &lt;span class="c"&gt;# verify exact name&lt;/span&gt;

&lt;span class="c"&gt;# Install IronPDF&lt;/span&gt;
dotnet add package IronPdf

dotnet restore
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Quick Start Migration (3 Steps)
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1 — License Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// https://ironpdf.com/how-to/license-keys/&lt;/span&gt;
&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;??&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;InvalidOperationException&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY not set"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2 — Namespace Swap
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Winnovative&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;           &lt;span class="c1"&gt;// verify namespace&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Winnovative.HtmlToPdfConverter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// verify&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf.Rendering&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3 — Basic HTML to PDF
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (Winnovative — verify all API names):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// VERIFY: Winnovative API names for your version&lt;/span&gt;
        &lt;span class="c1"&gt;// All names below are based on commonly documented usage — verify at their site&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdfConverter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Converter settings — VERIFY property names&lt;/span&gt;
        &lt;span class="c1"&gt;// converter.PdfPageSize = PdfPageSize.A4;&lt;/span&gt;
        &lt;span class="c1"&gt;// converter.PdfPageOrientation = PdfPageOrientation.Portrait;&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert HTML string — VERIFY method name and return type&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Save — VERIFY save method&lt;/span&gt;
        &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saved output.pdf — verify all Winnovative API names"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Hello&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Saved output.pdf (&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; page(s))"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// https://ironpdf.com/how-to/html-string-to-pdf/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Benchmark Reference Patterns
&lt;/h2&gt;

&lt;blockquote&gt;
&lt;p&gt;Measurement structures only — no claims. Run against your own HTML and environment. Use these to compare Winnovative and IronPDF baseline times before committing.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Single Render Timing
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
    &amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;
    &amp;lt;style&amp;gt;
        body { font-family: Arial, sans-serif; padding: 40px; }
        table { width: 100%; border-collapse: collapse; }
        th, td { border: 1px solid #ddd; padding: 6px; font-size: 11px; }
        th { background: #f0f0f0; }
    &amp;lt;/style&amp;gt;
    &amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;h1&amp;gt;Benchmark Report&amp;lt;/h1&amp;gt;
        &amp;lt;table&amp;gt;
            &amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Region&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Revenue&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;YoY&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;North America&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$12.4M&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;+8.2%&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Europe&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$9.1M&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;+3.7%&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;APAC&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$6.8M&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;+14.3%&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
        &amp;lt;/table&amp;gt;
    &amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;(&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;double&lt;/span&gt; &lt;span class="n"&gt;p95&lt;/span&gt;&lt;span class="p"&gt;)&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;BenchmarkIronPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;warmup&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// warm up&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;();&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;runs&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalMilliseconds&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Sort&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Average&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;[(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="p"&gt;)(&lt;/span&gt;&lt;span class="n"&gt;times&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Count&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;0.95&lt;/span&gt;&lt;span class="p"&gt;)]);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;p95&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;BenchmarkIronPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"IronPDF — Avg: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;avg&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ms | P95: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;p95&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ms"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Winnovative benchmark structure (synchronous):&lt;/span&gt;
&lt;span class="c1"&gt;// var sw = Stopwatch.StartNew();&lt;/span&gt;
&lt;span class="c1"&gt;// var converter = new HtmlToPdfConverter(); // VERIFY&lt;/span&gt;
&lt;span class="c1"&gt;// var doc = converter.ConvertHtmlString(html); // VERIFY&lt;/span&gt;
&lt;span class="c1"&gt;// doc.Save("bench.pdf"); // VERIFY&lt;/span&gt;
&lt;span class="c1"&gt;// Console.WriteLine($"Winnovative: {sw.Elapsed.TotalMilliseconds:F1}ms");&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Concurrent Throughput
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// https://ironpdf.com/examples/parallel/&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;BenchmarkConcurrency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;degree&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;jobs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Enumerable&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Range&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;degree&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="s"&gt;$"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Doc &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;jobs&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}));&lt;/span&gt;

    &lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Degree &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;degree&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalMilliseconds&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ms | &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;sw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Elapsed&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TotalMilliseconds&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="n"&gt;degree&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F1&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ms/doc"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;BenchmarkConcurrency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;BenchmarkConcurrency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;BenchmarkConcurrency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// See: https://ironpdf.com/how-to/async/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Memory Profile
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;MeasureMemoryDelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Memory test&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTotalMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forceFullCollection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// pdf disposed each iteration&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="n"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitForPendingFinalizers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetTotalMemory&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;forceFullCollection&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;iterations&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; renders: delta &lt;/span&gt;&lt;span class="p"&gt;{(&lt;/span&gt;&lt;span class="n"&gt;after&lt;/span&gt; &lt;span class="p"&gt;-&lt;/span&gt; &lt;span class="n"&gt;before&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;/&lt;/span&gt; &lt;span class="m"&gt;1024&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F0&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; KB after GC"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;MeasureMemoryDelta&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;50&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  API Mapping Tables
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Namespace Mapping
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Winnovative&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Winnovative.HtmlToPdfConverter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IronPdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Core namespace&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IronPdf.Rendering&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Rendering config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;&lt;code&gt;IronPdf.Editing&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Watermark / stamp&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Core Class Mapping
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Winnovative Class&lt;/th&gt;
&lt;th&gt;IronPDF Class&lt;/th&gt;
&lt;th&gt;Description&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HtmlToPdfConverter&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChromePdfRenderer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Primary rendering class&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Converter settings object&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChromePdfRenderOptions&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Page size, margins, options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF document result&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PdfDocument&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Output object&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PdfDocument.Merge()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Static merge&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Document Loading Methods
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Winnovative&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTML string&lt;/td&gt;
&lt;td&gt;&lt;code&gt;converter.ConvertHtmlString(html)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;renderer.RenderHtmlAsPdfAsync(html)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;URL&lt;/td&gt;
&lt;td&gt;&lt;code&gt;converter.ConvertUrl(url)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;renderer.RenderUrlAsPdfAsync(url)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML file&lt;/td&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;&lt;code&gt;renderer.RenderHtmlFileAsPdfAsync(path)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Load existing PDF&lt;/td&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PdfDocument.FromFile(path)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Page Operations
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Winnovative&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page count&lt;/td&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pdf.PageCount&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Remove page&lt;/td&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;pdf.RemovePage(index)&lt;/code&gt; — verify&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extract text&lt;/td&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pdf.ExtractAllText()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rotate&lt;/td&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;Verify in IronPDF docs&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Merge / Split Operations
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Operation&lt;/th&gt;
&lt;th&gt;Winnovative&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Merge&lt;/td&gt;
&lt;td&gt;Verify support&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PdfDocument.Merge(doc1, doc2)&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split&lt;/td&gt;
&lt;td&gt;Verify&lt;/td&gt;
&lt;td&gt;&lt;a href="https://ironpdf.com/how-to/merge-or-split-pdfs/" rel="noopener noreferrer"&gt;Guide&lt;/a&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;




&lt;h2&gt;
  
  
  Four Complete Before/After Migrations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. HTML String to PDF
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (Winnovative — verify all API names):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HtmlToPdfBefore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// VERIFY: all Winnovative class and method names at winnovative-software.com&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
            &amp;lt;html&amp;gt;
            &amp;lt;head&amp;gt;&amp;lt;style&amp;gt;
            body { font-family: Arial; padding: 40px; }
            .header { font-size: 20px; font-weight: bold; }
            table { width: 100%; border-collapse: collapse; }
            td, th { border: 1px solid #ccc; padding: 6px; }
            &amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;
            &amp;lt;body&amp;gt;
                &amp;lt;div class='header'&amp;gt;Invoice #INV-2024-0099&amp;lt;/div&amp;gt;
                &amp;lt;p&amp;gt;Customer: Acme Corp | Due: 2024-12-31&amp;lt;/p&amp;gt;
                &amp;lt;table&amp;gt;
                    &amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Item&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Qty&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;
                    &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Widget Pro&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$149.00&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
                &amp;lt;/table&amp;gt;
            &amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// VERIFY: HtmlToPdfConverter class and properties&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdfConverter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="c1"&gt;// converter.PdfPageSize = PdfPageSize.A4; // VERIFY property name/enum&lt;/span&gt;

        &lt;span class="c1"&gt;// VERIFY: ConvertHtmlString method name and return type&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// VERIFY: Save method&lt;/span&gt;
        &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saved invoice.pdf — verify all Winnovative API names"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
    &amp;lt;html&amp;gt;
    &amp;lt;head&amp;gt;&amp;lt;style&amp;gt;
    body { font-family: Arial; padding: 40px; }
    .header { font-size: 20px; font-weight: bold; }
    table { width: 100%; border-collapse: collapse; }
    td, th { border: 1px solid #ccc; padding: 6px; }
    &amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;
    &amp;lt;body&amp;gt;
        &amp;lt;div class='header'&amp;gt;Invoice #INV-2024-0099&amp;lt;/div&amp;gt;
        &amp;lt;p&amp;gt;Customer: Acme Corp | Due: 2024-12-31&amp;lt;/p&amp;gt;
        &amp;lt;table&amp;gt;
            &amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Item&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Qty&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;
            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Widget Pro&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;5&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$149.00&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
        &amp;lt;/table&amp;gt;
    &amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Saved invoice.pdf (&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; page(s))"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// https://ironpdf.com/how-to/html-string-to-pdf/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  2. Merge PDFs
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (Winnovative — verify merge support):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;MergeBefore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// VERIFY: Winnovative merge support and API&lt;/span&gt;
        &lt;span class="c1"&gt;// May require generating each section separately and merging with secondary library&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sections&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Section 1&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Section 2&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdfBytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;sections&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdfConverter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="c1"&gt;// VERIFY&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// VERIFY&lt;/span&gt;
            &lt;span class="c1"&gt;// VERIFY: export to bytes&lt;/span&gt;
            &lt;span class="c1"&gt;// pdfBytes.Add(doc.ToBytes()); // illustrative&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// Merge via secondary library if Winnovative doesn't support it:&lt;/span&gt;
        &lt;span class="c1"&gt;// var merged = SomePdfLib.Merge(pdfBytes);&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verify Winnovative merge API — secondary library may be needed"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Section 1&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Section 2&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// https://ironpdf.com/how-to/merge-or-split-pdfs/&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"merged.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Merged: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PageCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; pages"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  3. Watermark
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (Winnovative — verify support):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// VERIFY: Winnovative watermark API — may not be native&lt;/span&gt;
&lt;span class="c1"&gt;// If not supported, secondary library needed after generation&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;WatermarkBefore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// var converter = new HtmlToPdfConverter(); // VERIFY&lt;/span&gt;
        &lt;span class="c1"&gt;// var doc = converter.ConvertHtmlString("&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Report&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;");&lt;/span&gt;
        &lt;span class="c1"&gt;// VERIFY: watermark method — may not exist&lt;/span&gt;

        &lt;span class="c1"&gt;// If not native: apply via secondary library&lt;/span&gt;
        &lt;span class="c1"&gt;// var bytes = doc.ToBytes();&lt;/span&gt;
        &lt;span class="c1"&gt;// var watermarked = SomePdfLib.AddTextWatermark(bytes, "DRAFT");&lt;/span&gt;
        &lt;span class="c1"&gt;// File.WriteAllBytes("watermarked.pdf", watermarked);&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verify Winnovative watermark API — may require secondary library"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf.Editing&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Report&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// https://ironpdf.com/how-to/custom-watermark/&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;watermark&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;TextStamper&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;Text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"DRAFT"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;FontColor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Imaging&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Color&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Gray&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Opacity&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0.15&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;VerticalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Middle&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;HorizontalAlignment&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;HorizontalAlignment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Center&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ApplyStamp&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;watermark&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"watermarked.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Watermark applied — https://ironpdf.com/examples/pdf-watermarking/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h3&gt;
  
  
  4. Password Protection
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Before (Winnovative — verify security API):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="c1"&gt;// VERIFY: Winnovative password/security API&lt;/span&gt;

&lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PasswordBefore&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// var converter = new HtmlToPdfConverter(); // VERIFY&lt;/span&gt;
        &lt;span class="c1"&gt;// var doc = converter.ConvertHtmlString("&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Secured&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;");&lt;/span&gt;

        &lt;span class="c1"&gt;// VERIFY: Winnovative security API — property names are version-dependent&lt;/span&gt;
        &lt;span class="c1"&gt;// doc.Security.UserPassword = "open123";   // illustrative — VERIFY&lt;/span&gt;
        &lt;span class="c1"&gt;// doc.Security.OwnerPassword = "admin456"; // illustrative — VERIFY&lt;/span&gt;
        &lt;span class="c1"&gt;// doc.Save("secured.pdf");&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Verify Winnovative security API — check winnovative-software.com docs"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;After:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Secured&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// https://ironpdf.com/how-to/pdf-permissions-passwords/&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecuritySettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;UserPassword&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"open123"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SecuritySettings&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OwnerPassword&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"admin456"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"secured.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Saved secured.pdf — https://ironpdf.com/examples/encryption-and-decryption/"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Critical Migration Notes
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Verify API Names Before Any Code Removal
&lt;/h3&gt;

&lt;p&gt;Winnovative has limited public documentation compared to larger libraries. Before removing any Winnovative code, run the codebase audit to understand exact method signatures in use:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Capture all method calls before removing anything&lt;/span&gt;
rg &lt;span class="s2"&gt;"converter&lt;/span&gt;&lt;span class="se"&gt;\.\|&lt;/span&gt;&lt;span class="s2"&gt;HtmlToPdfConverter&lt;/span&gt;&lt;span class="se"&gt;\.\|&lt;/span&gt;&lt;span class="s2"&gt;ConvertHtml&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;ConvertUrl&lt;/span&gt;&lt;span class="se"&gt;\b&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; cs &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; winnovative-usage.txt
&lt;span class="nb"&gt;cat &lt;/span&gt;winnovative-usage.txt
&lt;span class="c"&gt;# Use this as the migration map — verify each line against Winnovative docs&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Rendering Engine Difference
&lt;/h3&gt;

&lt;p&gt;Winnovative uses an internal rendering engine. IronPDF uses Chromium. Modern CSS that didn't work in Winnovative may now work — and some Winnovative-specific CSS workarounds may no longer be needed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Find CSS that was added as Winnovative workarounds&lt;/span&gt;
rg &lt;span class="s2"&gt;"TODO.*winnovative&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;HACK.*render&lt;/span&gt;&lt;span class="se"&gt;\|&lt;/span&gt;&lt;span class="s2"&gt;workaround.*pdf"&lt;/span&gt; &lt;span class="nt"&gt;--type&lt;/span&gt; css &lt;span class="nt"&gt;--type&lt;/span&gt; html &lt;span class="nt"&gt;-in&lt;/span&gt;

&lt;span class="c"&gt;# After migration, test whether these workarounds are still needed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  &lt;code&gt;ConvertHtmlString&lt;/code&gt; Return Type
&lt;/h3&gt;

&lt;p&gt;Winnovative's return type varies by version — it may return &lt;code&gt;byte[]&lt;/code&gt; directly or a document object. Map to IronPDF accordingly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// If Winnovative returned byte[]:&lt;/span&gt;
&lt;span class="c1"&gt;// var bytes = converter.ConvertHtmlString(html);&lt;/span&gt;
&lt;span class="c1"&gt;// File.WriteAllBytes("output.pdf", bytes);&lt;/span&gt;

&lt;span class="c1"&gt;// IronPDF equivalent:&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;bytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// equivalent byte[]&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;   &lt;span class="c1"&gt;// or save directly&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Page Indexing
&lt;/h3&gt;

&lt;p&gt;Verify Winnovative's page indexing (if any page manipulation was used) before assuming 0-based. IronPDF uses 0-based indexing.&lt;/p&gt;




&lt;h2&gt;
  
  
  Performance Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Parallel Generation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Environment&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetEnvironmentVariable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"IRONPDF_LICENSE_KEY"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// https://ironpdf.com/examples/parallel/&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdfs&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WhenAll&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;dataList&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;data&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nf"&gt;BuildHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="p"&gt;}));&lt;/span&gt;

&lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;pdfs&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// See: https://ironpdf.com/how-to/async/&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Disposal Pattern
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdfAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Map from Winnovative return:&lt;/span&gt;
&lt;span class="c1"&gt;// If Winnovative returned byte[]: pdf.BinaryData is the equivalent&lt;/span&gt;
&lt;span class="c1"&gt;// If Winnovative returned a document with a Save(stream): pdf.Stream.CopyTo(stream)&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// pdf disposed at end of 'using' block&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;






&lt;h2&gt;
  
  
  Migration Checklist
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Pre-Migration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Verify Winnovative maintenance status at winnovative-software.com&lt;/li&gt;
&lt;li&gt;[ ] Find all Winnovative API usage (&lt;code&gt;rg "Winnovative\|ConvertHtmlString\|ConvertUrl" --type cs&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Document exact method signatures in use&lt;/li&gt;
&lt;li&gt;[ ] Identify secondary libraries used for merge/security/watermark&lt;/li&gt;
&lt;li&gt;[ ] Measure baseline render time for benchmark comparison&lt;/li&gt;
&lt;li&gt;[ ] Obtain IronPDF license key&lt;/li&gt;
&lt;li&gt;[ ] Verify IronPDF .NET version compatibility&lt;/li&gt;
&lt;li&gt;[ ] Check for native/COM dependency requirements in current Winnovative setup&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Migration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Install IronPDF (&lt;code&gt;dotnet add package IronPdf&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;[ ] Remove Winnovative NuGet packages&lt;/li&gt;
&lt;li&gt;[ ] Add license key at application startup&lt;/li&gt;
&lt;li&gt;[ ] Replace &lt;code&gt;HtmlToPdfConverter.ConvertHtmlString()&lt;/code&gt; with &lt;code&gt;ChromePdfRenderer.RenderHtmlAsPdfAsync()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Replace &lt;code&gt;converter.ConvertUrl()&lt;/code&gt; with &lt;code&gt;renderer.RenderUrlAsPdfAsync()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Replace &lt;code&gt;doc.Save(path)&lt;/code&gt; with &lt;code&gt;pdf.SaveAs(path)&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Map converter settings properties to &lt;code&gt;RenderingOptions.*&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Replace secondary merge library with &lt;code&gt;PdfDocument.Merge()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Replace secondary watermark library with &lt;code&gt;TextStamper&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;[ ] Replace secondary security library with &lt;code&gt;pdf.SecuritySettings&lt;/code&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Testing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Compare PDF output visually against Winnovative reference&lt;/li&gt;
&lt;li&gt;[ ] Test modern CSS rendering (flex, grid) — may now work where it didn't before&lt;/li&gt;
&lt;li&gt;[ ] Benchmark render time — single and concurrent&lt;/li&gt;
&lt;li&gt;[ ] Test Linux/Docker deployment if applicable&lt;/li&gt;
&lt;li&gt;[ ] Test merge, watermark, and security&lt;/li&gt;
&lt;li&gt;[ ] Verify page size and margin settings match reference&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Post-Migration
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Remove Winnovative NuGet packages&lt;/li&gt;
&lt;li&gt;[ ] Remove secondary libraries now replaced by IronPDF&lt;/li&gt;
&lt;li&gt;[ ] Remove Winnovative native components from deployment if applicable&lt;/li&gt;
&lt;li&gt;[ ] Archive Winnovative CSS workarounds in case reference is needed&lt;/li&gt;
&lt;/ul&gt;




&lt;h2&gt;
  
  
  One Last Thing
&lt;/h2&gt;

&lt;p&gt;The maintenance signal — last update years ago, issues unanswered — is the clearest migration trigger. The technical migration is straightforward because both tools do the same job (HTML-to-PDF); the API surface maps closely even if names differ.&lt;/p&gt;

&lt;p&gt;The benchmark patterns above are most useful for understanding how concurrent throughput changes — particularly if the current Winnovative setup has any thread-safety workarounds that added infrastructure overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Discussion question:&lt;/strong&gt; Which feature was hardest to replicate in IronPDF — was it a specific CSS behavior that worked differently, a margin/header setting that didn't map directly, or something in the rendering output that surprised you?&lt;/p&gt;




</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title># SelectPdf Slow Build Times and Conversion Performance (Issue Fixed)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Wed, 08 Apr 2026 08:34:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/-selectpdf-slow-build-times-and-conversion-performance-issue-fixed-23ai</link>
      <guid>https://dev.to/ironsoftware/-selectpdf-slow-build-times-and-conversion-performance-issue-fixed-23ai</guid>
      <description>&lt;p&gt;Developers integrating SelectPdf into .NET projects often encounter unexpected delays during both compilation and runtime. Build times stretch from seconds to minutes as Visual Studio downloads and processes massive NuGet packages. Once deployed, HTML-to-PDF conversions that should complete instantly take 3 seconds on development machines and up to 3.5 minutes on production web servers. These performance characteristics impact developer productivity and end-user experience alike.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;SelectPdf delivers PDF generation capabilities through a NuGet package architecture that prioritizes feature completeness over build-time efficiency. The primary Select.Pdf package weighs in at 75.61 MB, while the .NET Core variant reaches 105.33 MB. When using the Blink rendering engine (Chromium-based), the package includes an entire Chromium browser folder that must be extracted and deployed with each build.&lt;/p&gt;

&lt;p&gt;The runtime conversion performance presents separate concerns. Developers report consistent 3-second delays for simple HTML-to-PDF conversions on .NET Core, with some production environments experiencing conversions stretching to 3.5 minutes. These delays persist regardless of document complexity, indicating overhead in the conversion pipeline itself rather than rendering complexity.&lt;/p&gt;

&lt;p&gt;The combination of slow builds and slow conversions creates compounding productivity losses. A developer making iterative changes to PDF output spends significant time waiting for builds to complete and conversions to finish, extending development cycles substantially.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Messages and Symptoms
&lt;/h3&gt;

&lt;p&gt;Performance issues do not produce error messages in the traditional sense. Instead, developers observe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Build time: 45 seconds (previously 12 seconds before adding SelectPdf)
Package restore: Downloading Select.Pdf.NetCore 25.2.0 (105.33 MB)
Conversion time: 3,000ms for single-page HTML document
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;On production servers, the symptoms become more severe:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Request timeout after 60 seconds
Conversion completed in 210,000ms (3.5 minutes)
Memory usage spike during conversion: 500MB+ for simple documents
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Developers debugging performance often enable timing instrumentation:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Conversion time: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElapsedMilliseconds&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ms"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Output: Conversion time: 3247ms (simple HTML document)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;SelectPdf performance issues impact several categories of developers and deployment scenarios:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Development Environment Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Teams using CI/CD pipelines experience extended build times&lt;/li&gt;
&lt;li&gt;Developers on slower machines face compounded delays&lt;/li&gt;
&lt;li&gt;Projects with frequent build-test cycles suffer productivity losses&lt;/li&gt;
&lt;li&gt;Cold builds after cache clearing take significantly longer&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Runtime Performance Impact:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Web applications generating PDFs synchronously&lt;/li&gt;
&lt;li&gt;Batch processing systems creating multiple documents&lt;/li&gt;
&lt;li&gt;Report generation features where users wait for PDF output&lt;/li&gt;
&lt;li&gt;High-traffic applications where conversion latency affects throughput&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Deployment Scenarios:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Docker containers with SelectPdf experience large image sizes&lt;/li&gt;
&lt;li&gt;Azure App Service deployments require Basic tier or higher&lt;/li&gt;
&lt;li&gt;Serverless functions face cold start penalties&lt;/li&gt;
&lt;li&gt;Kubernetes pods with memory limits may hit constraints&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Evidence from the Developer Community
&lt;/h2&gt;

&lt;p&gt;Performance complaints about SelectPdf appear across multiple platforms, with consistent themes around build impact and conversion speed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2016-06&lt;/td&gt;
&lt;td&gt;Bubble.io users report "really really slow" export&lt;/td&gt;
&lt;td&gt;Bubble Forum&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2019-06&lt;/td&gt;
&lt;td&gt;GitHub issue opened: "Converting html to pdf takes 3 seconds"&lt;/td&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020-07&lt;/td&gt;
&lt;td&gt;PDF.js issue reports slow rendering of SelectPdf output&lt;/td&gt;
&lt;td&gt;Mozilla GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2021-12&lt;/td&gt;
&lt;td&gt;Large data issues and out of memory reports&lt;/td&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025-01&lt;/td&gt;
&lt;td&gt;Issue remains open, no resolution provided&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Community Reports
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"I like SelectPDF very much, but it takes 3 seconds to convert html to pdf on .NET Core 2.1"&lt;br&gt;
-- Developer, GitHub Issue #7, June 2019&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The GitHub issue remains open, with the SelectPdf team responding that performance can be improved by disabling various features, but not providing a fundamental fix for the baseline conversion overhead.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"It takes 3 seconds to convert html to pdf on .NET Core... The same conversion takes about 3.5 minutes on the web server."&lt;br&gt;
-- Stack Overflow discussion, cited in multiple forums&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;This disparity between local development performance and production server performance indicates environmental factors compound the base performance issues.&lt;/p&gt;

&lt;p&gt;On the Bubble.io forum, users running SelectPdf through an integration plugin described the export process as "really really slow" for invoice generation, with the thread spanning multiple pages of developers sharing similar experiences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Package Size Analysis
&lt;/h3&gt;

&lt;p&gt;The NuGet package sizes directly impact build performance:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Package&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th&gt;Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Select.Pdf&lt;/td&gt;
&lt;td&gt;25.2.0&lt;/td&gt;
&lt;td&gt;75.61 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Select.Pdf.NetCore&lt;/td&gt;
&lt;td&gt;25.2.0&lt;/td&gt;
&lt;td&gt;105.33 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Select.HtmlToPdf&lt;/td&gt;
&lt;td&gt;25.2.0&lt;/td&gt;
&lt;td&gt;65.97 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Select.Pdf.x64&lt;/td&gt;
&lt;td&gt;19.1.0&lt;/td&gt;
&lt;td&gt;83.99 MB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Select.Pdf.NetCore.Blink&lt;/td&gt;
&lt;td&gt;25.2.0&lt;/td&gt;
&lt;td&gt;Additional Chromium folder&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For comparison, typical .NET NuGet packages range from 100 KB to 5 MB. SelectPdf packages are 15-100 times larger than average.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;p&gt;SelectPdf's performance characteristics stem from its architectural design decisions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Package Size Contributors:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Multiple Rendering Engines&lt;/strong&gt;: SelectPdf includes both WebKit and Blink (Chromium) rendering engines. Each engine requires substantial native binaries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Bundled Dependencies&lt;/strong&gt;: The Select.Html.dep and Select.Tools.dep files contain the actual rendering logic and must be deployed alongside the main assembly.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Chromium Inclusion&lt;/strong&gt;: When using the Blink engine (required for modern HTML/CSS support), the package includes a full Chromium-124.0.6367.201 folder with browser binaries.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Cross-Platform Support Overhead&lt;/strong&gt;: The .NET Core package includes binaries for multiple architectures, inflating the package size.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Conversion Speed Contributors:&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Process Spawning&lt;/strong&gt;: SelectPdf spawns external processes (Select.Html.dep) for each conversion, adding process creation overhead.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Engine Initialization&lt;/strong&gt;: Each conversion may reinitialize the rendering engine, particularly in serverless or containerized environments without warm instances.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Default Configuration&lt;/strong&gt;: The default settings enable JavaScript, plugins, and other features that add processing time even when not needed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Memory Management&lt;/strong&gt;: Developers report that memory is not efficiently released between conversions, leading to garbage collection pauses that affect subsequent operations.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Server Environment Factors:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Production servers often perform worse than development machines due to:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reduced CPU allocation in shared hosting&lt;/li&gt;
&lt;li&gt;Memory pressure from concurrent operations&lt;/li&gt;
&lt;li&gt;Cold starts in containerized deployments&lt;/li&gt;
&lt;li&gt;Azure App Service sandbox restrictions (requiring restricted rendering engine)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds
&lt;/h2&gt;

&lt;p&gt;The SelectPdf documentation and community suggest several performance optimization approaches.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workaround 1: Disable Unnecessary Features
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Reduce conversion overhead by disabling features not required for the specific use case.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="c1"&gt;// Disable JavaScript if not needed&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JavaScriptEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Disable image compression processing&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JpegCompressionEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Skip font embedding&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EmbedFonts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Disable plugins&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PluginsEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Set minimum page load time to zero&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MinPageLoadTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Use fastest compression&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfCompressionLevel&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfCompressionLevel&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;NoCompression&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Disabling JavaScript breaks dynamic content&lt;/li&gt;
&lt;li&gt;No compression increases file sizes&lt;/li&gt;
&lt;li&gt;Feature stripping may not address core process overhead&lt;/li&gt;
&lt;li&gt;Reported improvements are modest (10-30% reduction, not elimination)&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Switch to Blink Rendering Engine
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Use the Chromium-based Blink engine instead of WebKit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;RenderingEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Blink&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Blink packages are even larger, increasing build times&lt;/li&gt;
&lt;li&gt;Requires .NET Framework 4.6.1+ or .NET Core&lt;/li&gt;
&lt;li&gt;Some SelectPdf features unavailable with Blink (bookmarks, post data, partial rendering)&lt;/li&gt;
&lt;li&gt;Does not address the fundamental 3-second baseline delay&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: Font Caching Configuration
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Configure font caching to use filesystem instead of memory.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Helps in specific scenarios where font loading is the bottleneck&lt;/li&gt;
&lt;li&gt;Does not address core conversion overhead&lt;/li&gt;
&lt;li&gt;Requires writable filesystem access, complicating containerized deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 4: Increase Timeouts
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Extend timeout settings to prevent failures on slow conversions.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MaxPageLoadTime&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;120&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 120 seconds timeout&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Does not improve performance, only prevents timeout errors&lt;/li&gt;
&lt;li&gt;Users still experience the full delay&lt;/li&gt;
&lt;li&gt;Ties up server resources during extended conversions&lt;/li&gt;
&lt;li&gt;Masks the underlying performance problem&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Different Approach: IronPDF
&lt;/h2&gt;

&lt;p&gt;IronPDF's architecture prioritizes conversion speed through a different technical approach. Rather than spawning external processes and initializing rendering engines per-conversion, IronPDF maintains a managed Chromium instance that handles conversions with minimal overhead.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why IronPDF Performs Differently
&lt;/h3&gt;

&lt;p&gt;The architectural differences that affect performance:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Managed Chromium Instance&lt;/strong&gt;: IronPDF manages the Chromium rendering engine lifecycle, avoiding repeated initialization costs.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Direct Integration&lt;/strong&gt;: Conversions occur within the .NET process rather than through inter-process communication with external executables.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Optimized Binaries&lt;/strong&gt;: Platform-specific native components are loaded once and reused across conversions.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Streaming Architecture&lt;/strong&gt;: Large documents can be processed without loading entirely into memory.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Performance testing in independent comparisons shows sub-second conversion for standard web pages, compared to SelectPdf's 2-3 second baseline.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Diagnostics&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// Demonstrates high-performance HTML to PDF conversion.&lt;/span&gt;
&lt;span class="c1"&gt;/// IronPDF's ChromePdfRenderer maintains an optimized rendering context&lt;/span&gt;
&lt;span class="c1"&gt;/// that avoids the per-conversion initialization overhead.&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HighPerformancePdfGenerator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ChromePdfRenderer&lt;/span&gt; &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;HighPerformancePdfGenerator&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Renderer initialization happens once&lt;/span&gt;
        &lt;span class="c1"&gt;// Subsequent conversions reuse the initialized context&lt;/span&gt;
        &lt;span class="n"&gt;_renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure rendering options&lt;/span&gt;
        &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;ConvertHtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Conversion benefits from already-initialized renderer&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConvertWithTiming&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stopwatch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;StartNew&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Stop&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Conversion completed in &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;stopwatch&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;ElapsedMilliseconds&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;ms"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Typical output: Conversion completed in 247ms&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points about this code:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The &lt;code&gt;ChromePdfRenderer&lt;/code&gt; instance can be reused across multiple conversions&lt;/li&gt;
&lt;li&gt;Initialization cost is paid once, not per-conversion&lt;/li&gt;
&lt;li&gt;Memory management is handled within the .NET runtime&lt;/li&gt;
&lt;li&gt;No external process spawning required&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Batch Processing Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// Demonstrates efficient batch PDF generation.&lt;/span&gt;
&lt;span class="c1"&gt;/// IronPDF supports parallel conversions without the process-spawning&lt;/span&gt;
&lt;span class="c1"&gt;/// overhead that limits SelectPdf batch performance.&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BatchPdfProcessor&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;ProcessBatchAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;htmlDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Process documents with efficient resource utilization&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;htmlDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;ProcessLargeVolumeAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;htmlDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// For high-volume scenarios, IronPDF supports streaming output&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;htmlDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Stream directly to storage without holding all PDFs in memory&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Write to file system, blob storage, or other destination&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;SaveToStorageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt; &lt;span class="nf"&gt;SaveToStorageAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;pdfStream&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Implementation depends on storage destination&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For comprehensive documentation on performance optimization:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/how-to/performance/" rel="noopener noreferrer"&gt;Performance Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/examples/batch-pdf-generation/" rel="noopener noreferrer"&gt;Batch Processing&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;p&gt;IronPDF uses a commercial license model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free development and testing with watermark&lt;/li&gt;
&lt;li&gt;Lite license starts at $749 (perpetual)&lt;/li&gt;
&lt;li&gt;Higher tiers available for multiple projects and enterprise needs&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/licensing/" rel="noopener noreferrer"&gt;Pricing details&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;SelectPdf also uses commercial licensing, with the Community Edition limited to 5 pages per document.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Differences
&lt;/h3&gt;

&lt;p&gt;The migration requires updating class names and method calls:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SelectPdf:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPageSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfPageSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Options&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;JavaScriptEnabled&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;converter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertHtmlString&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Save&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;IronPDF:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SelectPdf&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HtmlToPdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChromePdfRenderer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ConvertHtmlString()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderHtmlAsPdf()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ConvertUrl()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderUrlAsPdf()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;Options.PdfPageSize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderingOptions.PaperSize&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;doc.Save()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;pdf.SaveAs()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Sub-second conversion times for typical documents&lt;/li&gt;
&lt;li&gt;Reduced build times (smaller package footprint relative to features)&lt;/li&gt;
&lt;li&gt;Consistent performance between development and production&lt;/li&gt;
&lt;li&gt;Cross-platform support (Windows, Linux, macOS)&lt;/li&gt;
&lt;li&gt;Docker and Azure compatibility without workarounds&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Commercial license required for production&lt;/li&gt;
&lt;li&gt;IronPDF package sizes are also substantial due to embedded Chromium&lt;/li&gt;
&lt;li&gt;Memory usage patterns differ; evaluate for your specific workload&lt;/li&gt;
&lt;li&gt;Initial renderer instantiation has a one-time cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;SelectPdf's 75-105 MB NuGet packages extend build times, and its process-spawning architecture introduces 3+ second conversion delays that can reach 3.5 minutes on production servers. While workarounds involving feature disabling provide marginal improvements, they do not address the fundamental architectural overhead. IronPDF's managed Chromium approach delivers sub-second conversions and avoids the repeated initialization costs that characterize SelectPdf's performance profile.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/jacob-mellor" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt; has spent 25+ years building developer tools, including IronPDF.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/selectpdf/selectpdf-free-html-to-pdf-converter/issues/7" rel="noopener noreferrer"&gt;Converting html to pdf takes 3 seconds - GitHub Issue #7&lt;/a&gt;{:rel="nofollow"} - Original performance report on SelectPdf GitHub&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://forum.bubble.io/t/selectpdf-really-slow-when-exporting-to-pdf/3371" rel="noopener noreferrer"&gt;Selectpdf really slow when exporting to PDF - Bubble Forum&lt;/a&gt;{:rel="nofollow"} - Community discussion of export performance&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/mozilla/pdf.js/issues/12098" rel="noopener noreferrer"&gt;PDFs generated by selectpdf.com slow to render - Mozilla pdf.js Issue #12098&lt;/a&gt;{:rel="nofollow"} - Report on SelectPdf output rendering performance&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/selectpdf/selectpdf-free-html-to-pdf-converter/issues/22" rel="noopener noreferrer"&gt;Large data Issue using SelectPdf - GitHub Issue #22&lt;/a&gt;{:rel="nofollow"} - Memory and performance issues with large documents&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://selectpdf.com/docs/Troubleshooting.htm" rel="noopener noreferrer"&gt;SelectPdf Troubleshooting&lt;/a&gt;{:rel="nofollow"} - Official troubleshooting documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://selectpdf.com/html-to-pdf/docs/html/ConversionDelay.htm" rel="noopener noreferrer"&gt;SelectPdf Conversion Delay&lt;/a&gt;{:rel="nofollow"} - Official documentation on timeout configuration&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.nuget.org/packages/Select.Pdf/" rel="noopener noreferrer"&gt;NuGet Gallery - Select.Pdf&lt;/a&gt;{:rel="nofollow"} - Package size and version information&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.nuget.org/packages/Select.Pdf.NetCore" rel="noopener noreferrer"&gt;NuGet Gallery - Select.Pdf.NetCore&lt;/a&gt;{:rel="nofollow"} - .NET Core package information&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For the latest IronPDF documentation and tutorials, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Puppeteer Zombie Processes and Browser Instances (Issue Fixed)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Wed, 08 Apr 2026 06:32:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/puppeteer-zombie-processes-and-browser-instances-issue-fixed-3j30</link>
      <guid>https://dev.to/ironsoftware/puppeteer-zombie-processes-and-browser-instances-issue-fixed-3j30</guid>
      <description>&lt;p&gt;Developers running Puppeteer or PuppeteerSharp in production often discover their servers accumulating orphaned Chrome processes that consume memory but never terminate. These zombie browser processes escape disposal calls, pile up under load, and eventually exhaust system resources. The problem intensifies in containerized environments where memory limits trigger OOM kills, and debugging becomes nearly impossible when logs scatter across dozens of orphaned browser instances.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;When Puppeteer launches a browser, it spawns multiple operating system processes: a main browser process, GPU process, network service, and renderer processes for each tab. These processes communicate with the Node.js or .NET application through WebSocket connections using the Chrome DevTools Protocol. The parent application sends commands and receives responses, but it does not directly control the lifecycle of these child processes.&lt;/p&gt;

&lt;p&gt;Under normal conditions, calling &lt;code&gt;browser.close()&lt;/code&gt; in Node.js or &lt;code&gt;Browser.CloseAsync()&lt;/code&gt; in PuppeteerSharp signals the browser to terminate gracefully. The browser process should then exit, taking its child processes with it. In practice, this signal frequently fails to reach all processes, or the processes fail to respond to it. The result is a zombie process that remains in memory, consuming resources but no longer responding to commands.&lt;/p&gt;

&lt;p&gt;The zombie process problem compounds under high-traffic conditions. Each failed disposal leaves behind processes consuming 100-300MB of RAM. With hundreds of PDF generation requests per hour, memory consumption climbs steadily. Server monitoring shows RAM usage increasing even when the application itself reports successful disposal. Eventually, the operating system intervenes with OOM kills, or the server becomes unresponsive.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Messages and Symptoms
&lt;/h3&gt;

&lt;p&gt;Applications experiencing zombie browser processes typically encounter these errors and behaviors:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error: Protocol error (Target.createTarget): Target closed.

TimeoutError: Timed out after 30000 ms while trying to connect to the browser!
Most likely the browser was closed.

Error: Browser disconnected unexpectedly (closed?)

PuppeteerSharp.TargetClosedException: Protocol error (Target.activateTarget):
Target closed. (Session closed. Most likely the page has been closed.)

Container killed with exit code 137 (OOM killed by kernel)

Error: ECONNREFUSED - Connection refused
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Observable symptoms include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Memory usage climbing without corresponding application load&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ps aux | grep chrome&lt;/code&gt; showing dozens of orphaned Chrome processes&lt;/li&gt;
&lt;li&gt;Application logs reporting successful browser disposal while processes remain&lt;/li&gt;
&lt;li&gt;Container restarts due to memory limits without application errors&lt;/li&gt;
&lt;li&gt;Browser launch operations timing out due to resource exhaustion&lt;/li&gt;
&lt;li&gt;Server becoming unresponsive during peak traffic periods&lt;/li&gt;
&lt;li&gt;Logs appearing fragmented across multiple Chrome process outputs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;The zombie process issue affects deployments across multiple dimensions:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Container Deployments&lt;/strong&gt;: Docker and Kubernetes environments suffer most severely. Containers typically run with memory ceilings (512MB-2GB), and each orphaned Chrome process consumes a substantial portion of that allocation. The OOM killer terminates containers abruptly, causing request failures and potential data loss.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Long-Running Server Applications&lt;/strong&gt;: Web servers and background services running Puppeteer for PDF generation accumulate zombie processes over days or weeks of operation. The gradual memory growth is often mistaken for a memory leak in application code rather than orphaned browser processes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Serverless Functions&lt;/strong&gt;: AWS Lambda, Azure Functions, and Google Cloud Functions face unique challenges. Each function invocation may leave behind processes that persist beyond the function's execution timeout, consuming resources from subsequent invocations in warm containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;CI/CD Pipelines&lt;/strong&gt;: Build servers running Puppeteer for visual testing or screenshot generation accumulate zombie processes across multiple builds. Shared build agents eventually require manual intervention or restarts.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linux Environments&lt;/strong&gt;: Linux deployments face additional complexity because of how the kernel handles orphaned processes. When a parent process terminates without properly reaping its children, those children become zombies attached to PID 1 (init), where they remain until explicitly killed.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence from the Developer Community
&lt;/h2&gt;

&lt;p&gt;The zombie process problem is documented across GitHub issues, technical blogs, and developer forums spanning several years.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2019-01-15&lt;/td&gt;
&lt;td&gt;Page.Dispose() never completing reported&lt;/td&gt;
&lt;td&gt;GitHub Issue #122&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020-02-15&lt;/td&gt;
&lt;td&gt;Chrome zombie processes in Docker documented&lt;/td&gt;
&lt;td&gt;GitHub puppeteer Issue #5645&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2021-08-17&lt;/td&gt;
&lt;td&gt;DisposeAsync hanging in Docker reported&lt;/td&gt;
&lt;td&gt;GitHub PuppeteerSharp Issue #1489&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-06-01&lt;/td&gt;
&lt;td&gt;Zombie Chrome processes in Kubernetes clusters&lt;/td&gt;
&lt;td&gt;GitHub Issue #8695&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-04-10&lt;/td&gt;
&lt;td&gt;Multiple browser instances not closing properly&lt;/td&gt;
&lt;td&gt;GitHub puppeteer Issue #10030&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024-01-15&lt;/td&gt;
&lt;td&gt;Zombie Chrome processes in Docker/Kubernetes&lt;/td&gt;
&lt;td&gt;GitHub puppeteer Issue #12854&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024-06-20&lt;/td&gt;
&lt;td&gt;Browser version mismatch causing failures&lt;/td&gt;
&lt;td&gt;Multiple GitHub discussions&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Community Reports
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"We found 47 orphaned Chrome processes on our production server. Each was consuming 150-200MB of RAM. The application logs showed all browsers had been properly closed."&lt;br&gt;
— DevOps Engineer, Reddit r/node, 2023&lt;/p&gt;

&lt;p&gt;"When running PuppeteerSharp with Docker, I'm finding quite a lot of zombie Chrome processes that never get killed. Even using tini as an entry point didn't resolve the issue."&lt;br&gt;
— Developer, GitHub Issue #1489&lt;/p&gt;

&lt;p&gt;"The browser.close() call completes successfully according to our logs, but the Chrome processes remain. We've resorted to periodically running pkill -f chromium in a cron job."&lt;br&gt;
— Developer, Stack Overflow, 2023&lt;/p&gt;

&lt;p&gt;"After upgrading Chrome, our entire PDF generation pipeline broke. The library version no longer matched the browser version, and we had no way to know until production failed."&lt;br&gt;
— Developer, GitHub Discussion, 2024&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Teams have reported that a healthy Puppeteer deployment typically shows 2-3 Chrome processes, but zombie accumulation can push this to 30+ processes before intervention becomes necessary.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;p&gt;The zombie process problem stems from several interconnected factors in Puppeteer's architecture and its interaction with operating systems.&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket Communication Failures
&lt;/h3&gt;

&lt;p&gt;Puppeteer communicates with Chrome through WebSocket connections. When network conditions, system load, or timing issues cause the WebSocket connection to fail before the close command completes, the browser process receives no termination signal. The process continues running, believing it still has an active client.&lt;/p&gt;

&lt;h3&gt;
  
  
  Process Tree Management
&lt;/h3&gt;

&lt;p&gt;Chrome spawns multiple child processes that form a process tree. The main browser process is the parent of GPU processes, utility processes, and renderer processes. When the parent process terminates abnormally, its children may not receive termination signals, especially on Linux where SIGTERM propagation depends on process group configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Docker and Container Isolation
&lt;/h3&gt;

&lt;p&gt;Containers complicate process management significantly. The PID namespace isolation means Chrome processes see a different process hierarchy than the host system. Without an init process (like &lt;code&gt;tini&lt;/code&gt; or Docker's &lt;code&gt;--init&lt;/code&gt; flag), zombie processes cannot be reaped properly because there is no PID 1 process designed to adopt orphans.&lt;/p&gt;

&lt;h3&gt;
  
  
  Async Disposal Race Conditions
&lt;/h3&gt;

&lt;p&gt;PuppeteerSharp's &lt;code&gt;DisposeAsync()&lt;/code&gt; implementation has documented edge cases where the disposal task never completes. The method internally waits for the browser process to acknowledge shutdown, but if the acknowledgment is lost or delayed, the disposal hangs indefinitely. Developers have reported that &lt;code&gt;DisposeAsync()&lt;/code&gt; calls simply never return in certain Docker configurations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Version Management Complexity
&lt;/h3&gt;

&lt;p&gt;Puppeteer downloads and manages its own Chromium version. When library updates change the expected Chromium version, existing deployments can break. Auto-update mechanisms in CI/CD environments can inadvertently upgrade Puppeteer without upgrading Chromium, or vice versa, causing version mismatches that manifest as silent failures or zombie processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Scattered Logging
&lt;/h3&gt;

&lt;p&gt;Debugging zombie processes requires examining logs from multiple sources: the Node.js or .NET application, each Chrome process, and system logs. Chrome processes write to their own stdout/stderr streams, which may not be captured by application logging. This makes it difficult to correlate browser behavior with application state.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds
&lt;/h2&gt;

&lt;p&gt;The developer community has developed various strategies to manage zombie processes, each with significant trade-offs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workaround 1: Using Docker's Init Process
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Run containers with an init process that properly reaps zombie children.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; node:18-slim&lt;/span&gt;

&lt;span class="c"&gt;# Install tini for proper process supervision&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; tini

&lt;span class="c"&gt;# Install Chrome dependencies&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    chromium &lt;span class="se"&gt;\
&lt;/span&gt;    fonts-liberation &lt;span class="se"&gt;\
&lt;/span&gt;    libasound2 &lt;span class="se"&gt;\
&lt;/span&gt;    libatk-bridge2.0-0 &lt;span class="se"&gt;\
&lt;/span&gt;    libatk1.0-0 &lt;span class="se"&gt;\
&lt;/span&gt;    libcups2 &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="nt"&gt;--no-install-recommends&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["/usr/bin/tini", "--"]&lt;/span&gt;
&lt;span class="k"&gt;CMD&lt;/span&gt;&lt;span class="s"&gt; ["node", "app.js"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or using Docker's built-in init:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--init&lt;/span&gt; &lt;span class="nt"&gt;--memory&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;1g your-puppeteer-app
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only addresses zombie reaping, not the root cause of failed disposals&lt;/li&gt;
&lt;li&gt;Requires container configuration changes that may conflict with existing infrastructure&lt;/li&gt;
&lt;li&gt;Does not prevent memory consumption before zombies are reaped&lt;/li&gt;
&lt;li&gt;Cannot prevent processes from becoming zombies in the first place&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Aggressive Process Killing
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Periodically kill all Chrome processes and restart the browser pool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;execSync&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Kill all Chrome processes - nuclear option&lt;/span&gt;
&lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;killAllChromeProcesses&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;linux&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pkill -9 -f chromium || true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="nf"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pkill -9 -f chrome || true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;else&lt;/span&gt; &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;platform&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;darwin&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nf"&gt;execSync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pkill -9 -f "Google Chrome" || true&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Ignore errors - processes may not exist&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Run periodically&lt;/span&gt;
&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;killAllChromeProcesses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;60000&lt;/span&gt; &lt;span class="o"&gt;*&lt;/span&gt; &lt;span class="mi"&gt;30&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Every 30 minutes&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Kills active browser sessions, causing in-flight requests to fail&lt;/li&gt;
&lt;li&gt;Creates race conditions with ongoing PDF generation&lt;/li&gt;
&lt;li&gt;Not suitable for high-availability deployments&lt;/li&gt;
&lt;li&gt;Crude approach that indicates architectural problems&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: Browser Instance Pooling with Timeout
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Maintain a pool of browser instances with forced recycling after a time limit.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kd"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BrowserPool&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nf"&gt;constructor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;maxAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;300000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;maxInstances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxAge&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxInstances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;maxInstances&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[];&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;getBrowser&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Remove expired instances&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="k"&gt;for &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="k"&gt;of&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;now&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;createdAt&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxAge&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;destroyInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;filter&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyed&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Find available instance or create new one&lt;/span&gt;
        &lt;span class="kd"&gt;let&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inUse&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;length&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;maxInstances&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createInstance&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;push&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inUse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;No available browser instances&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;createInstance&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
            &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;args&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--no-sandbox&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;--disable-dev-shm-usage&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
        &lt;span class="p"&gt;});&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;createdAt&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;Date&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;now&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
            &lt;span class="na"&gt;inUse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="na"&gt;destroyed&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;
        &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="nf"&gt;destroyInstance&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;destroyed&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nb"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;race&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
                &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;close&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
                &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Promise&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="nx"&gt;_&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt;
                    &lt;span class="nf"&gt;setTimeout&lt;/span&gt;&lt;span class="p"&gt;(()&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;reject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;Close timeout&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)),&lt;/span&gt; &lt;span class="mi"&gt;5000&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
                &lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;]);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;error&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Force kill if close times out&lt;/span&gt;
            &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;pid&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;()?.&lt;/span&gt;&lt;span class="nx"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="k"&gt;try&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="nx"&gt;process&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;kill&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;pid&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;SIGKILL&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;catch &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;e&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
                    &lt;span class="c1"&gt;// Process may already be dead&lt;/span&gt;
                &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="nf"&gt;release&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;instance&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;instances&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;find&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;i&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;i&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;===&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="nx"&gt;instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;inUse&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Complex implementation with potential for bugs&lt;/li&gt;
&lt;li&gt;Forced destruction can still leave zombie child processes&lt;/li&gt;
&lt;li&gt;Pool management adds latency and resource overhead&lt;/li&gt;
&lt;li&gt;Does not solve the fundamental disposal problem&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 4: Monitor and Alert on Process Count
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Track Chrome process count and alert when it exceeds thresholds.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;exec&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;child_process&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;promisify&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;util&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;execAsync&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;promisify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;exec&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;countChromeProcesses&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;stdout&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;execAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;pgrep -c chromium || echo 0&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;parseInt&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;stdout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;trim&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;monitorProcesses&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;countChromeProcesses&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;expectedMax&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="mi"&gt;6&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 2 browsers * 3 processes each&lt;/span&gt;

    &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;expectedMax&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="nx"&gt;console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`WARNING: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;count&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt; Chrome processes detected (expected max: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;expectedMax&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;)`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="c1"&gt;// Send alert to monitoring system&lt;/span&gt;
        &lt;span class="c1"&gt;// Consider triggering cleanup or restart&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="nf"&gt;setInterval&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;monitorProcesses&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;30000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Reactive rather than preventive&lt;/li&gt;
&lt;li&gt;Requires external monitoring infrastructure&lt;/li&gt;
&lt;li&gt;Alert fatigue if thresholds are too sensitive&lt;/li&gt;
&lt;li&gt;Does not fix the underlying issue&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 5: Version Pinning
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Pin both Puppeteer and Chromium versions to prevent auto-update breakage.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"dependencies"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"puppeteer"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"21.5.0"&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;require&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;puppeteer&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;launchWithSpecificVersion&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;puppeteer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;launch&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="na"&gt;executablePath&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;/usr/bin/chromium-browser&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="c1"&gt;// Use system Chromium&lt;/span&gt;
        &lt;span class="na"&gt;headless&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;new&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt;
    &lt;span class="p"&gt;});&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;browser&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Security updates require manual intervention&lt;/li&gt;
&lt;li&gt;System Chromium may have different behavior than bundled version&lt;/li&gt;
&lt;li&gt;Coordination required across development, staging, and production&lt;/li&gt;
&lt;li&gt;Does not prevent zombie processes, only reduces one cause&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Different Approach: IronPDF
&lt;/h2&gt;

&lt;p&gt;For .NET applications where managing Chromium processes has become a maintenance burden, IronPDF offers an alternative that eliminates the process management problem entirely. Instead of spawning external browser processes that must be tracked and disposed, IronPDF embeds the Chrome rendering engine within the .NET process itself.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why IronPDF Avoids Zombie Processes
&lt;/h3&gt;

&lt;p&gt;IronPDF's architecture is fundamentally different from Puppeteer's external process model:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Single Process Architecture&lt;/strong&gt;: The Chrome rendering engine runs as part of the .NET application process, not as a separate executable. There are no external Chrome processes to become zombies because there are no external processes at all.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Standard .NET Disposal&lt;/strong&gt;: Memory and resources are managed through normal .NET garbage collection and &lt;code&gt;IDisposable&lt;/code&gt; patterns. When a &lt;code&gt;PdfDocument&lt;/code&gt; is disposed, its resources are released through the same mechanisms as any other .NET object.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No WebSocket Communication&lt;/strong&gt;: Without external processes, there is no WebSocket protocol layer that can fail, time out, or lose messages. Commands execute directly within the application's memory space.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Version Coordination&lt;/strong&gt;: The rendering engine version is fixed to the IronPDF library version. Upgrading IronPDF upgrades the rendering engine automatically, eliminating version mismatch issues.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Unified Logging&lt;/strong&gt;: All rendering activity occurs within the application process, meaning logs appear in the application's standard output without scattering across multiple process streams.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Threading.Tasks&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// PDF generation service demonstrating process-stable operation&lt;/span&gt;
&lt;span class="c1"&gt;// No external Chrome processes to manage or monitor&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;StablePdfService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ChromePdfRenderer&lt;/span&gt; &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;StablePdfService&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Initialize renderer once - no browser launch needed&lt;/span&gt;
        &lt;span class="n"&gt;_renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure rendering options&lt;/span&gt;
        &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GeneratePdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Render HTML to PDF - no external process spawned&lt;/span&gt;
        &lt;span class="c1"&gt;// No zombie process possible because no process is created&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="c1"&gt;// Memory released through standard .NET disposal&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GenerateBatchAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;htmlDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;List&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="k"&gt;]&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Process multiple PDFs without process accumulation&lt;/span&gt;
        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;htmlDocuments&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="c1"&gt;// Each PDF is fully released before the next begins&lt;/span&gt;
            &lt;span class="c1"&gt;// No process monitoring required&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;results&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GenerateFromUrl&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Render external URL with JavaScript execution&lt;/span&gt;
        &lt;span class="c1"&gt;// Chrome engine runs internally, not as separate process&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderUrlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Docker deployment - no init process or process supervision required&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DockerCompatibleService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GenerateInContainer&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Works in standard Docker containers without --init flag&lt;/span&gt;
        &lt;span class="c1"&gt;// No zombie processes to reap because no external processes exist&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points about this code:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No browser launch, close, or disposal methods to call&lt;/li&gt;
&lt;li&gt;No WebSocket connections that can fail or time out&lt;/li&gt;
&lt;li&gt;Standard &lt;code&gt;using&lt;/code&gt; statements handle all resource cleanup&lt;/li&gt;
&lt;li&gt;Process count remains constant regardless of PDF volume&lt;/li&gt;
&lt;li&gt;Container deployments require no special configuration&lt;/li&gt;
&lt;li&gt;Logs appear in application output, not scattered across processes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For more details on the methods used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer&lt;/a&gt; - Main rendering class&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/examples/using-html-to-create-a-pdf/" rel="noopener noreferrer"&gt;RenderHtmlAsPdf&lt;/a&gt; - HTML to PDF conversion&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/how-to/url-to-pdf/" rel="noopener noreferrer"&gt;RenderUrlAsPdf&lt;/a&gt; - URL to PDF conversion&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/how-to/docker-linux/" rel="noopener noreferrer"&gt;Docker Deployment Guide&lt;/a&gt; - Container configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;p&gt;IronPDF is commercial software requiring a license for production deployment. Licenses are per-developer and include deployment to unlimited servers. A free trial is available for evaluation. Teams should weigh licensing costs against the engineering time currently spent managing Puppeteer processes and the infrastructure costs of running containers with extra headroom for zombie processes.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Differences
&lt;/h3&gt;

&lt;p&gt;Puppeteer exposes browser automation primitives (launch browser, create page, navigate, execute script, generate PDF). IronPDF provides a direct path from HTML to PDF without the browser automation layer. Migration involves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Removing &lt;code&gt;Puppeteer.launch()&lt;/code&gt; / &lt;code&gt;BrowserFetcher&lt;/code&gt; code entirely&lt;/li&gt;
&lt;li&gt;Replacing page creation and navigation with &lt;code&gt;RenderHtmlAsPdf()&lt;/code&gt; or &lt;code&gt;RenderUrlAsPdf()&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Removing disposal code for browsers and pages&lt;/li&gt;
&lt;li&gt;Removing process monitoring and cleanup infrastructure&lt;/li&gt;
&lt;li&gt;Removing Docker init process configuration&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For applications using Puppeteer purely for PDF generation, this simplifies the codebase significantly. For applications using Puppeteer for other browser automation (testing, scraping), IronPDF addresses only the PDF portion.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Zero external processes to manage, monitor, or clean up&lt;/li&gt;
&lt;li&gt;No zombie process accumulation under any load conditions&lt;/li&gt;
&lt;li&gt;Predictable memory usage bounded by application behavior&lt;/li&gt;
&lt;li&gt;Simplified Docker deployments without init processes&lt;/li&gt;
&lt;li&gt;Unified logging through application output&lt;/li&gt;
&lt;li&gt;No version coordination between library and browser&lt;/li&gt;
&lt;li&gt;Consistent behavior across Windows, Linux, and macOS&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Commercial licensing versus open-source Puppeteer&lt;/li&gt;
&lt;li&gt;IronPDF is specific to PDF generation; Puppeteer offers broader browser automation&lt;/li&gt;
&lt;li&gt;Different rendering engine may produce slightly different output&lt;/li&gt;
&lt;li&gt;Initial integration adds the IronPDF package (approximately 150MB)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Puppeteer's external process architecture creates inherent challenges when browser disposal fails. Zombie Chrome processes accumulate under load, exhaust container memory limits, and scatter debugging information across multiple process outputs. Version management between library and browser adds another failure mode. For .NET applications where PDF generation is the primary use case, IronPDF eliminates these issues by removing external processes from the architecture entirely.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/jacob-mellor" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt; is CTO at Iron Software and built the company's core codebase, pioneering C# PDF technology.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/hardkoded/puppeteer-sharp/issues/122" rel="noopener noreferrer"&gt;Page.Dispose() never completing - GitHub Issue #122&lt;/a&gt;{:rel="nofollow"} - Early disposal issue documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/hardkoded/puppeteer-sharp/issues/1489" rel="noopener noreferrer"&gt;DisposeAsync hanging in Docker - GitHub Issue #1489&lt;/a&gt;{:rel="nofollow"} - PuppeteerSharp disposal hanging&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/puppeteer/puppeteer/issues/5645" rel="noopener noreferrer"&gt;Chrome zombie processes in Docker - GitHub Issue #5645&lt;/a&gt;{:rel="nofollow"} - Container zombie process reports&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/puppeteer/puppeteer/issues/8695" rel="noopener noreferrer"&gt;Docker container memory always increasing - GitHub Issue #8695&lt;/a&gt;{:rel="nofollow"} - Memory growth in containers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/puppeteer/puppeteer/issues/12854" rel="noopener noreferrer"&gt;Zombie Chrome processes in Docker/Kubernetes - GitHub Issue #12854&lt;/a&gt;{:rel="nofollow"} - Orchestration environment issues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/puppeteer/puppeteer/issues/10030" rel="noopener noreferrer"&gt;Browser instances not closing properly - GitHub Issue #10030&lt;/a&gt;{:rel="nofollow"} - Multiple browser disposal failures&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@rajesh.pal53/puppeteer-zombie-process-solution-0475e4f113e6" rel="noopener noreferrer"&gt;Puppeteer Zombie Process Solution - Medium&lt;/a&gt;{:rel="nofollow"} - Community workaround documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pptr.dev/troubleshooting" rel="noopener noreferrer"&gt;Puppeteer Troubleshooting Guide&lt;/a&gt;{:rel="nofollow"} - Official troubleshooting documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://devforth.io/blog/how-to-simply-workaround-ram-leaking-libraries-like-puppeteer-universal-way-to-fix-ram-leaks-once-and-forever/" rel="noopener noreferrer"&gt;How to workaround RAM-leaking libraries like Puppeteer - DevForth&lt;/a&gt;{:rel="nofollow"} - Memory management strategies&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://medium.com/@matveev.dina/the-hidden-cost-of-headless-browsers-a-puppeteer-memory-leak-journey-027e41291367" rel="noopener noreferrer"&gt;The Hidden Cost of Headless Browsers - Medium&lt;/a&gt;{:rel="nofollow"} - Production memory leak journey&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For the latest IronPDF documentation and tutorials, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>FO.NET vs IronPDF: an unbiased look for .NET teams</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Mon, 06 Apr 2026 12:54:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/fonet-vs-ironpdf-an-unbiased-look-for-net-teams-3k25</link>
      <guid>https://dev.to/ironsoftware/fonet-vs-ironpdf-an-unbiased-look-for-net-teams-3k25</guid>
      <description>&lt;p&gt;Picture a scenario common in enterprise .NET environments: a report generation system built in 2012 using FO.NET suddenly needs updates for compliance reporting, but the original library has been dormant on CodePlex for nearly a decade, the maintainer unreachable, and .NET 6 deployment throws compatibility warnings. This isn't hypothetical—teams encounter this situation when legacy XSL-FO pipelines collide with modern infrastructure requirements. FO.NET was designed for precise XML-based page layout, targeting applications where data arrives as XML and must render with millimeter-level positioning accuracy.&lt;/p&gt;

&lt;p&gt;IronPDF approaches document generation from the opposite direction: it assumes your layout is expressed in HTML/CSS (the universal design language of the web) and renders PDFs using a Chromium engine. This architectural choice reflects the reality of 2026 .NET development, where most teams already use HTML for web UIs and prefer reusing those skills for PDF generation rather than learning XSL-FO's specialized syntax.&lt;/p&gt;

&lt;h2&gt;
  
  
  Understanding IronPDF
&lt;/h2&gt;

&lt;p&gt;IronPDF is a .NET library built around HTML-to-PDF conversion, leveraging Chromium's rendering engine to produce PDFs that match browser output. Teams adopt it when they need to convert web pages, Razor views, or dynamically generated HTML into distributable documents. The library handles modern CSS (Grid, Flexbox), JavaScript execution, and web fonts, ensuring that complex layouts render correctly without manual coordinate positioning.&lt;/p&gt;

&lt;p&gt;Beyond rendering, IronPDF provides full PDF lifecycle management: merging documents, extracting text, filling forms, applying digital signatures, encrypting files, and manipulating pages. The API is designed for developers already familiar with HTML/CSS, eliminating the learning curve associated with XSL-FO's formatting object model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Limitations of FO.NET
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Product Status
&lt;/h3&gt;

&lt;p&gt;FO.NET is effectively discontinued. The original CodePlex project is defunct. Several GitHub forks exist (nholik, hahmed, leekelleher) but show minimal activity post-2018. No official maintainer, no roadmap, no security patches. Teams using FO.NET are maintaining legacy code with no upstream support.&lt;/p&gt;

&lt;h3&gt;
  
  
  Missing Capabilities
&lt;/h3&gt;

&lt;p&gt;No .NET Core or .NET 5+ support in any known fork. XSL-FO spec is frozen (W3C Recommendation from 2006); no modern CSS features. Cannot render HTML directly—requires XSLT transformation to XSL-FO first. No built-in support for interactive PDF forms, digital signatures, or modern encryption standards (AES-256).&lt;/p&gt;

&lt;h3&gt;
  
  
  Technical Issues
&lt;/h3&gt;

&lt;p&gt;XSL-FO learning curve is steep: developers must learn formatting objects (&lt;code&gt;fo:block&lt;/code&gt;, &lt;code&gt;fo:table&lt;/code&gt;, &lt;code&gt;fo:page-sequence&lt;/code&gt;) instead of reusing HTML/CSS knowledge. XSLT transformations add a pre-processing step. Font embedding is manual and error-prone. Limited Unicode support depending on font configuration. Performance degrades with large documents or complex tables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Support Status
&lt;/h3&gt;

&lt;p&gt;No commercial support available. Community support via GitHub forks is sporadic. Documentation is primarily the W3C XSL-FO spec plus Apache FOP guides (Java-focused). Troubleshooting requires forum archaeology or source code diving.&lt;/p&gt;

&lt;h3&gt;
  
  
  Architecture Problems
&lt;/h3&gt;

&lt;p&gt;Two-stage pipeline (XML → XSL-FO → PDF) adds failure points. XSLT debugging is notoriously difficult. Cannot leverage modern web design tools (browser DevTools, CSS frameworks). Tight coupling to XML data sources—JSON or object models require conversion. No browser-based preview; must generate PDF to see results.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Comparison Overview
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Aspect&lt;/th&gt;
&lt;th&gt;FO.NET&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Current Status&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Discontinued/unmaintained forks&lt;/td&gt;
&lt;td&gt;Active commercial development&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;HTML Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;No (XSL-FO only)&lt;/td&gt;
&lt;td&gt;Full HTML5/CSS3/JavaScript&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Rendering Quality&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Coordinate-based precision&lt;/td&gt;
&lt;td&gt;Chromium pixel-perfect&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Installation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Manual DLL or unofficial NuGet&lt;/td&gt;
&lt;td&gt;Official NuGet, self-contained&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Commercial SLA available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Future Viability&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Legacy maintenance only&lt;/td&gt;
&lt;td&gt;Continuous updates&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Troubleshooting Scenario: Page Break Issues
&lt;/h2&gt;

&lt;h3&gt;
  
  
  FO.NET — XSL-FO Page Break Control
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- XSL-FO document structure (verify syntax in W3C spec) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;fo:root&lt;/span&gt; &lt;span class="na"&gt;xmlns:fo=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/1999/XSL/Format"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;fo:layout-master-set&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fo:simple-page-master&lt;/span&gt; &lt;span class="na"&gt;master-name=&lt;/span&gt;&lt;span class="s"&gt;"A4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;fo:region-body&lt;/span&gt; &lt;span class="na"&gt;margin=&lt;/span&gt;&lt;span class="s"&gt;"1in"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fo:simple-page-master&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/fo:layout-master-set&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;fo:page-sequence&lt;/span&gt; &lt;span class="na"&gt;master-reference=&lt;/span&gt;&lt;span class="s"&gt;"A4"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fo:flow&lt;/span&gt; &lt;span class="na"&gt;flow-name=&lt;/span&gt;&lt;span class="s"&gt;"xsl-region-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-size=&lt;/span&gt;&lt;span class="s"&gt;"18pt"&lt;/span&gt; &lt;span class="na"&gt;space-after=&lt;/span&gt;&lt;span class="s"&gt;"12pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Section 1: Introduction
      &lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;fo:block&amp;gt;&lt;/span&gt;Content for section 1...&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;

      &lt;span class="c"&gt;&amp;lt;!-- Force page break --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;break-before=&lt;/span&gt;&lt;span class="s"&gt;"page"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-size=&lt;/span&gt;&lt;span class="s"&gt;"18pt"&lt;/span&gt; &lt;span class="na"&gt;space-after=&lt;/span&gt;&lt;span class="s"&gt;"12pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Section 2: Details
      &lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;fo:block&amp;gt;&lt;/span&gt;Content for section 2...&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;

      &lt;span class="c"&gt;&amp;lt;!-- Keep content together on same page --&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;keep-together=&lt;/span&gt;&lt;span class="s"&gt;"always"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-weight=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Critical Data:&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;fo:table&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;fo:table-column&lt;/span&gt; &lt;span class="na"&gt;column-width=&lt;/span&gt;&lt;span class="s"&gt;"3in"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;fo:table-column&lt;/span&gt; &lt;span class="na"&gt;column-width=&lt;/span&gt;&lt;span class="s"&gt;"2in"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;fo:table-body&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;fo:table-row&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;fo:table-cell&amp;gt;&amp;lt;fo:block&amp;gt;&lt;/span&gt;Metric A&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;fo:table-cell&amp;gt;&amp;lt;fo:block&amp;gt;&lt;/span&gt;Value 1&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/fo:table-row&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/fo:table-body&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/fo:table&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/fo:flow&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/fo:page-sequence&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fo:root&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// C# code to process XSL-FO (conceptual - verify API in specific FO.NET fork)&lt;/span&gt;
&lt;span class="c1"&gt;// Note: Exact implementation varies by fork and may not work on modern .NET&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Xml&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;FoNetExample&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Typical workflow (verify against fork documentation):&lt;/span&gt;
            &lt;span class="c1"&gt;// 1. Load XSL-FO document&lt;/span&gt;
            &lt;span class="c1"&gt;// 2. Create FO processor&lt;/span&gt;
            &lt;span class="c1"&gt;// 3. Render to PDF&lt;/span&gt;

            &lt;span class="c1"&gt;// WARNING: This is conceptual code&lt;/span&gt;
            &lt;span class="c1"&gt;// FO.NET forks have inconsistent APIs&lt;/span&gt;
            &lt;span class="c1"&gt;// Refer to specific fork documentation&lt;/span&gt;

            &lt;span class="k"&gt;try&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;foDocument&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;XmlDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
                &lt;span class="n"&gt;foDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Load&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"report.fo"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// FO.NET processor creation (API varies by fork)&lt;/span&gt;
                &lt;span class="c1"&gt;// Some forks use: FoNet.Render.Pdf.PdfRenderer&lt;/span&gt;
                &lt;span class="c1"&gt;// Documentation is sparse - expect trial and error&lt;/span&gt;

                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Check fork-specific documentation for exact API"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Error: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common troubleshooting issues:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Page break ignored&lt;/strong&gt;: XSL-FO &lt;code&gt;break-before&lt;/code&gt; may not trigger if preceding content doesn't fill the page; use &lt;code&gt;fo:block&lt;/code&gt; with explicit height to force breaks&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Content split unexpectedly&lt;/strong&gt;: &lt;code&gt;keep-together="always"&lt;/code&gt; can cause overflow errors if content exceeds page height; no automatic graceful degradation&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Table rendering issues&lt;/strong&gt;: Column widths must be explicitly set; auto-sizing doesn't work reliably&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Font embedding failures&lt;/strong&gt;: Fonts must be registered manually; missing fonts cause silent substitution or rendering errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Namespace errors&lt;/strong&gt;: XSL-FO namespace must match exactly: &lt;code&gt;http://www.w3.org/1999/XSL/Format&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No preview workflow&lt;/strong&gt;: Must generate full PDF to see layout; no incremental rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  IronPDF — CSS-Based Page Control
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;IronPdfPageBreakExample&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;htmlWithPageBreaks&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
                &amp;lt;html&amp;gt;
                &amp;lt;head&amp;gt;
                    &amp;lt;style&amp;gt;
                        body { font-family: Arial, sans-serif; }
                        h1 { font-size: 18pt; margin-bottom: 12pt; }
                        .page-break { page-break-before: always; }
                        .keep-together { page-break-inside: avoid; }
                        table { border-collapse: collapse; width: 100%; }
                        td { border: 1px solid #ccc; padding: 8px; }
                    &amp;lt;/style&amp;gt;
                &amp;lt;/head&amp;gt;
                &amp;lt;body&amp;gt;
                    &amp;lt;h1&amp;gt;Section 1: Introduction&amp;lt;/h1&amp;gt;
                    &amp;lt;p&amp;gt;Content for section 1...&amp;lt;/p&amp;gt;

                    &amp;lt;div class='page-break'&amp;gt;&amp;lt;/div&amp;gt;

                    &amp;lt;h1&amp;gt;Section 2: Details&amp;lt;/h1&amp;gt;
                    &amp;lt;p&amp;gt;Content for section 2...&amp;lt;/p&amp;gt;

                    &amp;lt;div class='keep-together'&amp;gt;
                        &amp;lt;strong&amp;gt;Critical Data:&amp;lt;/strong&amp;gt;
                        &amp;lt;table&amp;gt;
                            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Metric A&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Value 1&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
                            &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Metric B&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;Value 2&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
                        &amp;lt;/table&amp;gt;
                    &amp;lt;/div&amp;gt;
                &amp;lt;/body&amp;gt;
                &amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
            &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;72&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// 1 inch = 72 points&lt;/span&gt;
            &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;72&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlWithPageBreaks&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"SectionedReport.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PDF created with controlled page breaks"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;CSS &lt;code&gt;page-break-before&lt;/code&gt; and &lt;code&gt;page-break-inside&lt;/code&gt; work as expected in browsers, making layout predictable. For complex page break scenarios—widow/orphan control, running headers—see &lt;a href="https://ironsoftware.com/suite/blog/using-ironsuite/html-to-pdf-ironpdf-tutorial/" rel="noopener noreferrer"&gt;IronPDF's HTML to PDF guide&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting Scenario: Font Rendering Problems
&lt;/h2&gt;

&lt;h3&gt;
  
  
  FO.NET — Manual Font Configuration
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- XSL-FO font configuration (verify exact syntax in fork docs) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;fo:root&lt;/span&gt; &lt;span class="na"&gt;xmlns:fo=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/1999/XSL/Format"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;fo:layout-master-set&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fo:simple-page-master&lt;/span&gt; &lt;span class="na"&gt;master-name=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;fo:region-body&lt;/span&gt; &lt;span class="na"&gt;margin=&lt;/span&gt;&lt;span class="s"&gt;"1in"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fo:simple-page-master&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/fo:layout-master-set&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;fo:page-sequence&lt;/span&gt; &lt;span class="na"&gt;master-reference=&lt;/span&gt;&lt;span class="s"&gt;"main"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fo:flow&lt;/span&gt; &lt;span class="na"&gt;flow-name=&lt;/span&gt;&lt;span class="s"&gt;"xsl-region-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-family=&lt;/span&gt;&lt;span class="s"&gt;"Arial"&lt;/span&gt; &lt;span class="na"&gt;font-size=&lt;/span&gt;&lt;span class="s"&gt;"12pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Standard Arial text
      &lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-family=&lt;/span&gt;&lt;span class="s"&gt;"CustomFont"&lt;/span&gt; &lt;span class="na"&gt;font-size=&lt;/span&gt;&lt;span class="s"&gt;"14pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Custom font text (requires font file registration)
      &lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-family=&lt;/span&gt;&lt;span class="s"&gt;"Arial"&lt;/span&gt; &lt;span class="na"&gt;font-weight=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        Bold text
      &lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/fo:flow&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/fo:page-sequence&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fo:root&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common font troubleshooting:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Font not found&lt;/strong&gt;: FO.NET doesn't auto-discover system fonts; must register font files in configuration (exact method varies by fork)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Fallback substitution&lt;/strong&gt;: If specified font missing, FO.NET silently uses default sans-serif; no warning or error&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bold/italic failures&lt;/strong&gt;: Font variations (Arial Bold, Arial Italic) must be registered separately as distinct font families&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Unicode characters missing&lt;/strong&gt;: Font must contain glyphs for characters used; limited Unicode support depending on font&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Embedding issues&lt;/strong&gt;: PDF may not embed fonts correctly, causing rendering problems on different systems&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Configuration file complexity&lt;/strong&gt;: Font registration typically requires XML config file with exact paths to TTF files&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  IronPDF — Automatic Font Handling
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;IronPdfFontExample&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;htmlWithFonts&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
                &amp;lt;html&amp;gt;
                &amp;lt;head&amp;gt;
                    &amp;lt;style&amp;gt;
                        body { font-family: Arial, sans-serif; }
                        .custom-font { font-family: 'Roboto', Arial, sans-serif; }
                        .bold-text { font-weight: bold; }
                    &amp;lt;/style&amp;gt;
                    &amp;lt;link href='https://fonts.googleapis.com/css2?family=Roboto:wght@400;700&amp;amp;display=swap'
                          rel='stylesheet'&amp;gt;
                &amp;lt;/head&amp;gt;
                &amp;lt;body&amp;gt;
                    &amp;lt;p&amp;gt;Standard Arial text&amp;lt;/p&amp;gt;
                    &amp;lt;p class='custom-font'&amp;gt;Custom Roboto font text&amp;lt;/p&amp;gt;
                    &amp;lt;p class='bold-text'&amp;gt;Bold text&amp;lt;/p&amp;gt;
                    &amp;lt;p&amp;gt;Unicode test: こんにちは 你好 مرحبا&amp;lt;/p&amp;gt;
                &amp;lt;/body&amp;gt;
                &amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PrintHtmlBackgrounds&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlWithFonts&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"FontTestReport.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"PDF with various fonts created"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;IronPDF's Chromium engine handles fonts like a browser: system fonts work automatically, web fonts load from CDNs, and Unicode support is comprehensive. No manual configuration required.&lt;/p&gt;

&lt;h2&gt;
  
  
  Troubleshooting Scenario: Dynamic Table Generation
&lt;/h2&gt;

&lt;h3&gt;
  
  
  FO.NET — XSL-FO Table Construction
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- XSL-FO table with data binding (typically generated via XSLT) --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;fo:root&lt;/span&gt; &lt;span class="na"&gt;xmlns:fo=&lt;/span&gt;&lt;span class="s"&gt;"http://www.w3.org/1999/XSL/Format"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;fo:layout-master-set&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fo:simple-page-master&lt;/span&gt; &lt;span class="na"&gt;master-name=&lt;/span&gt;&lt;span class="s"&gt;"table-page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;fo:region-body&lt;/span&gt; &lt;span class="na"&gt;margin=&lt;/span&gt;&lt;span class="s"&gt;"0.5in"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;/fo:simple-page-master&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/fo:layout-master-set&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;fo:page-sequence&lt;/span&gt; &lt;span class="na"&gt;master-reference=&lt;/span&gt;&lt;span class="s"&gt;"table-page"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;fo:flow&lt;/span&gt; &lt;span class="na"&gt;flow-name=&lt;/span&gt;&lt;span class="s"&gt;"xsl-region-body"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;

      &lt;span class="nt"&gt;&amp;lt;fo:table&lt;/span&gt; &lt;span class="na"&gt;table-layout=&lt;/span&gt;&lt;span class="s"&gt;"fixed"&lt;/span&gt; &lt;span class="na"&gt;width=&lt;/span&gt;&lt;span class="s"&gt;"100%"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;fo:table-column&lt;/span&gt; &lt;span class="na"&gt;column-width=&lt;/span&gt;&lt;span class="s"&gt;"proportional-column-width(2)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;fo:table-column&lt;/span&gt; &lt;span class="na"&gt;column-width=&lt;/span&gt;&lt;span class="s"&gt;"proportional-column-width(1)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;fo:table-column&lt;/span&gt; &lt;span class="na"&gt;column-width=&lt;/span&gt;&lt;span class="s"&gt;"proportional-column-width(1)"&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;fo:table-header&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;fo:table-row&lt;/span&gt; &lt;span class="na"&gt;background-color=&lt;/span&gt;&lt;span class="s"&gt;"#cccccc"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;fo:table-cell&lt;/span&gt; &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"1pt solid black"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"4pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-weight=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Product&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;fo:table-cell&lt;/span&gt; &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"1pt solid black"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"4pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-weight=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Quantity&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;fo:table-cell&lt;/span&gt; &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"1pt solid black"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"4pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;fo:block&lt;/span&gt; &lt;span class="na"&gt;font-weight=&lt;/span&gt;&lt;span class="s"&gt;"bold"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;Price&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/fo:table-row&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/fo:table-header&amp;gt;&lt;/span&gt;

        &lt;span class="nt"&gt;&amp;lt;fo:table-body&amp;gt;&lt;/span&gt;
          &lt;span class="c"&gt;&amp;lt;!-- Data rows - typically generated via XSLT loop --&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;fo:table-row&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;fo:table-cell&lt;/span&gt; &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"1pt solid black"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"4pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;fo:block&amp;gt;&lt;/span&gt;Item A&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;fo:table-cell&lt;/span&gt; &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"1pt solid black"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"4pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;fo:block&amp;gt;&lt;/span&gt;100&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;fo:table-cell&lt;/span&gt; &lt;span class="na"&gt;border=&lt;/span&gt;&lt;span class="s"&gt;"1pt solid black"&lt;/span&gt; &lt;span class="na"&gt;padding=&lt;/span&gt;&lt;span class="s"&gt;"4pt"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
              &lt;span class="nt"&gt;&amp;lt;fo:block&amp;gt;&lt;/span&gt;$50.00&lt;span class="nt"&gt;&amp;lt;/fo:block&amp;gt;&lt;/span&gt;
            &lt;span class="nt"&gt;&amp;lt;/fo:table-cell&amp;gt;&lt;/span&gt;
          &lt;span class="nt"&gt;&amp;lt;/fo:table-row&amp;gt;&lt;/span&gt;
        &lt;span class="nt"&gt;&amp;lt;/fo:table-body&amp;gt;&lt;/span&gt;
      &lt;span class="nt"&gt;&amp;lt;/fo:table&amp;gt;&lt;/span&gt;

    &lt;span class="nt"&gt;&amp;lt;/fo:flow&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/fo:page-sequence&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/fo:root&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Common table troubleshooting:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Column width calculation errors&lt;/strong&gt;: &lt;code&gt;proportional-column-width()&lt;/code&gt; doesn't always distribute space as expected; fixed widths more reliable&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Border rendering gaps&lt;/strong&gt;: Borders may not align correctly at cell intersections; workaround involves careful padding/border settings&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Header repetition on page breaks&lt;/strong&gt;: &lt;code&gt;fo:table-header&lt;/code&gt; should repeat on each page, but implementation varies by fork&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cell content overflow&lt;/strong&gt;: Long text in cells doesn't wrap automatically; must use &lt;code&gt;wrap-option="wrap"&lt;/code&gt; and test thoroughly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance degradation&lt;/strong&gt;: Large tables (1000+ rows) can cause severe slowdowns; XSL-FO processors aren't optimized for data tables&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No auto-sizing&lt;/strong&gt;: Column widths must be calculated manually; no "fit content to column" feature&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  IronPDF — HTML Table Rendering
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Text&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;namespace&lt;/span&gt; &lt;span class="nn"&gt;IronPdfTableExample&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;Program&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;Main&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;tableHtml&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GenerateTableHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;1000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Generate large table&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tableHtml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"LargeDataTable.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Large table PDF created"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="k"&gt;static&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GenerateTableHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;rowCount&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringBuilder&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;head&amp;gt;&amp;lt;style&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"table { width: 100%; border-collapse: collapse; }"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"th { background-color: #ccc; padding: 8px; border: 1px solid black; }"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"td { padding: 8px; border: 1px solid black; }"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"thead { display: table-header-group; }"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Repeat header&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;/style&amp;gt;&amp;lt;/head&amp;gt;&amp;lt;body&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;table&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;thead&amp;gt;&amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Product&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Quantity&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&amp;lt;/thead&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;tbody&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;rowCount&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"&amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Item &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;10&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;*&lt;/span&gt; &lt;span class="m"&gt;5.50&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="n"&gt;F2&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;

            &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;AppendLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;/tbody&amp;gt;&amp;lt;/table&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;sb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;HTML tables handle automatic column sizing, text wrapping, and header repetition without manual intervention. The &lt;code&gt;thead&lt;/code&gt; element automatically repeats on page breaks.&lt;/p&gt;

&lt;h2&gt;
  
  
  API Mapping Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;FO.NET Operation&lt;/th&gt;
&lt;th&gt;XSL-FO Syntax&lt;/th&gt;
&lt;th&gt;IronPDF Equivalent&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Page setup&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;fo:simple-page-master&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderingOptions.PaperSize&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;XSL-FO: XML config; IronPDF: property&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Margins&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;fo:region-body margin=""&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderingOptions.MarginTop/Bottom/etc&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FO.NET: layout master; IronPDF: options&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Font selection&lt;/td&gt;
&lt;td&gt;&lt;code&gt;font-family="Arial"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CSS &lt;code&gt;font-family: Arial;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;XSL-FO: attribute; IronPDF: CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Bold text&lt;/td&gt;
&lt;td&gt;&lt;code&gt;font-weight="bold"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CSS &lt;code&gt;font-weight: bold;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Same concept, different syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page breaks&lt;/td&gt;
&lt;td&gt;&lt;code&gt;break-before="page"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CSS &lt;code&gt;page-break-before: always;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;XSL-FO: attribute; IronPDF: CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Keep content together&lt;/td&gt;
&lt;td&gt;&lt;code&gt;keep-together="always"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CSS &lt;code&gt;page-break-inside: avoid;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;Different property names&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tables&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;fo:table&amp;gt;&lt;/code&gt; structure&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; HTML element&lt;/td&gt;
&lt;td&gt;XSL-FO: verbose XML; IronPDF: standard HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Table columns&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;fo:table-column&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;CSS &lt;code&gt;width&lt;/code&gt; on &lt;code&gt;&amp;lt;th&amp;gt;&lt;/code&gt;/&lt;code&gt;&amp;lt;td&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;FO.NET: explicit; IronPDF: auto-sizing&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headers/footers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;fo:static-content&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RenderingOptions.TextHeader/Footer&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;FO.NET: XML; IronPDF: API&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Images&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;fo:external-graphic&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; HTML tag&lt;/td&gt;
&lt;td&gt;XSL-FO: element; IronPDF: standard tag&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Hyperlinks&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;lt;fo:basic-link&amp;gt;&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;a href=""&amp;gt;&lt;/code&gt; HTML&lt;/td&gt;
&lt;td&gt;FO.NET: FO object; IronPDF: HTML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unicode support&lt;/td&gt;
&lt;td&gt;Font-dependent&lt;/td&gt;
&lt;td&gt;Built-in&lt;/td&gt;
&lt;td&gt;FO.NET: manual; IronPDF: automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Comprehensive Feature Comparison
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;FO.NET&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Status&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active Development&lt;/td&gt;
&lt;td&gt;No (discontinued)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Last Update&lt;/td&gt;
&lt;td&gt;2017-2018 (varies by fork)&lt;/td&gt;
&lt;td&gt;Regular updates&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Official Maintainer&lt;/td&gt;
&lt;td&gt;None&lt;/td&gt;
&lt;td&gt;Iron Software&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Support&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Community Forums&lt;/td&gt;
&lt;td&gt;Dead GitHub repos&lt;/td&gt;
&lt;td&gt;Active support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Commercial SLA&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Documentation&lt;/td&gt;
&lt;td&gt;W3C spec + Apache FOP&lt;/td&gt;
&lt;td&gt;Comprehensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Code Samples&lt;/td&gt;
&lt;td&gt;Sparse&lt;/td&gt;
&lt;td&gt;Extensive&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Content Creation&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Layout System&lt;/td&gt;
&lt;td&gt;XSL-FO (XML)&lt;/td&gt;
&lt;td&gt;HTML/CSS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Modern CSS Support&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Full CSS3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript Support&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML Input&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;XML Input&lt;/td&gt;
&lt;td&gt;Yes (via XSLT)&lt;/td&gt;
&lt;td&gt;Via HTML conversion&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PDF Operations&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Generate PDF&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge PDFs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Split PDFs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Extract Text&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Edit Existing PDFs&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Form Filling&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Digital Signatures&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Security&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Encryption&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;AES 128/256-bit&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Password Protection&lt;/td&gt;
&lt;td&gt;Basic&lt;/td&gt;
&lt;td&gt;User/Owner passwords&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Permissions&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Full control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Known Issues&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET Core support&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 5+ support&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Font embedding&lt;/td&gt;
&lt;td&gt;Manual&lt;/td&gt;
&lt;td&gt;Automatic&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Large document performance&lt;/td&gt;
&lt;td&gt;Poor&lt;/td&gt;
&lt;td&gt;Optimized&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Table auto-sizing&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unicode rendering&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Full&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Development&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;td&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET Framework&lt;/td&gt;
&lt;td&gt;4.0-4.6 (fork-dependent)&lt;/td&gt;
&lt;td&gt;4.6.2+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET Core&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;3.1+&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET 5+&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Linux&lt;/td&gt;
&lt;td&gt;Unknown&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker&lt;/td&gt;
&lt;td&gt;Problematic&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Known FO.NET Issues
&lt;/h2&gt;

&lt;p&gt;Based on historical reports and fork documentation gaps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Memory leaks&lt;/strong&gt;: Long-running processes may accumulate memory; no official fix&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Threading issues&lt;/strong&gt;: Not thread-safe; requires external synchronization&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Image format limitations&lt;/strong&gt;: Limited support beyond JPEG/PNG; TIFF/BMP problematic&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complex table crashes&lt;/strong&gt;: Tables with merged cells or nested tables cause errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;SVG rendering&lt;/strong&gt;: Minimal or no SVG support depending on fork&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;These issues vary by fork and may not be documented. Verify behavior through testing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Installation Comparison
&lt;/h2&gt;

&lt;h3&gt;
  
  
  FO.NET
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# No official NuGet package&lt;/span&gt;
&lt;span class="c"&gt;# Manual DLL reference or fork-specific package&lt;/span&gt;
&lt;span class="c"&gt;# Example for unofficial fork package:&lt;/span&gt;
&lt;span class="c"&gt;# dotnet add package Fonet --version X.X.X&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Namespace varies by fork&lt;/span&gt;
&lt;span class="c1"&gt;// Commonly: using Fonet&lt;/span&gt;
&lt;span class="c1"&gt;// or: using FO.NET&lt;/span&gt;
&lt;span class="c1"&gt;// Verify in fork documentation&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  IronPDF
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;dotnet add package IronPdf
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;FO.NET served a specific need in the .NET ecosystem circa 2006-2012: teams with XML data pipelines who required precise, declarative page layout via XSL-FO standards. The library's dormancy reflects broader industry shifts—HTML/CSS emerged as the dominant layout language, XML processing moved to JSON/REST APIs, and .NET Framework-only libraries became incompatible with cloud-native architectures.&lt;/p&gt;

&lt;p&gt;For existing FO.NET codebases, the migration decision hinges on pain points: if you're encountering .NET Core incompatibility, font rendering issues, or need features like digital signatures, the technical debt of maintaining FO.NET outweighs refactoring costs. IronPDF's HTML-based approach means most teams already possess the skills (HTML/CSS) to rebuild layouts, eliminating XSL-FO's learning curve.&lt;/p&gt;

&lt;p&gt;Migration becomes mandatory when: deployment targets shift to .NET 5+; compliance requires modern encryption/signatures; or vendor-lock to unmaintained code becomes a security audit flag. In these cases, IronPDF's Chromium engine and active development provide a supported path forward.&lt;/p&gt;

&lt;p&gt;Have you encountered XSL-FO codebases in legacy projects? What triggered the decision to migrate or maintain?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Learn IronPDF's HTML-to-PDF workflow&lt;/strong&gt;: &lt;a href="https://ironsoftware.com/suite/blog/using-ironsuite/html-to-pdf-ironpdf-tutorial/" rel="noopener noreferrer"&gt;Complete HTML to PDF tutorial&lt;/a&gt;&lt;br&gt;
&lt;strong&gt;Explore IronPDF's full API capabilities&lt;/strong&gt;: &lt;a href="https://ironsoftware.com/suite/blog/using-ironsuite/csharp-create-pdf-ironpdf-tutorial/" rel="noopener noreferrer"&gt;C# PDF generation guide&lt;/a&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Grabzit External HTML to PDF APIs: Privacy, GDPR, and Hidden Costs</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Mon, 06 Apr 2026 08:53:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/grabzit-external-html-to-pdf-apis-privacy-gdpr-and-hidden-costs-4ci7</link>
      <guid>https://dev.to/ironsoftware/grabzit-external-html-to-pdf-apis-privacy-gdpr-and-hidden-costs-4ci7</guid>
      <description>&lt;p&gt;When developers integrate external services like GrabzIt or PDFmyURL for HTML-to-PDF conversion, they inherit risks that extend beyond technical implementation. Sending HTML content to third-party servers introduces data privacy concerns, GDPR compliance complexity, and operational dependencies that can create long-term problems. Understanding these risks before committing to an external API prevents costly migrations later.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Cloud-based HTML-to-PDF services operate by receiving your HTML content, processing it on their infrastructure, and returning the generated PDF. This architecture creates several categories of risk that compound over time.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Transmission&lt;/strong&gt;: Every conversion request sends your HTML content across the internet to a third-party server. For applications generating invoices, contracts, medical documents, or internal reports, this means sensitive data leaves your controlled environment on every request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Processing Jurisdiction&lt;/strong&gt;: GrabzIt, registered in England and Wales, explicitly states in their privacy policy that "depending on the physical location of you or the nominated receiving party, this automated action could mean that personal data is transmitted across international borders and beyond the United Kingdom and/or the European Union." This cross-border data flow complicates compliance with data residency requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Data Retention&lt;/strong&gt;: PDFmyURL states they retain server logs containing IP addresses and converted documents, which are "cleared out monthly." GrabzIt retains personal data until users have "stopped using GrabzIt's services for six months." Neither retention period may align with your organization's data minimization requirements.&lt;/p&gt;

&lt;h3&gt;
  
  
  Performance and Availability Impacts
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Typical conversion request flow with external API:

Your Server → Internet → API Server → Processing → Internet → Your Server
                ↓                           ↓
           Network latency           API processing time
           (50-500ms each way)       (variable, up to 60 seconds)

Total added latency per conversion: 200-2000ms minimum
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;External API dependencies add network round-trip time to every conversion. When PDFmyURL documentation notes they "stop each conversion process after 60 seconds if your page is too large or loads too slow," that timeout happens on their infrastructure, outside your control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;Organizations in these categories face heightened risk when using external HTML-to-PDF APIs:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Healthcare and Financial Services&lt;/strong&gt;: Applications handling protected health information (PHI) or financial data face regulatory requirements that may prohibit sending content to external processors. HIPAA requires Business Associate Agreements (BAAs) with any third party handling PHI. Not all cloud PDF services offer BAAs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Legal and Government Entities&lt;/strong&gt;: Document confidentiality requirements often mandate that data never leave approved infrastructure. Court documents, contracts, and government records may be subject to specific handling requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Enterprise Applications Processing PII&lt;/strong&gt;: GDPR's data processor requirements apply when sending European user data to any third party. The service becomes a data processor, requiring documented agreements, security assessments, and potentially Data Protection Impact Assessments (DPIAs).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;High-Volume Production Systems&lt;/strong&gt;: Applications generating thousands of PDFs per hour depend entirely on the external service's availability. Rate limiting, service outages, or API changes directly impact business operations.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organizations with Data Residency Requirements&lt;/strong&gt;: Some industries and regions mandate that data processing occur within specific geographic boundaries. Cross-border data transfers require additional legal mechanisms under GDPR.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence of Industry Concerns
&lt;/h2&gt;

&lt;p&gt;The challenges of external PDF API dependencies are documented across the developer community and security research.&lt;/p&gt;

&lt;h3&gt;
  
  
  Privacy and Data Processing
&lt;/h3&gt;

&lt;p&gt;G2 reviews for PDFmyURL note the inherent privacy risk: "Files uploaded to servers inherently run the risk of being compromised." While reviewers haven't experienced breaches, the architectural risk remains.&lt;/p&gt;

&lt;p&gt;GrabzIt's own documentation acknowledges international data transfer: their API "could mean that personal data is transmitted across international borders and beyond the United Kingdom and/or the European Union."&lt;/p&gt;

&lt;p&gt;Security researchers have extensively documented risks in HTML-to-PDF converters. The Daily Swig reported that "five popular open source libraries used to convert HTML files to PDF documents are vulnerable to server-side request forgery (SSRF), directory traversal, and denial-of-service (DoS) attacks." While this research focused on libraries, cloud services using similar underlying technology inherit comparable risks.&lt;/p&gt;

&lt;h3&gt;
  
  
  Availability and Performance Issues
&lt;/h3&gt;

&lt;p&gt;GrabzIt's support documentation addresses a common problem: "If all of your requests to GrabzIt's API never complete and then timeout, there could be a problem with your network. The most likely issue is a firewall or network configuration issue."&lt;/p&gt;

&lt;p&gt;G2 reviews for PDFmyURL identify the "conversion time limit (60 seconds) for complex or slow-loading pages" as a main drawback, along with the service being "relatively expensive compared to competitors."&lt;/p&gt;

&lt;p&gt;One GrabzIt user on G2 reported that "the tool was bugging out and wasn't able to capture any PDFs due to it crashing. The support team blamed it on poor code and gave no insight or help." Production applications cannot afford such debugging uncertainty when revenue-generating functions depend on PDF generation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Vendor Lock-In Concerns
&lt;/h3&gt;

&lt;p&gt;Research published in ResearchGate on SaaS migration notes that "the vendor lock-in problem is often caused by cloud computing SaaS provider's use of unique and proprietary user interfaces, application programming interfaces (APIs) and databases."&lt;/p&gt;

&lt;p&gt;The practical impact: once your application integrates with a specific API's request format, authentication scheme, and response handling, migrating to an alternative requires code changes throughout your application.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;p&gt;The fundamental issues with external HTML-to-PDF APIs stem from architectural decisions that prioritize ease of initial integration over long-term operational control.&lt;/p&gt;

&lt;h3&gt;
  
  
  Data Must Leave Your Control
&lt;/h3&gt;

&lt;p&gt;There is no way to use GrabzIt, PDFmyURL, or similar services without sending your HTML content to their servers. The service cannot render HTML to PDF without receiving the HTML. This is not a bug to be fixed but the fundamental nature of external API services.&lt;/p&gt;

&lt;p&gt;For organizations with data handling requirements, this architecture creates an irreconcilable conflict: the service cannot function without data access, but data access may violate policy.&lt;/p&gt;

&lt;h3&gt;
  
  
  Network Dependency on Every Operation
&lt;/h3&gt;

&lt;p&gt;External APIs add network latency to every conversion. Even with optimal network conditions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Step&lt;/th&gt;
&lt;th&gt;Latency&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;DNS resolution&lt;/td&gt;
&lt;td&gt;1-50ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TLS handshake&lt;/td&gt;
&lt;td&gt;50-200ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Request transmission&lt;/td&gt;
&lt;td&gt;10-100ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API processing&lt;/td&gt;
&lt;td&gt;500-60000ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Response transmission&lt;/td&gt;
&lt;td&gt;50-500ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Total minimum&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;611ms+&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For batch processing scenarios generating hundreds or thousands of PDFs, this per-conversion overhead compounds significantly.&lt;/p&gt;

&lt;h3&gt;
  
  
  Ongoing Cost Structure
&lt;/h3&gt;

&lt;p&gt;External APIs use subscription models with per-conversion or monthly fees. PDFmyURL pricing starts at $19/month, with additional fees for volume beyond 20,000 conversions (additional 10,000 conversions cost $60/month). GrabzIt offers monthly subscriptions with similar scaling costs.&lt;/p&gt;

&lt;p&gt;Over multi-year application lifespans, subscription costs accumulate:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Annual Cost&lt;/th&gt;
&lt;th&gt;3-Year Total&lt;/th&gt;
&lt;th&gt;5-Year Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;$228/year ($19/mo)&lt;/td&gt;
&lt;td&gt;$684&lt;/td&gt;
&lt;td&gt;$1,140&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$720/year ($60/mo)&lt;/td&gt;
&lt;td&gt;$2,160&lt;/td&gt;
&lt;td&gt;$3,600&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;$2,400/year ($200/mo)&lt;/td&gt;
&lt;td&gt;$7,200&lt;/td&gt;
&lt;td&gt;$12,000&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;These costs recur indefinitely. Failure to maintain subscription results in complete loss of PDF generation capability.&lt;/p&gt;

&lt;h3&gt;
  
  
  GDPR Compliance Complexity
&lt;/h3&gt;

&lt;p&gt;When using an external HTML-to-PDF service, the service becomes a data processor under GDPR. This creates several obligations:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Processing Agreement&lt;/strong&gt;: Article 28 requires a written contract with specific provisions regarding processing instructions, confidentiality, security measures, and audit rights.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;International Transfer Mechanisms&lt;/strong&gt;: For services processing data outside the EU (or transferring to non-adequate jurisdictions), Standard Contractual Clauses (SCCs) or other transfer mechanisms are required.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Records of Processing&lt;/strong&gt;: Organizations must document the use of external processors, the categories of data processed, and the purposes of processing.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Data Subject Rights&lt;/strong&gt;: If a user exercises their right to erasure, the organization must ensure the processor also deletes the data, which may conflict with the processor's retention policies.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds
&lt;/h2&gt;

&lt;p&gt;Organizations have attempted various approaches to mitigate external API risks while continuing to use them.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workaround 1: Minimizing Sensitive Data
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Strip sensitive fields from HTML before sending to the external service, then merge data back into the PDF locally.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Attempting to minimize sensitive data exposure&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GeneratePdfWithReducedExposure&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomerData&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Replace sensitive values with placeholders&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;sanitizedHtml&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htmlTemplate&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{SSN}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"[REDACTED]"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{AccountNumber}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"[REDACTED]"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"{PhoneNumber}"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"[REDACTED]"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Send sanitized HTML to external service&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdfBytes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;ExternalPdfService&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;sanitizedHtml&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Problem: How do you put the real values back?&lt;/span&gt;
    &lt;span class="c1"&gt;// The PDF is a rendered image - you cannot simply&lt;/span&gt;
    &lt;span class="c1"&gt;// search and replace text&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdfBytes&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Missing sensitive data&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PDFs are rendered documents, not text files; merging data post-conversion is technically complex&lt;/li&gt;
&lt;li&gt;Positioning replacement text requires precise coordinate calculation&lt;/li&gt;
&lt;li&gt;Any data that affects layout must be present during conversion&lt;/li&gt;
&lt;li&gt;Partial data in the PDF may still be useful to attackers&lt;/li&gt;
&lt;li&gt;Approach adds significant complexity without eliminating the core risk&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Self-Hosted API Proxy
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Run a local proxy that intercepts requests, potentially encrypting or transforming data before forwarding.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The external service still receives the HTML (encrypted or not)&lt;/li&gt;
&lt;li&gt;Adding a proxy introduces another failure point&lt;/li&gt;
&lt;li&gt;Does not address compliance requirements for data residency&lt;/li&gt;
&lt;li&gt;Increases operational complexity without solving the fundamental architecture&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: Contractual Protections
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Rely on the service's terms of service and privacy policy to protect data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Terms of service are typically drafted to protect the provider, not the customer&lt;/li&gt;
&lt;li&gt;Privacy policies can be changed with notice&lt;/li&gt;
&lt;li&gt;Breach notification timelines may not meet regulatory requirements&lt;/li&gt;
&lt;li&gt;Limited recourse if data is mishandled&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 4: Separate Environment for Sensitive Documents
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Use external APIs only for non-sensitive documents; use a different solution for confidential content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires maintaining two different PDF generation systems&lt;/li&gt;
&lt;li&gt;Developers must correctly classify document sensitivity&lt;/li&gt;
&lt;li&gt;Edge cases and misclassification create risk&lt;/li&gt;
&lt;li&gt;Doubles maintenance and testing burden&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Different Approach: On-Premises Processing with IronPDF
&lt;/h2&gt;

&lt;p&gt;For organizations where data privacy, compliance, or operational independence matter, processing HTML-to-PDF conversion locally eliminates the architectural constraints of external APIs.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why On-Premises Processing Addresses These Concerns
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Data Never Leaves Your Infrastructure&lt;/strong&gt;: IronPDF processes HTML to PDF entirely within your application. The HTML content, rendered PDF, and all intermediate states remain within your controlled environment. There is no network transmission to external parties.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Third-Party Data Processor&lt;/strong&gt;: When conversion happens within your application, no external data processor exists. This eliminates GDPR data processing agreements, international transfer mechanisms, and third-party audit requirements for the PDF generation component.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;No Network Dependency&lt;/strong&gt;: Conversion speed depends on your server's resources, not internet latency. Typical conversion times for moderate HTML documents are 100-500ms, with no network round-trip overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Predictable Cost Structure&lt;/strong&gt;: IronPDF uses perpetual licensing, not subscriptions. After the initial purchase, the software continues functioning indefinitely without recurring fees. Organizations concerned about long-term costs can calculate total cost of ownership with certainty.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;OnPremisesPdfGenerator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GenerateConfidentialDocument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomerData&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// HTML never leaves your server&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;BuildInvoiceHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure rendering - all processing happens locally&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginLeft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginRight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Set paper size&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Generate PDF - no network calls, no external data transmission&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;GenerateBatchReports&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;ReportData&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;reports&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;reports&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Each conversion is independent, no API rate limits&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;BuildReportHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"/secure-storage/reports/&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// No per-conversion charges, no external service calls&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;BuildInvoiceHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;CustomerData&lt;/span&gt; &lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Sensitive data stays in your application&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;$@"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;head&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;style&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                body &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sans&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;40&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                .header &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt; &lt;span class="n"&gt;solid&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="m"&gt;333&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;bottom&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                .customer-info &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                .confidential &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;c00&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;weight&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;bold&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;/style&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;/head&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;body&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;div class='header'&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                &amp;lt;h1&amp;gt;Invoice #&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvoiceNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                &amp;lt;p class='confidential'&amp;gt;CONFIDENTIAL&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;div class='customer-info'&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Customer:&amp;lt;/strong&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Name&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Account:&amp;lt;/strong&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;AccountNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                &amp;lt;p&amp;gt;&amp;lt;strong&amp;gt;Tax ID:&amp;lt;/strong&amp;gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;customer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;TaxId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/p&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;!-- This sensitive HTML never leaves your server --&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;/body&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;BuildReportHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ReportData&lt;/span&gt; &lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;$"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;report&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;CustomerData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;InvoiceNumber&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Name&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;AccountNumber&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;TaxId&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReportData&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Id&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="k"&gt;get&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="k"&gt;set&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points about this implementation:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;All HTML content, including sensitive fields, remains within your application&lt;/li&gt;
&lt;li&gt;No network requests occur during PDF generation&lt;/li&gt;
&lt;li&gt;Batch processing has no rate limits or per-conversion fees&lt;/li&gt;
&lt;li&gt;Conversion timing is deterministic, based on document complexity and server resources&lt;/li&gt;
&lt;li&gt;The same code runs in development, staging, and production without API key management&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Processing Without Internet Access
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;AirGappedEnvironmentGenerator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;GenerateInSecureEnvironment&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// IronPDF works in air-gapped environments&lt;/span&gt;
        &lt;span class="c1"&gt;// No license validation calls required during conversion&lt;/span&gt;
        &lt;span class="c1"&gt;// No telemetry transmitted&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure for offline operation&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Process classified documents without network access&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetClassifiedDocumentHtml&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/secure/classified-output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GetClassifiedDocumentHtml&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;
        &lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Classified Document&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For implementation details on on-premises PDF generation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer&lt;/a&gt; - HTML-to-PDF conversion without external dependencies&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderOptions.html" rel="noopener noreferrer"&gt;RenderingOptions&lt;/a&gt; - Configuration options for PDF output&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/how-to/pdf-encryption-and-decryption/" rel="noopener noreferrer"&gt;Security and Encryption&lt;/a&gt; - Applying PDF security features locally&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;p&gt;IronPDF is commercial software using perpetual licensing. The initial cost is higher than a single month of API subscription, but there are no recurring fees for continued use. Organizations should compare:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Subscription API&lt;/strong&gt;: Lower initial cost, ongoing monthly fees, perpetual dependency&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Perpetual License&lt;/strong&gt;: Higher initial cost, no recurring fees, indefinite use&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For applications with multi-year lifespans, the break-even calculation typically favors perpetual licensing within 12-24 months.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Migration Effort
&lt;/h3&gt;

&lt;p&gt;Switching from an external API to IronPDF requires code changes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Change Area&lt;/th&gt;
&lt;th&gt;Effort&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Remove API client libraries&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Add IronPDF NuGet package&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Replace HTTP calls with IronPDF API&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Update error handling&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Adjust for synchronous processing&lt;/td&gt;
&lt;td&gt;Varies&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Testing and validation&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The actual migration typically takes 1-3 days for straightforward implementations, longer for applications with complex API integrations or custom error handling.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Complete control over when and how conversions occur&lt;/li&gt;
&lt;li&gt;No dependency on external service availability&lt;/li&gt;
&lt;li&gt;Elimination of per-conversion network latency&lt;/li&gt;
&lt;li&gt;Simplified compliance posture (no external data processor)&lt;/li&gt;
&lt;li&gt;Predictable performance characteristics&lt;/li&gt;
&lt;li&gt;Offline and air-gapped capability&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Initial licensing cost versus subscription costs&lt;/li&gt;
&lt;li&gt;Server resource requirements for local processing&lt;/li&gt;
&lt;li&gt;Team familiarity with .NET ecosystem (IronPDF is a .NET library)&lt;/li&gt;
&lt;li&gt;Deployment complexity in containerized environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;IronPDF provides Docker images and documentation for Linux deployment, but organizations unfamiliar with .NET deployment may need additional setup time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;External HTML-to-PDF APIs like GrabzIt and PDFmyURL introduce data privacy risks, GDPR compliance obligations, and operational dependencies that compound over time. Organizations processing sensitive documents should evaluate whether architectural convenience justifies sending confidential HTML to third-party servers. On-premises processing eliminates these concerns while providing predictable performance and cost structures.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/jacob-mellor" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt; has led Iron Software's technical development for over two decades, building tools that process documents without external dependencies.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://grabz.it/legal/privacy-policy/" rel="noopener noreferrer"&gt;GrabzIt Privacy Policy&lt;/a&gt;{:rel="nofollow"} - Official privacy documentation detailing data processing and international transfers&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pdfmyurl.com/privacy" rel="noopener noreferrer"&gt;PDFmyURL Privacy Policy&lt;/a&gt;{:rel="nofollow"} - Service privacy terms and data retention policies&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pdfmyurl.com/plans" rel="noopener noreferrer"&gt;PDFmyURL Pricing&lt;/a&gt;{:rel="nofollow"} - Subscription cost structure&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://grabz.it/upgrade/" rel="noopener noreferrer"&gt;GrabzIt Pricing&lt;/a&gt;{:rel="nofollow"} - Premium package options and costs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://grabz.it/support/article/grabzit-api-timeout/" rel="noopener noreferrer"&gt;GrabzIt API Timeout Support&lt;/a&gt;{:rel="nofollow"} - Documentation on network and timeout issues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://pdfmyurl.com/usage-restrictions" rel="noopener noreferrer"&gt;PDFmyURL Usage Restrictions&lt;/a&gt;{:rel="nofollow"} - Conversion timeout limitations&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.g2.com/products/grabzit/reviews" rel="noopener noreferrer"&gt;GrabzIt Reviews - G2&lt;/a&gt;{:rel="nofollow"} - User reviews including performance and support experiences&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.g2.com/products/pdfmyurl/reviews" rel="noopener noreferrer"&gt;PDFmyURL Reviews - G2&lt;/a&gt;{:rel="nofollow"} - User reviews on limitations and costs&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://portswigger.net/daily-swig/html-to-pdf-converters-open-to-denial-of-service-ssrf-directory-traversal-attacks" rel="noopener noreferrer"&gt;HTML-to-PDF Converters Security Vulnerabilities - The Daily Swig&lt;/a&gt;{:rel="nofollow"} - Security research on PDF converter vulnerabilities&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.researchgate.net/publication/318880729_A_Holistic_Decision_Framework_to_Avoid_Vendor_Lock-in_for_Cloud_SaaS_Migration" rel="noopener noreferrer"&gt;SaaS Vendor Lock-In Analysis - ResearchGate&lt;/a&gt;{:rel="nofollow"} - Academic research on migration challenges&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://docraptor.com/security-and-privacy" rel="noopener noreferrer"&gt;DocRaptor Security Documentation&lt;/a&gt;{:rel="nofollow"} - Example of enterprise-grade API security measures for comparison&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://gdpr-info.eu/" rel="noopener noreferrer"&gt;GDPR Legal Text&lt;/a&gt;{:rel="nofollow"} - Official GDPR regulation reference&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For IronPDF documentation on private, on-premises PDF generation, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Understanding GdPicture.NET Pricing: Is the Document Imaging SDK Worth the Cost?</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Mon, 06 Apr 2026 07:51:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/understanding-gdpicturenet-pricing-is-the-document-imaging-sdk-worth-the-cost-3gc7</link>
      <guid>https://dev.to/ironsoftware/understanding-gdpicturenet-pricing-is-the-document-imaging-sdk-worth-the-cost-3gc7</guid>
      <description>&lt;p&gt;When developers need HTML-to-PDF conversion in their .NET applications, they often encounter GdPicture.NET during their search for solutions. GdPicture positions itself as an enterprise-grade document imaging SDK with over 3,000 functionalities. However, this comprehensive approach comes with a significant price tag that may not align with the needs of developers who simply require PDF generation capabilities.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;GdPicture.NET is designed as an all-in-one document imaging toolkit. The SDK bundles PDF processing with OCR, barcode recognition, TWAIN scanning, DICOM medical imaging, and dozens of other features. For organizations needing PDF generation from HTML or basic document manipulation, this bundled approach presents several challenges:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Forced feature bundling&lt;/strong&gt;: PDF capabilities are packaged with imaging features you may never use&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Enterprise-focused pricing&lt;/strong&gt;: License costs designed for large document processing operations&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Annual maintenance requirements&lt;/strong&gt;: 20% of license cost annually for updates and support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Per-developer licensing&lt;/strong&gt;: Each developer who compiles code using the SDK needs a separate license&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing Structure Overview
&lt;/h3&gt;

&lt;p&gt;GdPicture.NET uses a modular licensing model with five core editions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Edition&lt;/th&gt;
&lt;th&gt;Target Use Case&lt;/th&gt;
&lt;th&gt;Approximate Cost Range&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Ultimate SDK&lt;/td&gt;
&lt;td&gt;Full document imaging suite&lt;/td&gt;
&lt;td&gt;$3,000+ per developer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Document Imaging SDK&lt;/td&gt;
&lt;td&gt;PDF, imaging, annotations&lt;/td&gt;
&lt;td&gt;$1,200+ per developer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Image SDK&lt;/td&gt;
&lt;td&gt;Image processing only&lt;/td&gt;
&lt;td&gt;$500+ per developer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;TWAIN SDK&lt;/td&gt;
&lt;td&gt;Scanner integration&lt;/td&gt;
&lt;td&gt;$350+ per developer&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Document Viewer SDK&lt;/td&gt;
&lt;td&gt;PDF viewing&lt;/td&gt;
&lt;td&gt;$950+ per developer&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Additionally, individual plugins can be purchased separately:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PDF Plugin: ~$700&lt;/li&gt;
&lt;li&gt;OCR Plugin: ~$700&lt;/li&gt;
&lt;li&gt;Annotation Plugin: ~$700&lt;/li&gt;
&lt;li&gt;Barcode plugins: ~$500 each&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These figures are based on historical pricing and the company's stated "contact sales for pricing" model. Actual costs may vary based on negotiation and volume.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;The GdPicture pricing structure most significantly impacts:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Small to mid-sized development teams&lt;/strong&gt;: A team of three developers working on a web application that generates PDF invoices would need three separate licenses. At $1,200+ per developer for the Document Imaging SDK, the initial investment exceeds $3,600 before annual maintenance.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Startups and indie developers&lt;/strong&gt;: The entry cost for basic PDF functionality requires significant upfront capital that may not fit early-stage budgets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Projects with focused requirements&lt;/strong&gt;: Applications that only need HTML-to-PDF conversion or basic PDF manipulation end up paying for OCR, barcode, and imaging capabilities they will never use.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Organizations with strict procurement policies&lt;/strong&gt;: The "contact sales for pricing" approach requires procurement negotiations rather than transparent self-service licensing.&lt;/p&gt;

&lt;h2&gt;
  
  
  The SDK Bundle vs. PDF-Only Needs
&lt;/h2&gt;

&lt;p&gt;GdPicture markets itself as a "Five-in-One Toolkit" that delivers "an all-in-one SDK without extra costs or complex licensing." However, this bundled approach means developers cannot purchase only the PDF features they need at a reduced price.&lt;/p&gt;

&lt;h3&gt;
  
  
  What GdPicture.NET Includes
&lt;/h3&gt;

&lt;p&gt;The Ultimate SDK bundles together:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;PDF creation, editing, and rendering&lt;/li&gt;
&lt;li&gt;OCR (Optical Character Recognition)&lt;/li&gt;
&lt;li&gt;1D and 2D barcode reading/writing&lt;/li&gt;
&lt;li&gt;Image processing (500+ functions)&lt;/li&gt;
&lt;li&gt;TWAIN scanner integration&lt;/li&gt;
&lt;li&gt;DICOM medical image support&lt;/li&gt;
&lt;li&gt;JBIG2 compression&lt;/li&gt;
&lt;li&gt;Document annotation&lt;/li&gt;
&lt;li&gt;Form field processing&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What Many Developers Actually Need
&lt;/h3&gt;

&lt;p&gt;For typical web application PDF generation:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML-to-PDF conversion&lt;/li&gt;
&lt;li&gt;PDF merging and splitting&lt;/li&gt;
&lt;li&gt;Adding headers, footers, and page numbers&lt;/li&gt;
&lt;li&gt;Digital signatures&lt;/li&gt;
&lt;li&gt;Basic PDF editing&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The mismatch between GdPicture's comprehensive offering and these focused requirements results in paying for functionality that remains unused.&lt;/p&gt;

&lt;h2&gt;
  
  
  Cost Analysis for Typical PDF Use Cases
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scenario 1: E-commerce Invoice Generation
&lt;/h3&gt;

&lt;p&gt;A small e-commerce platform needs to generate PDF invoices from HTML templates.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With GdPicture.NET:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Minimum viable option: Document Imaging SDK&lt;/li&gt;
&lt;li&gt;Cost per developer: ~$1,200&lt;/li&gt;
&lt;li&gt;Team of 2 developers: ~$2,400&lt;/li&gt;
&lt;li&gt;Annual maintenance (20%): ~$480/year&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;First-year cost: ~$2,880&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Features used:&lt;/strong&gt; PDF generation from HTML&lt;br&gt;
&lt;strong&gt;Features paid for but unused:&lt;/strong&gt; OCR, barcode recognition, image processing, TWAIN scanning, annotations&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 2: Report Generation System
&lt;/h3&gt;

&lt;p&gt;A business application generates weekly reports as PDFs.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With GdPicture.NET:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Required: Document Imaging SDK + PDF Plugin&lt;/li&gt;
&lt;li&gt;Team of 3 developers: ~$3,600+&lt;/li&gt;
&lt;li&gt;Annual maintenance: ~$720/year&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;First-year cost: ~$4,320&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Features used:&lt;/strong&gt; PDF creation, basic styling&lt;br&gt;
&lt;strong&gt;Features unused:&lt;/strong&gt; OCR, barcode, medical imaging, scanner integration&lt;/p&gt;

&lt;h3&gt;
  
  
  Scenario 3: Document Management Platform
&lt;/h3&gt;

&lt;p&gt;A larger system needs PDF viewing, annotation, and conversion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;With GdPicture.NET:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Required: Ultimate SDK for full functionality&lt;/li&gt;
&lt;li&gt;Team of 5 developers: ~$15,000+&lt;/li&gt;
&lt;li&gt;Annual maintenance: ~$3,000/year&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;First-year cost: ~$18,000&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This scenario better utilizes GdPicture's capabilities, but many organizations do not require the full imaging suite.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Annual Maintenance Consideration
&lt;/h2&gt;

&lt;p&gt;GdPicture.NET requires an Annual Maintenance Contract (AMC) for continued access to updates and support:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initial cost: 20% of the Suggested Retail Price (SRP)&lt;/li&gt;
&lt;li&gt;Renewal cost: 20% annually&lt;/li&gt;
&lt;li&gt;Without AMC: No access to new versions or technical support&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For a team using the Ultimate SDK ($15,000 initial investment), annual maintenance adds $3,000 per year indefinitely. Over a five-year period, maintenance costs alone total $15,000, effectively doubling the total cost of ownership.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Focused Alternative: IronPDF
&lt;/h2&gt;

&lt;p&gt;For developers whose primary need is PDF generation rather than comprehensive document imaging, IronPDF offers a more targeted solution.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why Consider IronPDF for PDF-Focused Projects
&lt;/h3&gt;

&lt;p&gt;IronPDF is built specifically for PDF operations in .NET applications. Rather than bundling PDF capabilities into a larger imaging SDK, IronPDF focuses on common PDF tasks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;HTML-to-PDF rendering using an embedded Chromium engine&lt;/li&gt;
&lt;li&gt;PDF creation, editing, and manipulation&lt;/li&gt;
&lt;li&gt;Digital signatures and security&lt;/li&gt;
&lt;li&gt;Form filling and extraction&lt;/li&gt;
&lt;li&gt;PDF merging, splitting, and conversion&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Pricing Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;GdPicture.NET&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Entry-level license&lt;/td&gt;
&lt;td&gt;~$950+ (Viewer only)&lt;/td&gt;
&lt;td&gt;$749 (Lite)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF creation capability&lt;/td&gt;
&lt;td&gt;~$1,200+ (Doc Imaging SDK)&lt;/td&gt;
&lt;td&gt;$749 (Lite)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Small team (3 devs)&lt;/td&gt;
&lt;td&gt;~$3,600+&lt;/td&gt;
&lt;td&gt;$1,499 (Plus)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Unlimited developers&lt;/td&gt;
&lt;td&gt;Contact sales&lt;/td&gt;
&lt;td&gt;$2,999 (Professional)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Annual maintenance&lt;/td&gt;
&lt;td&gt;20% required&lt;/td&gt;
&lt;td&gt;Optional (included first year)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SaaS deployment&lt;/td&gt;
&lt;td&gt;Additional licensing&lt;/td&gt;
&lt;td&gt;Available in license tiers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;IronPDF's pricing structure is transparent and publicly available, allowing developers to calculate costs without contacting a sales team.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Example: HTML to PDF
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceGenerator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;GenerateInvoice&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Configure the renderer with Chrome-based rendering&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Set rendering options for invoice formatting&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginLeft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginRight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Enable CSS media type for print-optimized styling&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CssMediaType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfCssMediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Render HTML to PDF&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Save the generated invoice&lt;/span&gt;
        &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This code generates a PDF from HTML content using IronPDF's Chromium-based renderer. The approach handles CSS, JavaScript, and modern web features without requiring additional plugins or configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For more details on the methods used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderOptions.html" rel="noopener noreferrer"&gt;RenderingOptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/tutorials/html-to-pdf/" rel="noopener noreferrer"&gt;HTML to PDF Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Feature Comparison for PDF Tasks
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;PDF Capability&lt;/th&gt;
&lt;th&gt;GdPicture.NET&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;HTML to PDF&lt;/td&gt;
&lt;td&gt;Yes (via plugin)&lt;/td&gt;
&lt;td&gt;Yes (built-in Chrome engine)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSS3 support&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Full Chromium support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript execution&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Full Chromium support&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF/A compliance&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Digital signatures&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;PDF editing&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Form filling&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Merge/Split&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Watermarks&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Headers/Footers&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Docker/Linux&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;.NET Core/.NET 5+&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For HTML-to-PDF specifically, IronPDF's embedded Chromium engine provides accurate rendering of modern web pages, including complex CSS layouts and JavaScript-generated content.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  When GdPicture.NET Makes Sense
&lt;/h3&gt;

&lt;p&gt;GdPicture.NET remains a valid choice when:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your application requires OCR, barcode processing, and PDF in the same workflow&lt;/li&gt;
&lt;li&gt;You need TWAIN scanner integration for document capture&lt;/li&gt;
&lt;li&gt;Medical imaging (DICOM) is part of your requirements&lt;/li&gt;
&lt;li&gt;You have existing GdPicture integration and migration cost exceeds licensing cost&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  When IronPDF Is More Appropriate
&lt;/h3&gt;

&lt;p&gt;IronPDF better fits projects that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Focus primarily on PDF generation from HTML/CSS&lt;/li&gt;
&lt;li&gt;Need accurate rendering of modern web content&lt;/li&gt;
&lt;li&gt;Have small to medium development teams&lt;/li&gt;
&lt;li&gt;Prefer transparent, self-service licensing&lt;/li&gt;
&lt;li&gt;Want to avoid paying for unused features&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Licensing Model Differences
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;GdPicture.NET:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Per-developer licensing (each developer compiling code needs a license)&lt;/li&gt;
&lt;li&gt;Mandatory annual maintenance for updates&lt;/li&gt;
&lt;li&gt;Contact sales for pricing&lt;/li&gt;
&lt;li&gt;Enterprise-focused negotiation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;IronPDF:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tiered licensing (Lite: 1 dev, Plus: 3 devs, Professional: unlimited)&lt;/li&gt;
&lt;li&gt;First year support included&lt;/li&gt;
&lt;li&gt;Optional renewal for continued updates&lt;/li&gt;
&lt;li&gt;Transparent public pricing&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Total Cost of Ownership: 3-Year Comparison
&lt;/h2&gt;

&lt;p&gt;For a team of 3 developers building a PDF invoice system:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GdPicture.NET Document Imaging SDK:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initial license: ~$3,600&lt;/li&gt;
&lt;li&gt;Year 1 maintenance: ~$720&lt;/li&gt;
&lt;li&gt;Year 2 maintenance: ~$720&lt;/li&gt;
&lt;li&gt;Year 3 maintenance: ~$720&lt;/li&gt;
&lt;li&gt;&lt;strong&gt;3-year total: ~$5,760&lt;/strong&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;IronPDF Plus License:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Initial license: $1,499&lt;/li&gt;
&lt;li&gt;Year 1 support: Included&lt;/li&gt;
&lt;li&gt;Year 2 support (optional): ~$450&lt;/li&gt;
&lt;li&gt;Year 3 support (optional): ~$450&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;3-year total: ~$2,399&lt;/strong&gt; (or $1,499 if support not renewed)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The difference represents significant budget that could be allocated to other development resources.&lt;/p&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;GdPicture.NET is a comprehensive document imaging SDK that serves organizations needing its full range of capabilities. However, for developers whose requirements center on PDF generation, particularly HTML-to-PDF conversion, the bundled pricing structure results in paying for features that remain unused.&lt;/p&gt;

&lt;p&gt;IronPDF provides a focused alternative with transparent pricing, modern HTML rendering via Chromium, and licensing designed for teams of varying sizes. Before committing to either solution, evaluate your actual PDF requirements against the features included in each offering.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/jacob-mellor" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt; is CTO at Iron Software and originally built IronPDF.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.gdpicture.com/pricing/" rel="noopener noreferrer"&gt;GdPicture.NET SDK Pricing&lt;/a&gt;{:rel="nofollow"} - Official pricing page&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gdpicture.com/order/price-lists/" rel="noopener noreferrer"&gt;GdPicture Product Price Lists&lt;/a&gt;{:rel="nofollow"} - Complete product pricing in USD&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gdpicture.com/order/GdPicture-Annual-Maintenance-Contract.pdf" rel="noopener noreferrer"&gt;GdPicture Annual Maintenance Contract&lt;/a&gt;{:rel="nofollow"} - AMC terms and pricing structure&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gdpicture.com/order/sales-faq/" rel="noopener noreferrer"&gt;GdPicture Sales FAQ&lt;/a&gt;{:rel="nofollow"} - Licensing model details&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gdpicture.com/products/dotnet-sdk-comparison-matrix/" rel="noopener noreferrer"&gt;GdPicture.NET Editions Comparison&lt;/a&gt;{:rel="nofollow"} - Feature comparison across editions&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.gdpicture.com/guides/gdpicture/Licensing%20model.html" rel="noopener noreferrer"&gt;GdPicture Licensing Model&lt;/a&gt;{:rel="nofollow"} - Per-developer licensing explanation&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For the latest IronPDF documentation and tutorials, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Rotativa Not Working in .NET Core: Modern Alternative (Issue Fixed)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Fri, 03 Apr 2026 16:07:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/rotativa-not-working-in-net-core-modern-alternative-issue-fixed-2bc4</link>
      <guid>https://dev.to/ironsoftware/rotativa-not-working-in-net-core-modern-alternative-issue-fixed-2bc4</guid>
      <description>&lt;p&gt;Rotativa has been a popular choice for converting ASP.NET MVC views to PDF documents. Developers appreciate its simple API patterns like &lt;code&gt;ViewAsPdf&lt;/code&gt; and &lt;code&gt;ActionAsPdf&lt;/code&gt; that integrate naturally with MVC controller actions. However, migrating to .NET Core reveals significant compatibility issues that stem from Rotativa's architecture: it wraps wkhtmltopdf, a command-line tool that has been archived and is no longer maintained.&lt;/p&gt;

&lt;p&gt;This article documents the common errors developers encounter when using Rotativa.AspNetCore, explains why these issues persist, and demonstrates how to achieve the same MVC-to-PDF functionality with IronPDF.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Rotativa.AspNetCore exists as a port of the original Rotativa library for .NET Core, but it inherits fundamental limitations from its dependency on wkhtmltopdf. Developers encounter a range of errors depending on their deployment environment.&lt;/p&gt;

&lt;h3&gt;
  
  
  How Rotativa Works
&lt;/h3&gt;

&lt;p&gt;Rotativa acts as a wrapper around wkhtmltopdf, spawning the external executable to render HTML content as PDF. This architecture requires:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;The wkhtmltopdf binary to be present in a specific location&lt;/li&gt;
&lt;li&gt;The application process to have permission to execute external binaries&lt;/li&gt;
&lt;li&gt;Platform-specific binaries (Windows .exe vs Linux/Mac executables)&lt;/li&gt;
&lt;li&gt;All native dependencies that wkhtmltopdf requires&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;When any of these requirements fail, Rotativa produces errors that can be difficult to diagnose.&lt;/p&gt;

&lt;h3&gt;
  
  
  The wkhtmltopdf Dependency Problem
&lt;/h3&gt;

&lt;p&gt;The wkhtmltopdf project was archived on January 2, 2023. The repository is now read-only with no further development planned. This matters because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No bug fixes or security patches will be released&lt;/li&gt;
&lt;li&gt;The rendering engine uses Qt WebKit, which hasn't been updated since 2012&lt;/li&gt;
&lt;li&gt;Modern HTML5, CSS3, and JavaScript features are not supported&lt;/li&gt;
&lt;li&gt;Known security vulnerabilities remain unpatched&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Error Messages and Symptoms
&lt;/h2&gt;

&lt;p&gt;Developers migrating to .NET Core commonly encounter these errors:&lt;/p&gt;

&lt;h3&gt;
  
  
  Binary Not Found
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.ComponentModel.Win32Exception: The system cannot find the file specified
   at System.Diagnostics.Process.StartWithShellExecuteEx(ProcessStartInfo startInfo)
   at Rotativa.AspNetCore.WkhtmlDriver.Convert(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This occurs because the NuGet package does not automatically deploy the wkhtmltopdf executable. Developers must manually copy the binary to the correct location.&lt;/p&gt;

&lt;h3&gt;
  
  
  Permission Denied on Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.ComponentModel.Win32Exception (13): Permission denied
   at Interop.Sys.ForkAndExecProcess(...)
   at System.Diagnostics.Process.StartCore(ProcessStartInfo startInfo)
   at Rotativa.AspNetCore.WkhtmlDriver.Convert(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Linux deployments fail when the wkhtmltopdf binary lacks execute permissions or when the application process cannot spawn external executables.&lt;/p&gt;

&lt;h3&gt;
  
  
  Broken Pipe on Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.IO.IOException: Broken pipe
   at System.IO.Pipes.PipeStream.WriteCore(ReadOnlySpan`1 buffer)
   at Rotativa.AspNetCore.WkhtmlDriver.Convert(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This error indicates communication failure between the .NET application and the wkhtmltopdf process, often due to missing native dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  ArgumentNullException with ActionAsPdf
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.ArgumentNullException: Value cannot be null. (Parameter 'key')
   at Rotativa.AspNetCore.ActionAsPdf.CallTheDriver(...)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;code&gt;ActionAsPdf&lt;/code&gt; pattern can fail in .NET Core with null reference errors even when the same code works with &lt;code&gt;ViewAsPdf&lt;/code&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Authentication Loss with ActionAsPdf
&lt;/h3&gt;

&lt;p&gt;When using &lt;code&gt;ActionAsPdf&lt;/code&gt; with authenticated controllers, Rotativa often renders the login page instead of the intended view. The wkhtmltopdf process makes a separate HTTP request that does not carry the user's authentication cookies.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Deployment Environments
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Linux servers and containers&lt;/strong&gt;: Most cloud deployments use Linux, where Rotativa requires manual binary installation and permission configuration&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker containers&lt;/strong&gt;: The .NET Core containers from Microsoft do not include wkhtmltopdf or its dependencies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure App Service on Linux&lt;/strong&gt;: No built-in wkhtmltopdf support&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Windows servers without Visual C++ Redistributable&lt;/strong&gt;: Requires msvcp120.dll to be manually deployed&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Use Cases
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;ASP.NET Core applications migrated from .NET Framework&lt;/li&gt;
&lt;li&gt;Projects using &lt;code&gt;ViewAsPdf&lt;/code&gt; or &lt;code&gt;ActionAsPdf&lt;/code&gt; patterns for invoice generation, report exports, or document creation&lt;/li&gt;
&lt;li&gt;Continuous integration pipelines that build and test on Linux&lt;/li&gt;
&lt;li&gt;Containerized microservices requiring PDF generation&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Evidence from the Developer Community
&lt;/h2&gt;

&lt;p&gt;The Rotativa.AspNetCore GitHub repository documents persistent issues across multiple years.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;Permission denied on Ubuntu reported&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/webgio/Rotativa/issues/197" rel="noopener noreferrer"&gt;GitHub Issue #197&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2019&lt;/td&gt;
&lt;td&gt;Unable to run under Linux&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/webgio/Rotativa.AspNetCore/issues/13" rel="noopener noreferrer"&gt;GitHub Issue #13&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Docker deployment questions&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/webgio/Rotativa.AspNetCore/issues/7" rel="noopener noreferrer"&gt;GitHub Issue #7&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;.NET Core 3.1 setup issues&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/webgio/Rotativa.AspNetCore/issues/79" rel="noopener noreferrer"&gt;GitHub Issue #79&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-01-02&lt;/td&gt;
&lt;td&gt;wkhtmltopdf repository archived&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/wkhtmltopdf/wkhtmltopdf" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Community Reports
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"Rotativa worked perfectly on Windows with .NET Core web API (2.1) and was able to generate PDFs from cshtml files, but when deploying the same project to Ubuntu, it gives permission denied exceptions."&lt;br&gt;
— Developer, GitHub Issues, 2018&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The pattern repeats across multiple issues: functionality that works on Windows development machines fails when deployed to Linux production environments.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;"Using ViewAsPdf now passing model to send some data and it's working but using ActionAsPdf getting an error: ArgumentNullException: Value cannot be null."&lt;br&gt;
— Developer, Microsoft Forums, 2017&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The &lt;code&gt;ActionAsPdf&lt;/code&gt; pattern, which was a key feature of Rotativa's MVC integration, exhibits inconsistent behavior in .NET Core that developers must work around by switching to &lt;code&gt;ViewAsPdf&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Architectural Dependency
&lt;/h3&gt;

&lt;p&gt;Rotativa's architecture creates a process dependency chain:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;ASP.NET Core App → Rotativa.AspNetCore → wkhtmltopdf binary → Qt WebKit → libgdiplus (Linux)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each link in this chain introduces potential failure points. The NuGet package installs only the .NET wrapper; the external binary and its native dependencies must be managed separately.&lt;/p&gt;

&lt;h3&gt;
  
  
  wkhtmltopdf's Obsolete Rendering Engine
&lt;/h3&gt;

&lt;p&gt;wkhtmltopdf uses a patched version of Qt WebKit that stopped receiving updates in 2012. The Qt project deprecated QtWebKit in 2015 and removed it from Qt 5.6 in 2016. The wkhtmltopdf maintainers considered migrating to QtWebEngine (which uses Chromium) but concluded it was not feasible because certain APIs required by wkhtmltopdf do not exist in the newer engine.&lt;/p&gt;

&lt;p&gt;As a result, wkhtmltopdf cannot render:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS Flexbox or Grid layouts&lt;/li&gt;
&lt;li&gt;Modern JavaScript ES6+ features&lt;/li&gt;
&lt;li&gt;Web fonts that require JavaScript loading&lt;/li&gt;
&lt;li&gt;Many HTML5 elements and attributes&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Security Vulnerabilities
&lt;/h3&gt;

&lt;p&gt;CVE-2022-35583 documents a critical (CVSS 9.8) Server-Side Request Forgery vulnerability in wkhtmltopdf 0.12.6. Because the project is archived, this vulnerability will not be patched. The wkhtmltopdf maintainers stated this is an application-level concern, but the practical effect is that any application using wkhtmltopdf must implement its own input sanitization to prevent SSRF attacks.&lt;/p&gt;

&lt;p&gt;The archived status means:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No security patches for future CVEs&lt;/li&gt;
&lt;li&gt;No fixes for rendering bugs&lt;/li&gt;
&lt;li&gt;No updates for newer operating systems&lt;/li&gt;
&lt;li&gt;No support for modern web standards&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Workaround 1: Manual Binary Deployment
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Copy wkhtmltopdf executables to the project folder and set "Copy Always" in file properties.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Project/
├── Rotativa/
│   ├── Windows/
│   │   └── wkhtmltopdf.exe
│   └── Linux/
│       └── wkhtmltopdf
└── Program.cs
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// In Program.cs or Startup.cs&lt;/span&gt;
&lt;span class="n"&gt;RotativaConfiguration&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Setup&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;env&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WebRootPath&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"Rotativa"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Increases deployment package size significantly&lt;/li&gt;
&lt;li&gt;Requires maintaining platform-specific binaries&lt;/li&gt;
&lt;li&gt;Linux binaries need execute permissions set post-deployment&lt;/li&gt;
&lt;li&gt;Does not solve the underlying technology obsolescence&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Docker Layer Installation
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Install wkhtmltopdf in the Docker image during build.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;mcr.microsoft.com/dotnet/aspnet:8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;AS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;base&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    wkhtmltopdf &lt;span class="se"&gt;\
&lt;/span&gt;    libgdiplus &lt;span class="se"&gt;\
&lt;/span&gt;    libc6-dev &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Adds container build time and image size&lt;/li&gt;
&lt;li&gt;Version of wkhtmltopdf from package managers may differ from expected&lt;/li&gt;
&lt;li&gt;Still using archived, vulnerable software&lt;/li&gt;
&lt;li&gt;libgdiplus introduces its own compatibility issues&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: Replace ActionAsPdf with ViewAsPdf
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Avoid the &lt;code&gt;ActionAsPdf&lt;/code&gt; pattern that makes separate HTTP requests.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Instead of:&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;DownloadPdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ActionAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invoice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="n"&gt;id&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;123&lt;/span&gt; &lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Use:&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;DownloadPdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetInvoiceModel&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;123&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ViewAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Invoice"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires refactoring existing code&lt;/li&gt;
&lt;li&gt;Loses the ability to generate PDFs from actions with complex setup logic&lt;/li&gt;
&lt;li&gt;Does not solve permission or binary issues&lt;/li&gt;
&lt;li&gt;Still relies on wkhtmltopdf&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Different Approach: IronPDF
&lt;/h2&gt;

&lt;p&gt;IronPDF provides PDF generation capabilities for ASP.NET Core without external binary dependencies. Instead of wrapping a command-line tool, IronPDF embeds a Chromium rendering engine directly in the .NET process.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why IronPDF Avoids These Issues
&lt;/h3&gt;

&lt;p&gt;The architectural difference eliminates the root causes of Rotativa's problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No external binary&lt;/strong&gt;: The rendering engine is packaged as .NET assemblies&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No spawn/exec permissions needed&lt;/strong&gt;: Everything runs in-process&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Cross-platform by design&lt;/strong&gt;: Same code works on Windows, Linux, and macOS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Modern rendering&lt;/strong&gt;: Uses Chromium, supporting current HTML5, CSS3, and JavaScript&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Actively maintained&lt;/strong&gt;: Regular updates with security patches and new features&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Example: Replacing ViewAsPdf
&lt;/h3&gt;

&lt;p&gt;The following example shows how to achieve the same result as Rotativa's &lt;code&gt;ViewAsPdf&lt;/code&gt; pattern:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;InvoiceController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// Rotativa pattern - requires external wkhtmltopdf binary&lt;/span&gt;
    &lt;span class="c1"&gt;// public IActionResult DownloadPdfRotativa()&lt;/span&gt;
    &lt;span class="c1"&gt;// {&lt;/span&gt;
    &lt;span class="c1"&gt;//     var model = GetInvoiceModel();&lt;/span&gt;
    &lt;span class="c1"&gt;//     return new ViewAsPdf("Invoice", model);&lt;/span&gt;
    &lt;span class="c1"&gt;// }&lt;/span&gt;

    &lt;span class="c1"&gt;// IronPDF pattern - no external dependencies&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;DownloadPdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Create the renderer with Chromium engine&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure page settings similar to Rotativa options&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Get the invoice model&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetInvoiceModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Render HTML content to PDF&lt;/span&gt;
        &lt;span class="c1"&gt;// This HTML would typically come from rendering a Razor view&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GenerateInvoiceHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Return as file result - displays in browser&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="c1"&gt;// Or to force download with filename:&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;DownloadPdfAsFile&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GetInvoiceModel&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;GenerateInvoiceHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Third parameter triggers download instead of inline display&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"invoice.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="n"&gt;InvoiceModel&lt;/span&gt; &lt;span class="nf"&gt;GetInvoiceModel&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Your existing model retrieval logic&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;InvoiceModel&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="cm"&gt;/* ... */&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="nf"&gt;GenerateInvoiceHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;InvoiceModel&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Generate HTML from your template&lt;/span&gt;
        &lt;span class="c1"&gt;// This could use Razor rendering or string interpolation&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="s"&gt;$@"&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;!DOCTYPE html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;html&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;head&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;style&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                body &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;family&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Arial&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;sans&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;serif&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                .invoice-header &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="n"&gt;c3e50&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                table &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;width&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;%;&lt;/span&gt; &lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;collapse&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;collapse&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;top&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                th, td &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;border&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt; &lt;span class="n"&gt;solid&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="n"&gt;ddd&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="n"&gt;px&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;align&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;left&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                th &lt;/span&gt;&lt;span class="p"&gt;{{&lt;/span&gt; &lt;span class="n"&gt;background&lt;/span&gt;&lt;span class="p"&gt;-&lt;/span&gt;&lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="err"&gt;#&lt;/span&gt;&lt;span class="m"&gt;3498d&lt;/span&gt;&lt;span class="n"&gt;b&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;color&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;white&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="p"&gt;}}&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;/style&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;/head&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;body&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;div class='invoice-header'&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                &amp;lt;h1&amp;gt;Invoice #&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;InvoiceNumber&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;&amp;lt;/h1&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;/div&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;table&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                &amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Item&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Quantity&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;                &amp;lt;!-- Invoice items would be rendered here --&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;            &amp;lt;/table&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;/body&amp;gt;&lt;/span&gt;&lt;span class="err"&gt;
&lt;/span&gt;&lt;span class="s"&gt;        &amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points about this approach:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;No wkhtmltopdf binary required&lt;/li&gt;
&lt;li&gt;No platform-specific file deployment&lt;/li&gt;
&lt;li&gt;Works identically on Windows, Linux, and macOS&lt;/li&gt;
&lt;li&gt;Full CSS support including Flexbox and Grid&lt;/li&gt;
&lt;li&gt;JavaScript executes as in a real browser&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Rendering Razor Views to PDF
&lt;/h3&gt;

&lt;p&gt;For projects heavily using Razor views, IronPDF provides an extension package that renders views directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf.Extensions.Mvc.Core&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc.ViewEngines&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReportController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Controller&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ICompositeViewEngine&lt;/span&gt; &lt;span class="n"&gt;_viewEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;readonly&lt;/span&gt; &lt;span class="n"&gt;ITempDataProvider&lt;/span&gt; &lt;span class="n"&gt;_tempDataProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="nf"&gt;ReportController&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;ICompositeViewEngine&lt;/span&gt; &lt;span class="n"&gt;viewEngine&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;ITempDataProvider&lt;/span&gt; &lt;span class="n"&gt;tempDataProvider&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;_viewEngine&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;viewEngine&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;_tempDataProvider&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;tempDataProvider&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="n"&gt;IActionResult&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;GenerateReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;reportId&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;GetReportData&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;reportId&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Render the Razor view to HTML string&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;RenderViewToStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Report"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert to PDF&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitFor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"report-&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;reportId&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;private&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="n"&gt;Task&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nf"&gt;RenderViewToStringAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;viewName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;object&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;ViewData&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Model&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;model&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringWriter&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;viewResult&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;_viewEngine&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FindView&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ControllerContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;viewName&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;viewContext&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ViewContext&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
            &lt;span class="n"&gt;ControllerContext&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;viewResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;ViewData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;TempData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
            &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HtmlHelperOptions&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
        &lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="n"&gt;viewResult&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;View&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderAsync&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;viewContext&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;writer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetStringBuilder&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;ToString&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Equivalent to ActionAsPdf
&lt;/h3&gt;

&lt;p&gt;IronPDF can also render URLs, providing functionality similar to Rotativa's &lt;code&gt;ActionAsPdf&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GenerateFromUrl&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Enable JavaScript for dynamic content&lt;/span&gt;
    &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitFor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderDelay&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Render from URL - similar to ActionAsPdf&lt;/span&gt;
    &lt;span class="c1"&gt;// Note: For local development, ensure the URL is accessible&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderUrlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://localhost:5001/Report/View/123"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For detailed documentation on the methods demonstrated:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer Class&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/how-to/cshtml-to-pdf-mvc-core/" rel="noopener noreferrer"&gt;ASP.NET Core MVC Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderOptions.html" rel="noopener noreferrer"&gt;Rendering Options&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  NuGet Package Changes
&lt;/h3&gt;

&lt;p&gt;Remove Rotativa packages and add IronPDF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Remove --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"Rotativa.AspNetCore"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- Add --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"IronPdf"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="c"&gt;&amp;lt;!-- Optional: For Razor view rendering --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"IronPdf.Extensions.Mvc.Core"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"*"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Configuration Changes
&lt;/h3&gt;

&lt;p&gt;Remove Rotativa setup code:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Remove from Program.cs or Startup.cs:&lt;/span&gt;
&lt;span class="c1"&gt;// RotativaConfiguration.Setup(env.WebRootPath, "Rotativa");&lt;/span&gt;

&lt;span class="c1"&gt;// IronPDF requires no global setup&lt;/span&gt;
&lt;span class="c1"&gt;// Optionally configure license key:&lt;/span&gt;
&lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;License&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LicenseKey&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"your-license-key"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;p&gt;IronPDF is commercial software with per-developer licensing. A free trial is available for evaluation. For projects currently using Rotativa (which is MIT licensed), the licensing model represents a change, but must be weighed against:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Time saved debugging deployment issues&lt;/li&gt;
&lt;li&gt;Security of actively maintained software&lt;/li&gt;
&lt;li&gt;Support for modern web standards&lt;/li&gt;
&lt;li&gt;Cross-platform reliability&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Pattern Mapping
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Rotativa Pattern&lt;/th&gt;
&lt;th&gt;IronPDF Equivalent&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ViewAsPdf("ViewName", model)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Render HTML string with &lt;code&gt;RenderHtmlAsPdf&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;ActionAsPdf("ActionName")&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Use &lt;code&gt;RenderUrlAsPdf&lt;/code&gt; or render view to string&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;CustomSwitches&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;RenderingOptions&lt;/code&gt; properties&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PageSize.A4&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PdfPaperSize.A4&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PageMargins&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Individual margin properties&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Elimination of wkhtmltopdf binary deployment&lt;/li&gt;
&lt;li&gt;No platform-specific configuration&lt;/li&gt;
&lt;li&gt;Modern CSS support (Flexbox, Grid, CSS variables)&lt;/li&gt;
&lt;li&gt;JavaScript execution with configurable wait times&lt;/li&gt;
&lt;li&gt;Active security updates&lt;/li&gt;
&lt;li&gt;Technical support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Commercial licensing required for production use&lt;/li&gt;
&lt;li&gt;Different API patterns require code changes&lt;/li&gt;
&lt;li&gt;Larger assembly size than Rotativa wrapper (Chromium engine is included)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Rotativa's architecture as a wrapper around wkhtmltopdf creates deployment challenges in .NET Core that stem from external binary dependencies and an archived rendering engine. The common errors (binary not found, permission denied, authentication loss) all trace back to this design. With wkhtmltopdf archived and unpatched against known security vulnerabilities, continuing to use Rotativa introduces both technical debt and security risk.&lt;/p&gt;

&lt;p&gt;IronPDF provides equivalent functionality through an embedded Chromium engine that requires no external binaries, works consistently across platforms, and supports modern web standards. For projects experiencing Rotativa issues in .NET Core deployments, migration eliminates the root causes rather than adding workarounds.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by &lt;a href="https://ironsoftware.com/about-us/authors/jacobmellor/" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt;, CTO at Iron Software. He leads technical development at Iron Software and originally built IronPDF.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/webgio/Rotativa.AspNetCore" rel="noopener noreferrer"&gt;Rotativa.AspNetCore GitHub Repository&lt;/a&gt;{:rel="nofollow"} - Official .NET Core port&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/webgio/Rotativa/issues/197" rel="noopener noreferrer"&gt;Permission Denied on Ubuntu - Issue #197&lt;/a&gt;{:rel="nofollow"} - Linux deployment error&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/webgio/Rotativa.AspNetCore/issues/13" rel="noopener noreferrer"&gt;Unable to Run Under Linux - Issue #13&lt;/a&gt;{:rel="nofollow"} - Cross-platform issues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/webgio/Rotativa.AspNetCore/issues/7" rel="noopener noreferrer"&gt;Docker Deployment - Issue #7&lt;/a&gt;{:rel="nofollow"} - Container configuration&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/webgio/Rotativa.AspNetCore/issues/79" rel="noopener noreferrer"&gt;.NET Core 3.1 Setup - Issue #79&lt;/a&gt;{:rel="nofollow"} - Configuration changes&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://wkhtmltopdf.org/status.html" rel="noopener noreferrer"&gt;wkhtmltopdf Status Page&lt;/a&gt;{:rel="nofollow"} - Official archive announcement&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://nvd.nist.gov/vuln/detail/CVE-2022-35583" rel="noopener noreferrer"&gt;CVE-2022-35583 - NVD&lt;/a&gt;{:rel="nofollow"} - SSRF vulnerability details&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/wkhtmltopdf/wkhtmltopdf/issues/5249" rel="noopener noreferrer"&gt;wkhtmltopdf SSRF Issue #5249&lt;/a&gt;{:rel="nofollow"} - Security vulnerability discussion&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/wkhtmltopdf/wkhtmltopdf/issues/3391" rel="noopener noreferrer"&gt;Qt WebKit Deprecation - Issue #3391&lt;/a&gt;{:rel="nofollow"} - Why migration to QtWebEngine was not possible&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/webgio/Rotativa/issues/120" rel="noopener noreferrer"&gt;ActionAsPdf Authentication Issue #120&lt;/a&gt;{:rel="nofollow"} - Login page rendering problem&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For comprehensive IronPDF documentation including tutorials, API reference, and code examples, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Spire.PDF HTML Conversion Renders Text as Rasterized Image (Fixed)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Fri, 03 Apr 2026 13:06:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/spirepdf-html-conversion-renders-text-as-rasterized-image-fixed-adh</link>
      <guid>https://dev.to/ironsoftware/spirepdf-html-conversion-renders-text-as-rasterized-image-fixed-adh</guid>
      <description>&lt;p&gt;Developers using Spire.PDF for .NET to convert HTML to PDF frequently discover that the resulting documents contain no actual text layer. Instead of selectable, searchable text, the PDF contains rasterized bitmap images of text. This creates immediate problems: users cannot select or copy text, search functionality fails completely, screen readers cannot interpret the content, and file sizes balloon to 10-50 times larger than vector-based PDFs. The issue stems from Spire.PDF's reliance on Internet Explorer's rendering engine, which screenshots web content rather than constructing a proper PDF text layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;Spire.PDF's &lt;code&gt;LoadFromHTML&lt;/code&gt; method does not actually parse HTML and render it as PDF text. Instead, it captures a screenshot of the HTML content as rendered by Internet Explorer and embeds that screenshot as an image within the PDF. The result is a PDF that looks correct visually but is fundamentally broken for any use case requiring actual text.&lt;/p&gt;

&lt;p&gt;When developers open a PDF generated by &lt;code&gt;LoadFromHTML&lt;/code&gt;, they discover that clicking and dragging to select text does nothing. The cursor does not change to a text selection cursor because there is no text to select. What appears to be text is actually a bitmap image of text rendered at whatever DPI Internet Explorer used during the capture.&lt;/p&gt;

&lt;p&gt;This architectural decision has cascading consequences. PDF search functionality, which relies on an embedded text layer, returns no results regardless of what text appears visually in the document. Screen readers used by visually impaired users cannot interpret the document because the accessibility APIs find no text content. Copy and paste operations fail entirely. And because images require significantly more storage than vector text, file sizes increase dramatically.&lt;/p&gt;

&lt;p&gt;The root cause is dependency on the Internet Explorer rendering engine. When IE version 9 or later is installed on the system (which is the case for all modern Windows installations), Spire.PDF renders HTML as an image rather than as text.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Messages and Symptoms
&lt;/h3&gt;

&lt;p&gt;Developers typically do not receive error messages because the conversion technically succeeds. The symptoms manifest when using the resulting PDF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// When attempting to extract text programmatically:&lt;/span&gt;
&lt;span class="n"&gt;PdfTextExtractor&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfTextExtractor&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;text&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;extractor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExtractAllText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="c1"&gt;// Returns empty string or null - no text layer exists&lt;/span&gt;

&lt;span class="c1"&gt;// Text selection in PDF viewer:&lt;/span&gt;
&lt;span class="c1"&gt;// Cursor remains as pointer, not text selection cursor&lt;/span&gt;
&lt;span class="c1"&gt;// Ctrl+A selects nothing&lt;/span&gt;
&lt;span class="c1"&gt;// Ctrl+F finds nothing&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Symptoms include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text cursor never appears when hovering over "text" in the PDF&lt;/li&gt;
&lt;li&gt;Ctrl+F search finds zero results for words clearly visible on the page&lt;/li&gt;
&lt;li&gt;Copy operation copies nothing or copies garbled characters&lt;/li&gt;
&lt;li&gt;Screen readers report the document as empty or containing only images&lt;/li&gt;
&lt;li&gt;File size of 500KB HTML becomes 5-50MB PDF&lt;/li&gt;
&lt;li&gt;PDF appears grainy or blurry when zoomed, revealing pixel artifacts&lt;/li&gt;
&lt;li&gt;Hyperlinks in the original HTML do not work in the PDF&lt;/li&gt;
&lt;li&gt;Text appears fuzzy compared to vector-rendered PDFs&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;This issue impacts any deployment using Spire.PDF's HTML-to-PDF functionality on systems with Internet Explorer 9 or later:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operating Systems&lt;/strong&gt;: All Windows versions since Windows 7, which ship with IE9+. Windows 10 and 11 include Edge but retain IE components that Spire.PDF uses for rendering. The issue affects 100% of modern Windows deployments.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Framework Versions&lt;/strong&gt;: .NET Framework 4.x, .NET Core 3.1, .NET 5, .NET 6, .NET 7, and .NET 8. The IE rendering dependency exists across all supported .NET versions when using the &lt;code&gt;LoadFromHTML&lt;/code&gt; method.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;: Invoice generation systems, report builders, document archival workflows, web page preservation tools, email-to-PDF converters, and any application that needs searchable PDFs from HTML content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Accessibility Requirements&lt;/strong&gt;: Any organization subject to accessibility compliance (ADA in the US, AODA in Canada, EN 301 549 in the EU) faces legal exposure because the generated PDFs are completely inaccessible to assistive technology.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence from the Developer Community
&lt;/h2&gt;

&lt;p&gt;The text rasterization issue has been reported consistently on the E-iceblue forums for years, with users expressing frustration at the fundamental limitation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2017&lt;/td&gt;
&lt;td&gt;Initial reports of text rendered as images&lt;/td&gt;
&lt;td&gt;E-iceblue Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2018&lt;/td&gt;
&lt;td&gt;Forum thread: "LoadFromHTML as text instead of image?"&lt;/td&gt;
&lt;td&gt;E-iceblue Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2019&lt;/td&gt;
&lt;td&gt;Multiple threads about links not working, text not selectable&lt;/td&gt;
&lt;td&gt;E-iceblue Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2020&lt;/td&gt;
&lt;td&gt;Qt plugin introduced as workaround, links still not supported&lt;/td&gt;
&lt;td&gt;E-iceblue Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2021&lt;/td&gt;
&lt;td&gt;"Grainy HTML to PDF" quality issues reported&lt;/td&gt;
&lt;td&gt;E-iceblue Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022&lt;/td&gt;
&lt;td&gt;Linux Qt plugin issues documented&lt;/td&gt;
&lt;td&gt;E-iceblue Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023&lt;/td&gt;
&lt;td&gt;Issue persists, workarounds remain incomplete&lt;/td&gt;
&lt;td&gt;E-iceblue Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024&lt;/td&gt;
&lt;td&gt;Community still seeking solutions&lt;/td&gt;
&lt;td&gt;E-iceblue Forums&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Community Reports
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"doc.LoadFromHTML(url, false, true, true); This seems to only take screenshots of the webpage and save as an image in the pdf. I am looking to save the html page as text so it can be selectable in the pdf."&lt;br&gt;
— Developer, E-iceblue Forums&lt;/p&gt;

&lt;p&gt;"It seems that spire.pdf only makes a screenshot of the html file because in the final pdf you cannot mark text or follow links."&lt;br&gt;
— Developer, E-iceblue Forums&lt;/p&gt;

&lt;p&gt;"The quality of the PDF is, quite frankly, awful. The text is blurred and of very poor quality, unlike the original."&lt;br&gt;
— Developer, E-iceblue Forums, discussing LoadFromHTML output&lt;/p&gt;

&lt;p&gt;"Spire generates a PDF file that is just an image. Some of the css is not even correct, such as ignoring bold fonts."&lt;br&gt;
— Developer, E-iceblue Forums&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The official E-iceblue response confirms the architectural limitation: "The method 'LoadFromHTML' would render the pdf depending on the IE engine installed on your system, if it is IE9 or above, it would be rendered as an image while version 8 or below as text."&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;p&gt;The text rasterization issue exists because Spire.PDF delegates HTML rendering to Internet Explorer's MSHTML engine rather than implementing proper HTML parsing and PDF text rendering. This design decision made development simpler but created a fundamental limitation in the output.&lt;/p&gt;

&lt;p&gt;When &lt;code&gt;LoadFromHTML&lt;/code&gt; executes, Spire.PDF:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Loads the HTML content into an embedded IE WebBrowser control&lt;/li&gt;
&lt;li&gt;Waits for IE to render the page&lt;/li&gt;
&lt;li&gt;Captures a bitmap screenshot of the rendered content&lt;/li&gt;
&lt;li&gt;Embeds that bitmap as an image in the PDF&lt;/li&gt;
&lt;li&gt;Returns a PDF that visually represents the HTML but contains no text layer&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Internet Explorer versions 9 and later changed how content is captured, resulting in image-based output. On systems with IE8 or earlier (essentially non-existent in production today), text was captured differently and remained selectable. This created a situation where the feature worked during initial development on older Windows versions but broke on all modern systems.&lt;/p&gt;

&lt;p&gt;The consequences of this architecture:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;No text layer&lt;/strong&gt;: PDF/A compliance is impossible without a text layer&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No hyperlinks&lt;/strong&gt;: Since the PDF contains an image, anchor tags become static pixels&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Quality loss&lt;/strong&gt;: Bitmap text at screen DPI becomes fuzzy when zoomed&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;File bloat&lt;/strong&gt;: A page of text as vectors might be 50KB; as a 300DPI image, it becomes 2-5MB&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No accessibility&lt;/strong&gt;: Screen readers require a text layer to function&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a design-level limitation, not a bug to be fixed. Spire.PDF would need to replace its entire HTML rendering pipeline to generate actual PDF text content from HTML.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds
&lt;/h2&gt;

&lt;p&gt;The Spire.PDF community and E-iceblue support have suggested several workarounds, each with significant limitations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workaround 1: Qt Plugin Converter
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Use the separate Qt-based HTML converter plugin instead of &lt;code&gt;LoadFromHTML&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Spire.Pdf.HtmlConverter.Qt&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Set the plugin path&lt;/span&gt;
&lt;span class="n"&gt;HtmlConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PluginPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"C:\path\to\plugins"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Convert using Qt engine&lt;/span&gt;
&lt;span class="n"&gt;HtmlConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Convert&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="s"&gt;@"C:\output\document.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                           &lt;span class="c1"&gt;// Enable JavaScript&lt;/span&gt;
    &lt;span class="m"&gt;60000&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;                          &lt;span class="c1"&gt;// Timeout in milliseconds&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Drawing&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SizeF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;612&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;792&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;  &lt;span class="c1"&gt;// Page size&lt;/span&gt;
    &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="n"&gt;Spire&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Graphics&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PdfMargins&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;LoadHtmlType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;SourceCode&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text becomes selectable but hyperlinks are lost&lt;/li&gt;
&lt;li&gt;Official response: "The plugin method uses QT, which doesn't support keeping the link during conversion. Sorry there is no good way to deal with it yet."&lt;/li&gt;
&lt;li&gt;Requires separate plugin download and deployment&lt;/li&gt;
&lt;li&gt;Platform compatibility issues: "The plugin is compatible with X86 platform well, but the compatibility with the X64 platform is not good at present"&lt;/li&gt;
&lt;li&gt;Requires Microsoft Visual C++ 2015 Redistributable&lt;/li&gt;
&lt;li&gt;Linux support is problematic with additional dependencies&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Use Spire.Doc Instead
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Use the Spire.Doc library to convert HTML to DOCX, then DOCX to PDF.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Spire.Doc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Document&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;Document&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlFile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveToFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;FileFormat&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PDF&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires additional license for Spire.Doc&lt;/li&gt;
&lt;li&gt;Two-step conversion adds processing time&lt;/li&gt;
&lt;li&gt;HTML/CSS support limited to what Word can interpret&lt;/li&gt;
&lt;li&gt;Complex layouts may not convert correctly&lt;/li&gt;
&lt;li&gt;Cannot add PDF-specific features like attachments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: PdfHTMLTextElement for Simple HTML
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Use &lt;code&gt;PdfHTMLTextElement&lt;/code&gt; class for rendering basic HTML tags as actual text.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Spire.Pdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Spire.Pdf.HtmlConverter&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;PdfPageBase&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Pages&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Add&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="n"&gt;PdfHTMLTextElement&lt;/span&gt; &lt;span class="n"&gt;htmlElement&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfHTMLTextElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="s"&gt;"&amp;lt;b&amp;gt;Bold&amp;lt;/b&amp;gt; and &amp;lt;i&amp;gt;italic&amp;lt;/i&amp;gt; text"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PdfFontBase&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;PdfBrush&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;htmlElement&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Draw&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PointF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Only supports basic tags: Font, B, I, U, Sub, Sup, BR&lt;/li&gt;
&lt;li&gt;No CSS support&lt;/li&gt;
&lt;li&gt;No JavaScript support&lt;/li&gt;
&lt;li&gt;No complex layouts&lt;/li&gt;
&lt;li&gt;Not available in .NET Core or .NET Standard&lt;/li&gt;
&lt;li&gt;Unusable for real-world HTML documents&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 4: Increase Screenshot DPI
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Configure higher DPI for the IE rendering to improve image quality.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text is still rasterized, just at higher resolution&lt;/li&gt;
&lt;li&gt;File sizes increase even further&lt;/li&gt;
&lt;li&gt;Still no text selection, search, or accessibility&lt;/li&gt;
&lt;li&gt;Does not solve the fundamental problem&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Different Approach: IronPDF
&lt;/h2&gt;

&lt;p&gt;For applications that require actual PDF text content from HTML, the solution requires a library that renders HTML using a modern browser engine and constructs proper PDF text layers. IronPDF uses an embedded Chromium browser engine that renders HTML with full CSS3 and JavaScript support, then constructs PDFs with vector text, working hyperlinks, and accessibility metadata.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why IronPDF Produces Selectable Text
&lt;/h3&gt;

&lt;p&gt;IronPDF's architecture differs fundamentally from Spire.PDF's IE-based approach. Rather than capturing screenshots, IronPDF:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Renders HTML using an embedded Chromium engine (the same engine as Chrome and Edge)&lt;/li&gt;
&lt;li&gt;Processes the rendered DOM to construct PDF text objects&lt;/li&gt;
&lt;li&gt;Preserves hyperlinks as PDF annotations&lt;/li&gt;
&lt;li&gt;Maintains the document structure for accessibility&lt;/li&gt;
&lt;li&gt;Generates vector-based text that scales without quality loss&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This approach produces PDFs where:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text is selectable with click-and-drag&lt;/li&gt;
&lt;li&gt;Ctrl+F search finds all text content&lt;/li&gt;
&lt;li&gt;Copy and paste works correctly&lt;/li&gt;
&lt;li&gt;Screen readers can interpret the document&lt;/li&gt;
&lt;li&gt;Hyperlinks remain clickable&lt;/li&gt;
&lt;li&gt;File sizes remain small (text as vectors, not bitmaps)&lt;/li&gt;
&lt;li&gt;Zooming shows sharp text at any scale&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;

&lt;p&gt;The following example demonstrates HTML-to-PDF conversion that produces fully selectable, searchable text:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;HtmlToPdfWithSelectableText&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConvertHtmlWithTextLayer&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Initialize the Chromium-based renderer&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure rendering options&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginLeft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginRight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;15&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Enable JavaScript for dynamic content&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// HTML with various formatting and links&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
            &amp;lt;!DOCTYPE html&amp;gt;
            &amp;lt;html&amp;gt;
            &amp;lt;head&amp;gt;
                &amp;lt;style&amp;gt;
                    body {
                        font-family: 'Segoe UI', Arial, sans-serif;
                        line-height: 1.6;
                        color: #333;
                    }
                    h1 { color: #2c3e50; }
                    .highlight { background-color: #ffffcc; }
                    a { color: #3498db; }
                    table { border-collapse: collapse; width: 100%; }
                    td, th { border: 1px solid #ddd; padding: 8px; }
                &amp;lt;/style&amp;gt;
            &amp;lt;/head&amp;gt;
            &amp;lt;body&amp;gt;
                &amp;lt;h1&amp;gt;Invoice #12345&amp;lt;/h1&amp;gt;
                &amp;lt;p&amp;gt;This text is &amp;lt;span class='highlight'&amp;gt;fully selectable&amp;lt;/span&amp;gt;
                   and searchable in the resulting PDF.&amp;lt;/p&amp;gt;

                &amp;lt;p&amp;gt;Visit our website: &amp;lt;a href='https://example.com'&amp;gt;example.com&amp;lt;/a&amp;gt;&amp;lt;/p&amp;gt;

                &amp;lt;table&amp;gt;
                    &amp;lt;tr&amp;gt;&amp;lt;th&amp;gt;Item&amp;lt;/th&amp;gt;&amp;lt;th&amp;gt;Price&amp;lt;/th&amp;gt;&amp;lt;/tr&amp;gt;
                    &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Widget A&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$29.99&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
                    &amp;lt;tr&amp;gt;&amp;lt;td&amp;gt;Widget B&amp;lt;/td&amp;gt;&amp;lt;td&amp;gt;$49.99&amp;lt;/td&amp;gt;&amp;lt;/tr&amp;gt;
                &amp;lt;/table&amp;gt;

                &amp;lt;p&amp;gt;Total: $79.98&amp;lt;/p&amp;gt;
            &amp;lt;/body&amp;gt;
            &amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Render HTML to PDF with proper text layer&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Save the PDF - text will be selectable&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"invoice.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Demonstrate that text extraction works&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;extractedText&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ExtractAllText&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"Extracted text (proves text layer exists):"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;extractedText&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// File size comparison:&lt;/span&gt;
        &lt;span class="c1"&gt;// - Rasterized image-based PDF: typically 2-5 MB for a single page&lt;/span&gt;
        &lt;span class="c1"&gt;// - Vector text-based PDF: typically 50-200 KB for the same content&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConvertUrlWithAccessibility&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure for accessibility compliance&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Title&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"Accessible PDF Document"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Render from URL - hyperlinks remain clickable&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderUrlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"https://example.com/article"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"accessible-article.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="c1"&gt;// The resulting PDF:&lt;/span&gt;
        &lt;span class="c1"&gt;// - Contains actual text that screen readers can interpret&lt;/span&gt;
        &lt;span class="c1"&gt;// - Preserves hyperlinks as clickable PDF annotations&lt;/span&gt;
        &lt;span class="c1"&gt;// - Maintains reading order from the HTML structure&lt;/span&gt;
        &lt;span class="c1"&gt;// - Complies with accessibility requirements&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;

    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;BatchConvertWithConsistentQuality&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="n"&gt;htmlFiles&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="s"&gt;"report1.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"report2.html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"report3.html"&lt;/span&gt; &lt;span class="p"&gt;};&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;htmlFile&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;htmlFiles&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlFile&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;htmlFile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;".html"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;".pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
                &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Every PDF has:&lt;/span&gt;
                &lt;span class="c1"&gt;// - Selectable text (not screenshots)&lt;/span&gt;
                &lt;span class="c1"&gt;// - Working hyperlinks&lt;/span&gt;
                &lt;span class="c1"&gt;// - Searchable content&lt;/span&gt;
                &lt;span class="c1"&gt;// - Small file size&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points about this code:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;ChromePdfRenderer uses Chromium for rendering, not Internet Explorer&lt;/li&gt;
&lt;li&gt;Text is rendered as vector PDF text objects, not rasterized images&lt;/li&gt;
&lt;li&gt;Hyperlinks in HTML become clickable PDF link annotations&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;ExtractAllText()&lt;/code&gt; returns actual content because a text layer exists&lt;/li&gt;
&lt;li&gt;File sizes remain small because text is stored as vectors&lt;/li&gt;
&lt;li&gt;CSS and JavaScript are fully supported&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For details on the methods used above:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer&lt;/a&gt; - Main rendering class using Chromium engine&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html#IronPdf_ChromePdfRenderer_RenderHtmlAsPdf_System_String_" rel="noopener noreferrer"&gt;RenderHtmlAsPdf&lt;/a&gt; - Convert HTML string to PDF&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html#IronPdf_ChromePdfRenderer_RenderUrlAsPdf_System_String_" rel="noopener noreferrer"&gt;RenderUrlAsPdf&lt;/a&gt; - Convert web page URL to PDF&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.PdfDocument.html#IronPdf_PdfDocument_ExtractAllText" rel="noopener noreferrer"&gt;ExtractAllText&lt;/a&gt; - Text extraction proving text layer exists&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/tutorials/html-to-pdf/" rel="noopener noreferrer"&gt;HTML to PDF Tutorial&lt;/a&gt; - Complete guide to HTML rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;p&gt;IronPDF is commercial software with per-developer licensing. A free trial is available for evaluation without watermarks for development purposes. Teams should verify that IronPDF meets their specific HTML rendering requirements before committing to migration.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Differences
&lt;/h3&gt;

&lt;p&gt;The migration from Spire.PDF to IronPDF for HTML conversion is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Spire.PDF (produces rasterized images)&lt;/span&gt;
&lt;span class="n"&gt;PdfDocument&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;LoadFromHTML&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveToFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// IronPDF (produces selectable text)&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderUrlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The conceptual model differs slightly: Spire.PDF loads HTML into an existing document object, while IronPDF's renderer creates new PDF documents. For most use cases, this requires minimal code changes.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Text that is actually selectable and searchable&lt;/li&gt;
&lt;li&gt;Hyperlinks that work in the PDF&lt;/li&gt;
&lt;li&gt;Accessibility for screen readers and assistive technology&lt;/li&gt;
&lt;li&gt;File sizes 10-50x smaller (text as vectors, not images)&lt;/li&gt;
&lt;li&gt;Modern CSS3 and JavaScript support&lt;/li&gt;
&lt;li&gt;Consistent rendering across platforms&lt;/li&gt;
&lt;li&gt;No dependency on Internet Explorer or system-installed browsers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Commercial licensing cost&lt;/li&gt;
&lt;li&gt;Slightly different API structure&lt;/li&gt;
&lt;li&gt;Chromium engine adds approximately 100-200MB to deployment size&lt;/li&gt;
&lt;li&gt;First render may take 1-2 seconds for Chromium initialization&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;Spire.PDF's HTML-to-PDF conversion produces rasterized screenshots rather than actual PDF text, making the resulting documents unsearchable, inaccessible, and unnecessarily large. This is an architectural limitation of the IE-based rendering approach that cannot be fixed with configuration changes. For applications requiring proper PDF text layers, migrating to a library with Chromium-based rendering provides PDFs where text is selectable, searchable, and accessible.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Written by &lt;a href="https://ironsoftware.com/about-us/authors/jacobmellor/" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt;, CTO at Iron Software and original developer of IronPDF.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/html-to-pdf-can-t-select-text-in-pdf-t8618.html" rel="noopener noreferrer"&gt;Html to PDF can't select text in PDF - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - Primary thread documenting the text selection issue&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/loadfromhtml-as-text-instead-of-image-t7213.html" rel="noopener noreferrer"&gt;LoadFromHTML as text instead of image? - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - Developer request for actual text rendering&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/htmltopdf-not-possible-to-mark-text-or-follow-links-t7860.html" rel="noopener noreferrer"&gt;HtmlToPdf not possible to mark text or follow links - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - Links and text selection issues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/grainy-html-to-pdf-t7617.html" rel="noopener noreferrer"&gt;Grainy HTML to PDF - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - Quality degradation from rasterization&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/issue-with-spire-html-to-pdf-conversion-t8364.html" rel="noopener noreferrer"&gt;Issue with Spire HTML to PDF conversion - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - General conversion problems&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/Knowledgebase/Spire.PDF/Spire.PDF-Program-Guide/New-Plugin-of-Converting-HTML-to-PDF.html" rel="noopener noreferrer"&gt;Convert HTML to PDF with New Plugin - E-iceblue Knowledge Base&lt;/a&gt;{:rel="nofollow"} - Qt plugin documentation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/massive-filesize-increase-problem-t5603.html" rel="noopener noreferrer"&gt;Massive Filesize Increase Problem - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - File size bloat from image-based conversion&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/html-to-pdf-t4625.html" rel="noopener noreferrer"&gt;HTML to PDF - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - Official confirmation of IE dependency&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/troubleshoot-qt-plugin-issue-t12031.html" rel="noopener noreferrer"&gt;Troubleshoot QT Plugin Issue - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - Qt plugin limitations&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://www.e-iceblue.com/forum/html-string-to-pdf-one-linux-with-qt-plugin-not-working-t12656.html" rel="noopener noreferrer"&gt;html string to pdf one Linux with QT plugin not working - Spire.PDF Forums&lt;/a&gt;{:rel="nofollow"} - Cross-platform plugin issues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For IronPDF documentation and tutorials, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>iTextSharp HTML to PDF in C#: Why HTMLWorker Breaks (Issue Fixed)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Fri, 03 Apr 2026 10:05:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/itextsharp-html-to-pdf-in-c-why-htmlworker-breaks-issue-fixed-5c1g</link>
      <guid>https://dev.to/ironsoftware/itextsharp-html-to-pdf-in-c-why-htmlworker-breaks-issue-fixed-5c1g</guid>
      <description>&lt;p&gt;Developers searching for HTML-to-PDF conversion with iTextSharp encounter a fundamental limitation: iTextSharp and iText 7 were not designed for rendering HTML as a web browser would. The libraries provide limited HTML parsing capabilities that break with modern HTML5/CSS3 content. With over 300,000 developers viewing this question on Stack Overflow, the demand is clear but the solution within iText is not straightforward. This article examines the limitations, shows the correct patterns for iTextSharp, and presents alternatives with browser-accurate rendering.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;iTextSharp (the .NET port of iText 5) and its successor iText 7 are PDF manipulation libraries, not HTML rendering engines. They provide &lt;code&gt;HTMLWorker&lt;/code&gt; (deprecated) and &lt;code&gt;pdfHTML&lt;/code&gt; (add-on product) for HTML parsing, but neither implements a browser-compatible rendering engine.&lt;/p&gt;

&lt;p&gt;When developers attempt to convert HTML to PDF with iTextSharp, they encounter:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Incomplete CSS support (no flexbox, grid, or modern layout)&lt;/li&gt;
&lt;li&gt;Missing JavaScript execution (dynamic content doesn't render)&lt;/li&gt;
&lt;li&gt;Broken layouts for responsive designs&lt;/li&gt;
&lt;li&gt;No support for web fonts without manual configuration&lt;/li&gt;
&lt;li&gt;Image handling issues with relative URLs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The expectation gap is significant: developers want browser-quality PDF output, but iTextSharp provides basic HTML parsing at best.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Messages and Symptoms
&lt;/h3&gt;

&lt;p&gt;Common issues when using iTextSharp's HTMLWorker:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;iTextSharp.text.html.simpleparser.HTMLWorker is obsolete
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// This approach produces broken output for modern HTML&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;stringReader&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;StringReader&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="n"&gt;HTMLWorker&lt;/span&gt; &lt;span class="n"&gt;htmlWorker&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;HTMLWorker&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;document&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;htmlWorker&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stringReader&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Fails on CSS3, HTML5 elements&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With iText 7's pdfHTML add-on:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;itextpdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;html2pdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exceptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;CssApplierInitializationException&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="nc"&gt;Cannot&lt;/span&gt; &lt;span class="n"&gt;find&lt;/span&gt; &lt;span class="no"&gt;CSS&lt;/span&gt; &lt;span class="n"&gt;applier&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;tag&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;article&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight java"&gt;&lt;code&gt;&lt;span class="n"&gt;com&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;itextpdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;html2pdf&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;exceptions&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="na"&gt;TagWorkerInitializationException&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;
&lt;span class="nc"&gt;Tag&lt;/span&gt; &lt;span class="n"&gt;worker&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;section&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;not&lt;/span&gt; &lt;span class="n"&gt;found&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Symptoms include:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Tables rendering without proper column widths&lt;/li&gt;
&lt;li&gt;Floated elements collapsing or overlapping&lt;/li&gt;
&lt;li&gt;Background images not appearing&lt;/li&gt;
&lt;li&gt;Custom fonts displaying as fallback fonts&lt;/li&gt;
&lt;li&gt;Responsive layouts breaking completely&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;The 309,000+ views on Stack Overflow indicate massive demand across:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Industries&lt;/strong&gt;: Reporting systems, invoice generation, document automation, legal document processing, healthcare records, and any system generating documents from web content.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Frameworks&lt;/strong&gt;: .NET Framework with iTextSharp, .NET Core/5/6/7/8 with iText 7.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Converting HTML templates to PDF invoices or receipts&lt;/li&gt;
&lt;li&gt;Generating reports from HTML dashboards&lt;/li&gt;
&lt;li&gt;Creating printable versions of web pages&lt;/li&gt;
&lt;li&gt;Automating document generation from CMS content&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Evidence from the Developer Community
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Scale of the Problem
&lt;/h3&gt;

&lt;p&gt;Stack Overflow tracks these highly-viewed questions:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Question&lt;/th&gt;
&lt;th&gt;Views&lt;/th&gt;
&lt;th&gt;Score&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;"How to convert HTML to PDF using iTextSharp"&lt;/td&gt;
&lt;td&gt;309,021&lt;/td&gt;
&lt;td&gt;77&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"Convert HTML to PDF in .NET"&lt;/td&gt;
&lt;td&gt;959,034&lt;/td&gt;
&lt;td&gt;528&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;"iText 7 HTML to PDF conversion"&lt;/td&gt;
&lt;td&gt;185,727&lt;/td&gt;
&lt;td&gt;21&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2014-08-06&lt;/td&gt;
&lt;td&gt;Original question posted&lt;/td&gt;
&lt;td&gt;Stack Overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2015-2018&lt;/td&gt;
&lt;td&gt;Answers reference HTMLWorker (now deprecated)&lt;/td&gt;
&lt;td&gt;Stack Overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2019-2021&lt;/td&gt;
&lt;td&gt;Answers shift to pdfHTML add-on recommendation&lt;/td&gt;
&lt;td&gt;Stack Overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025-01-15&lt;/td&gt;
&lt;td&gt;Question still receiving new views and answers&lt;/td&gt;
&lt;td&gt;Stack Overflow&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Community Reports
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"I want to convert the below HTML to PDF using iTextSharp but don't know where to start."&lt;br&gt;
— Developer, Stack Overflow, August 2014&lt;/p&gt;

&lt;p&gt;"HTMLWorker is deprecated and limited. pdfHTML is better but requires a separate license."&lt;br&gt;
— Stack Overflow Answer, 2020&lt;/p&gt;

&lt;p&gt;"For anything with complex CSS, you need a browser engine. iText's HTML support is basic."&lt;br&gt;
— Stack Overflow Comment, 2023&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Getting Started: NuGet Package Installation
&lt;/h2&gt;

&lt;p&gt;Before examining the limitations, developers need to understand the different package options.&lt;/p&gt;

&lt;h3&gt;
  
  
  iTextSharp (.NET Framework)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# For .NET Framework 4.x projects&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Install-Package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iTextSharp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;5.5.13.3&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Package reference in .csproj --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"iTextSharp"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"5.5.13.3"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note: iTextSharp 5.x is no longer actively developed. The last release was in 2022.&lt;/p&gt;

&lt;h3&gt;
  
  
  iText 7 (.NET Core / .NET 5+)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight powershell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Core library&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Install-Package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;iText7&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;8.0.2&lt;/span&gt;&lt;span class="w"&gt;

&lt;/span&gt;&lt;span class="c"&gt;# HTML conversion add-on (separate commercial license required)&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="n"&gt;Install-Package&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;itext7.pdfhtml&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nt"&gt;-Version&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;5.0.2&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Package references --&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"iText7"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"itext7.pdfhtml"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"5.0.2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Project Configuration
&lt;/h3&gt;

&lt;p&gt;For .NET Core or .NET 6+ projects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight xml"&gt;&lt;code&gt;&lt;span class="nt"&gt;&amp;lt;Project&lt;/span&gt; &lt;span class="na"&gt;Sdk=&lt;/span&gt;&lt;span class="s"&gt;"Microsoft.NET.Sdk"&lt;/span&gt;&lt;span class="nt"&gt;&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;PropertyGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;TargetFramework&amp;gt;&lt;/span&gt;net8.0&lt;span class="nt"&gt;&amp;lt;/TargetFramework&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;ImplicitUsings&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/ImplicitUsings&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;Nullable&amp;gt;&lt;/span&gt;enable&lt;span class="nt"&gt;&amp;lt;/Nullable&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/PropertyGroup&amp;gt;&lt;/span&gt;

  &lt;span class="nt"&gt;&amp;lt;ItemGroup&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"iText7"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"8.0.2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
    &lt;span class="nt"&gt;&amp;lt;PackageReference&lt;/span&gt; &lt;span class="na"&gt;Include=&lt;/span&gt;&lt;span class="s"&gt;"itext7.pdfhtml"&lt;/span&gt; &lt;span class="na"&gt;Version=&lt;/span&gt;&lt;span class="s"&gt;"5.0.2"&lt;/span&gt; &lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
  &lt;span class="nt"&gt;&amp;lt;/ItemGroup&amp;gt;&lt;/span&gt;
&lt;span class="nt"&gt;&amp;lt;/Project&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Licensing Considerations
&lt;/h3&gt;

&lt;p&gt;iText uses dual licensing:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;AGPL v3&lt;/strong&gt;: Free for open-source projects that release source code&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Commercial License&lt;/strong&gt;: Required for proprietary/closed-source applications&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The pdfHTML add-on requires an additional commercial license beyond the base iText 7 license.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;p&gt;iTextSharp and iText 7 are fundamentally PDF object manipulation libraries. PDF generation from scratch, modification, form filling, and extraction are their primary purposes.&lt;/p&gt;

&lt;p&gt;HTML-to-PDF conversion requires:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;HTML Parser&lt;/strong&gt;: Understanding HTML5 elements and structure&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;CSS Engine&lt;/strong&gt;: Implementing the CSS box model, selectors, cascading&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Layout Engine&lt;/strong&gt;: Calculating positions, handling floats, flexbox, grid&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Font Renderer&lt;/strong&gt;: Loading and rendering fonts including web fonts&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript Engine&lt;/strong&gt;: Executing scripts that modify content&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;iText provides partial implementations of 1 and 2, with significant gaps. It does not include 3, 4, or 5 in any browser-compatible form.&lt;/p&gt;

&lt;h3&gt;
  
  
  HTMLWorker vs pdfHTML Comparison
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;HTMLWorker (iText 5)&lt;/th&gt;
&lt;th&gt;pdfHTML (iText 7)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Status&lt;/td&gt;
&lt;td&gt;Deprecated&lt;/td&gt;
&lt;td&gt;Active&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;AGPL/Commercial&lt;/td&gt;
&lt;td&gt;Additional license required&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HTML5 elements&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CSS3 support&lt;/td&gt;
&lt;td&gt;Minimal&lt;/td&gt;
&lt;td&gt;Partial (no flexbox/grid)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;JavaScript&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Web fonts&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Active development&lt;/td&gt;
&lt;td&gt;No&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;pdfHTML&lt;/code&gt; add-on improves on HTMLWorker but still lacks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Full CSS3 support (flexbox, grid, variables)&lt;/li&gt;
&lt;li&gt;JavaScript execution&lt;/li&gt;
&lt;li&gt;Browser-compatible rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;This is a design limitation, not a bug. Implementing a full browser engine would be a separate product entirely.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Workaround 1: pdfHTML Add-on
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Purchase and use iText's pdfHTML commercial add-on.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;iText.Html2pdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;ConvertWithPdfHtml&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;outputStream&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;MemoryStream&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;HtmlConverter&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ConvertToPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;outputStream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;outputStream&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToArray&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Separate commercial license required&lt;/li&gt;
&lt;li&gt;Still lacks flexbox, grid, and modern CSS3&lt;/li&gt;
&lt;li&gt;No JavaScript execution&lt;/li&gt;
&lt;li&gt;Output quality varies significantly from browser rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Pre-process HTML
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Simplify HTML to only use features iTextSharp supports.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Convert modern HTML to iText-compatible subset&lt;/span&gt;
&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;simplifiedHtml&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;article&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;div&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;/article&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;/div&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;section&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;div&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Replace&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;/section&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;/div&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Remove CSS that won't work&lt;/span&gt;
&lt;span class="c1"&gt;// Inline all styles&lt;/span&gt;
&lt;span class="c1"&gt;// Etc.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Significant development effort&lt;/li&gt;
&lt;li&gt;Maintains two versions of templates&lt;/li&gt;
&lt;li&gt;Breaks responsive designs&lt;/li&gt;
&lt;li&gt;Not scalable for complex documents&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: HTML to Image to PDF
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Render HTML to an image using a browser automation tool, then embed in PDF.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Text is not selectable in output PDF&lt;/li&gt;
&lt;li&gt;File sizes much larger&lt;/li&gt;
&lt;li&gt;Quality issues with scaling&lt;/li&gt;
&lt;li&gt;Loss of PDF features (links, bookmarks)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Different Approach: IronPDF
&lt;/h2&gt;

&lt;p&gt;IronPDF embeds a Chromium browser engine specifically for HTML-to-PDF conversion. Rather than parsing HTML and approximating browser behavior, it renders HTML exactly as Chrome would.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why IronPDF Handles HTML Differently
&lt;/h3&gt;

&lt;p&gt;IronPDF's architecture is fundamentally different:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Full Chromium Engine&lt;/strong&gt;: Same rendering engine used by Google Chrome&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Complete CSS3&lt;/strong&gt;: Flexbox, Grid, Variables, Animations (rendered as final state)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;JavaScript Execution&lt;/strong&gt;: Dynamic content, charting libraries, frameworks all work&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Web Fonts&lt;/strong&gt;: Google Fonts, custom fonts load automatically&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Responsive Rendering&lt;/strong&gt;: Media queries and viewport handling included&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;When you convert HTML with IronPDF, you're generating a PDF from an actual browser render, not a parsed approximation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;ReportGenerator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GenerateReport&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure rendering options&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginLeft&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginRight&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Enable features for complex content&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Wait for JS to complete&lt;/span&gt;

        &lt;span class="c1"&gt;// Render HTML to PDF - uses actual Chrome rendering&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Example with modern HTML/CSS:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;CreateModernDashboardPdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;link href='https://fonts.googleapis.com/css2?family=Inter:wght@400;600&amp;amp;display=swap' rel='stylesheet'&amp;gt;
    &amp;lt;style&amp;gt;
        body {
            font-family: 'Inter', sans-serif;
            margin: 0;
            padding: 20px;
        }
        .dashboard {
            display: grid;
            grid-template-columns: repeat(3, 1fr);
            gap: 20px;
        }
        .card {
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            border-radius: 12px;
            padding: 24px;
            color: white;
        }
        .card h3 {
            margin: 0 0 8px 0;
            font-weight: 600;
        }
        .card .value {
            font-size: 2.5rem;
            font-weight: 600;
        }
        @media print {
            .dashboard { grid-template-columns: repeat(2, 1fr); }
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Q4 2025 Dashboard&amp;lt;/h1&amp;gt;
    &amp;lt;div class='dashboard'&amp;gt;
        &amp;lt;div class='card'&amp;gt;
            &amp;lt;h3&amp;gt;Revenue&amp;lt;/h3&amp;gt;
            &amp;lt;div class='value'&amp;gt;$2.4M&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class='card'&amp;gt;
            &amp;lt;h3&amp;gt;Users&amp;lt;/h3&amp;gt;
            &amp;lt;div class='value'&amp;gt;48.2K&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
        &amp;lt;div class='card'&amp;gt;
            &amp;lt;h3&amp;gt;Conversion&amp;lt;/h3&amp;gt;
            &amp;lt;div class='value'&amp;gt;3.2%&amp;lt;/div&amp;gt;
        &amp;lt;/div&amp;gt;
    &amp;lt;/div&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points about this code:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;CSS Grid layout works exactly as in a browser&lt;/li&gt;
&lt;li&gt;Google Fonts load automatically&lt;/li&gt;
&lt;li&gt;Gradients and border-radius render correctly&lt;/li&gt;
&lt;li&gt;Print media queries are respected&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Converting URLs
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;ConvertWebPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Render a live web page&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderUrlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;url&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  JavaScript Execution: Charts and Dynamic Content
&lt;/h3&gt;

&lt;p&gt;One major difference is JavaScript support. iText cannot execute JavaScript, so charts and dynamically generated content do not render.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GenerateChartPdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Enable JavaScript and wait for execution&lt;/span&gt;
    &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;WaitFor&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;JavaScript&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;2000&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt; &lt;span class="c1"&gt;// Wait up to 2 seconds&lt;/span&gt;

    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;script src='https://cdn.jsdelivr.net/npm/chart.js'&amp;gt;&amp;lt;/script&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;h1&amp;gt;Sales Report&amp;lt;/h1&amp;gt;
    &amp;lt;canvas id='myChart' width='400' height='200'&amp;gt;&amp;lt;/canvas&amp;gt;
    &amp;lt;script&amp;gt;
        var ctx = document.getElementById('myChart').getContext('2d');
        new Chart(ctx, {
            type: 'bar',
            data: {
                labels: ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun'],
                datasets: [{
                    label: 'Sales ($K)',
                    data: [12, 19, 3, 5, 2, 3],
                    backgroundColor: 'rgba(54, 162, 235, 0.8)'
                }]
            }
        });
    &amp;lt;/script&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Print-Specific CSS Handling
&lt;/h3&gt;

&lt;p&gt;IronPDF respects print media queries, allowing print-specific styling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GeneratePrintOptimizedDocument&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="c1"&gt;// Use print media type&lt;/span&gt;
    &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;CssMediaType&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfCssMediaType&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Print&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
&amp;lt;!DOCTYPE html&amp;gt;
&amp;lt;html&amp;gt;
&amp;lt;head&amp;gt;
    &amp;lt;style&amp;gt;
        /* Screen styles */
        @media screen {
            body { background: #f5f5f5; }
            .no-print { display: block; }
        }

        /* Print styles */
        @media print {
            body {
                background: white;
                font-size: 12pt;
            }
            .no-print { display: none; }
            .page-break { page-break-after: always; }

            a[href]::after {
                content: ' (' attr(href) ')';
            }
        }
    &amp;lt;/style&amp;gt;
&amp;lt;/head&amp;gt;
&amp;lt;body&amp;gt;
    &amp;lt;div class='no-print'&amp;gt;This navigation won't appear in PDF&amp;lt;/div&amp;gt;

    &amp;lt;h1&amp;gt;Chapter 1&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Content for first page...&amp;lt;/p&amp;gt;

    &amp;lt;div class='page-break'&amp;gt;&amp;lt;/div&amp;gt;

    &amp;lt;h1&amp;gt;Chapter 2&amp;lt;/h1&amp;gt;
    &amp;lt;p&amp;gt;Content for second page...&amp;lt;/p&amp;gt;
&amp;lt;/body&amp;gt;
&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  PDF/A Compliance for Archival
&lt;/h3&gt;

&lt;p&gt;For long-term document archival:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;GenerateArchivalPdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

    &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;&amp;lt;h1&amp;gt;Archived Document&amp;lt;/h1&amp;gt;&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="c1"&gt;// Save as PDF/A-3b for archival compliance&lt;/span&gt;
    &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAsPdfA&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"archived-document.pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfAVersions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfA3b&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For more details on the methods used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderOptions.html" rel="noopener noreferrer"&gt;RenderingOptions&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/tutorials/html-to-pdf/" rel="noopener noreferrer"&gt;HTML to PDF Tutorial&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/how-to/pdfa/" rel="noopener noreferrer"&gt;PDF/A Compliance&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;IronPDF is commercial software with per-developer licensing&lt;/li&gt;
&lt;li&gt;Free trial available for evaluation&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/licensing/" rel="noopener noreferrer"&gt;Pricing details&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Differences
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;iTextSharp: PDF object manipulation with limited HTML parsing&lt;/li&gt;
&lt;li&gt;IronPDF: HTML/CSS-first approach with full browser rendering&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Migration typically means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Remove HTMLWorker or pdfHTML code&lt;/li&gt;
&lt;li&gt;Replace with ChromePdfRenderer&lt;/li&gt;
&lt;li&gt;Keep existing HTML templates unchanged (or simplify them)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Browser-quality PDF output from any HTML/CSS&lt;/li&gt;
&lt;li&gt;JavaScript support for dynamic content&lt;/li&gt;
&lt;li&gt;Full CSS3 including modern layout (flexbox, grid)&lt;/li&gt;
&lt;li&gt;Web fonts load automatically&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Chromium binaries add to deployment size&lt;/li&gt;
&lt;li&gt;Different pricing model than iText&lt;/li&gt;
&lt;li&gt;Different API paradigm (HTML-first vs PDF-first)&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;iTextSharp and iText 7 were designed for PDF manipulation, not browser-quality HTML rendering. Developers seeking accurate HTML-to-PDF conversion face fundamental limitations with these libraries. For projects where HTML templates must render exactly as they appear in browsers, a Chromium-based approach provides the rendering accuracy that parsed HTML cannot achieve.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/jacob-mellor" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt; has spent 25+ years building developer tools, including IronPDF.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/questions/25164257/how-to-convert-html-to-pdf-using-itextsharp" rel="noopener noreferrer"&gt;Stack Overflow: How to convert HTML to PDF using iTextSharp&lt;/a&gt;{:rel="nofollow"} - 309K+ views&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://stackoverflow.com/questions/564650/convert-html-to-pdf-in-net" rel="noopener noreferrer"&gt;Stack Overflow: Convert HTML to PDF in .NET&lt;/a&gt;{:rel="nofollow"} - 959K+ views&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For the latest IronPDF documentation and tutorials, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>SelectPdf Linux Error: Unable to Load kernel32.dll (Issue Fixed)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Thu, 02 Apr 2026 14:34:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/selectpdf-linux-error-unable-to-load-kernel32dll-issue-fixed-10pd</link>
      <guid>https://dev.to/ironsoftware/selectpdf-linux-error-unable-to-load-kernel32dll-issue-fixed-10pd</guid>
      <description>&lt;p&gt;Developers attempting to use SelectPdf on Linux environments encounter a runtime exception: &lt;code&gt;Unable to load shared library 'kernel32.dll' or one of its dependencies&lt;/code&gt;. This error indicates a fundamental platform limitation rather than a configuration issue. SelectPdf is a Windows-only library with no Linux support.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;SelectPdf relies on Windows-specific native libraries, including &lt;code&gt;kernel32.dll&lt;/code&gt;, which is a core Windows system component. When developers deploy applications using SelectPdf to Linux servers, Docker containers, or other non-Windows environments, the application fails immediately upon attempting any PDF operation.&lt;/p&gt;

&lt;p&gt;This limitation affects developers who initially build and test on Windows development machines, only to discover the incompatibility when deploying to production Linux environments. The error occurs regardless of .NET version, framework configuration, or runtime settings because the underlying dependency simply does not exist on Linux.&lt;/p&gt;

&lt;p&gt;Unlike some libraries where Linux compatibility issues stem from optional dependencies that can be worked around, SelectPdf's Windows-only architecture means there is no configuration change, package installation, or code modification that enables Linux operation.&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Messages and Symptoms
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;System.DllNotFoundException: Unable to load shared library 'kernel32.dll' or one of its dependencies.
In order to help diagnose loading problems, consider setting the LD_DEBUG environment variable:
libkernel32.dll: cannot open shared object file: No such file or directory
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The error surfaces immediately when SelectPdf attempts to initialize its rendering engine, preventing any HTML-to-PDF conversion from occurring.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;This limitation impacts developers in several common scenarios:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Linux server deployments (Ubuntu, Debian, CentOS, RHEL, Alpine)&lt;/li&gt;
&lt;li&gt;Docker containerized applications using Linux base images&lt;/li&gt;
&lt;li&gt;Azure App Service on Linux&lt;/li&gt;
&lt;li&gt;AWS Lambda and other serverless platforms&lt;/li&gt;
&lt;li&gt;CI/CD pipelines running on Linux build agents&lt;/li&gt;
&lt;li&gt;Kubernetes deployments with Linux nodes&lt;/li&gt;
&lt;li&gt;macOS development environments&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The issue affects all .NET versions including .NET Core 3.1, .NET 5, .NET 6, .NET 7, and .NET 8. Since the limitation is architectural rather than version-specific, no framework update resolves it.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence from the Developer Community
&lt;/h2&gt;

&lt;p&gt;Developers have reported this issue across multiple channels, consistently receiving the same response: SelectPdf does not support Linux.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2021-02-10&lt;/td&gt;
&lt;td&gt;First GitHub issue opened&lt;/td&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2021-02-10&lt;/td&gt;
&lt;td&gt;Official response confirms Windows-only&lt;/td&gt;
&lt;td&gt;GitHub&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025-01-20&lt;/td&gt;
&lt;td&gt;No Linux support announced&lt;/td&gt;
&lt;td&gt;-&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Community Reports
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"Unable to load shared library 'kernel32.dll' or one of its dependencies"&lt;br&gt;
-- GitHub Issue #2, SelectPdf Repository, 2021&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;The GitHub issue repository for SelectPdf shows multiple developers encountering this same limitation when attempting Linux deployments. The maintainer response confirms SelectPdf's Windows-only architecture.&lt;/p&gt;

&lt;p&gt;Additional developers on Stack Overflow and Reddit have reported discovering this limitation only after building applications with SelectPdf, leading to significant refactoring efforts when deployment requirements included Linux environments.&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis
&lt;/h2&gt;

&lt;p&gt;SelectPdf depends directly on Windows API calls through P/Invoke to &lt;code&gt;kernel32.dll&lt;/code&gt; and potentially other Windows system libraries. This architectural decision means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Native Dependency&lt;/strong&gt;: The library makes system calls to Windows kernel functions that have no Linux equivalents&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No Abstraction Layer&lt;/strong&gt;: Unlike cross-platform libraries that use abstraction layers (like .NET's own cross-platform APIs), SelectPdf calls Windows APIs directly&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Binary Incompatibility&lt;/strong&gt;: The compiled native components are Windows PE (Portable Executable) format, not Linux ELF format&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is not a bug that can be fixed with a patch or configuration change. Supporting Linux would require a complete rewrite of SelectPdf's rendering engine architecture, which the maintainers have indicated is not planned.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Workaround 1: Wine Compatibility Layer
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Some developers have attempted running SelectPdf through Wine on Linux.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Unreliable rendering results&lt;/li&gt;
&lt;li&gt;Performance overhead&lt;/li&gt;
&lt;li&gt;Additional deployment complexity&lt;/li&gt;
&lt;li&gt;Not suitable for production environments&lt;/li&gt;
&lt;li&gt;Incompatible with containerized deployments&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Windows Container
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Using Windows containers instead of Linux containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Windows containers have significantly larger image sizes (gigabytes vs megabytes)&lt;/li&gt;
&lt;li&gt;Limited orchestration platform support&lt;/li&gt;
&lt;li&gt;Higher resource consumption&lt;/li&gt;
&lt;li&gt;Increased licensing costs&lt;/li&gt;
&lt;li&gt;Many cloud platforms prefer or require Linux containers&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: Remote Windows Service
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Running a separate Windows service/API that handles PDF generation.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Added infrastructure complexity&lt;/li&gt;
&lt;li&gt;Network latency for each PDF operation&lt;/li&gt;
&lt;li&gt;Additional points of failure&lt;/li&gt;
&lt;li&gt;Higher operational costs&lt;/li&gt;
&lt;li&gt;Complicates deployment pipelines&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;None of these workarounds provide a production-ready solution for Linux deployments.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Different Approach: IronPDF
&lt;/h2&gt;

&lt;p&gt;For developers who need cross-platform PDF generation, IronPDF provides native support for Windows, Linux, macOS, and Docker environments. The library uses a self-contained Chromium-based rendering engine that ships with the package, eliminating external dependencies.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why IronPDF Works on Linux
&lt;/h3&gt;

&lt;p&gt;IronPDF's architecture differs fundamentally from SelectPdf:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Embedded Rendering Engine&lt;/strong&gt;: IronPDF includes its own Chromium-based renderer, packaged as platform-specific native binaries for each supported OS&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Platform Detection&lt;/strong&gt;: The library automatically loads the correct native components based on the runtime environment&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No System Dependencies&lt;/strong&gt;: Linux deployments require minimal additional packages (standard libraries that most distributions include by default)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Docker-Native Support&lt;/strong&gt;: IronPDF provides tested Docker configurations and base images&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Code Example: HTML to PDF on Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// IronPDF works identically on Windows, Linux, and macOS&lt;/span&gt;
&lt;span class="c1"&gt;// No platform-specific code required&lt;/span&gt;

&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;LinuxPdfGenerator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;GeneratePdfFromHtml&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Configure renderer for Linux environment&lt;/span&gt;
        &lt;span class="c1"&gt;// Note: This configuration works on any platform&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Set rendering options&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;20&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="c1"&gt;// Convert HTML string to PDF&lt;/span&gt;
        &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;html&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;@"
            &amp;lt;html&amp;gt;
            &amp;lt;head&amp;gt;
                &amp;lt;style&amp;gt;
                    body { font-family: Arial, sans-serif; }
                    h1 { color: #333; }
                &amp;lt;/style&amp;gt;
            &amp;lt;/head&amp;gt;
            &amp;lt;body&amp;gt;
                &amp;lt;h1&amp;gt;Generated on Linux&amp;lt;/h1&amp;gt;
                &amp;lt;p&amp;gt;This PDF was created using IronPDF running on a Linux server.&amp;lt;/p&amp;gt;
            &amp;lt;/body&amp;gt;
            &amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;html&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="c1"&gt;// Save to file&lt;/span&gt;
        &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"/app/output/document.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key points about this code:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The code runs identically on Windows, Linux, and macOS&lt;/li&gt;
&lt;li&gt;No platform-specific configuration required&lt;/li&gt;
&lt;li&gt;IronPDF handles native library loading automatically&lt;/li&gt;
&lt;li&gt;Full CSS and JavaScript support via Chromium engine&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Docker Deployment Example
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight docker"&gt;&lt;code&gt;&lt;span class="c"&gt;# Dockerfile for IronPDF on Linux&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt;&lt;span class="s"&gt; mcr.microsoft.com/dotnet/aspnet:8.0&lt;/span&gt;

&lt;span class="c"&gt;# Install minimal dependencies for IronPDF&lt;/span&gt;
&lt;span class="k"&gt;RUN &lt;/span&gt;apt-get update &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; apt-get &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-y&lt;/span&gt; &lt;span class="se"&gt;\
&lt;/span&gt;    libgdiplus &lt;span class="se"&gt;\
&lt;/span&gt;    libc6-dev &lt;span class="se"&gt;\
&lt;/span&gt;    &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;rm&lt;/span&gt; &lt;span class="nt"&gt;-rf&lt;/span&gt; /var/lib/apt/lists/&lt;span class="k"&gt;*&lt;/span&gt;

&lt;span class="k"&gt;WORKDIR&lt;/span&gt;&lt;span class="s"&gt; /app&lt;/span&gt;
&lt;span class="k"&gt;COPY&lt;/span&gt;&lt;span class="s"&gt; --from=build /app/publish .&lt;/span&gt;

&lt;span class="k"&gt;ENTRYPOINT&lt;/span&gt;&lt;span class="s"&gt; ["dotnet", "YourApp.dll"]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// Docker-specific configuration (optional, for optimization)&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;DockerPdfService&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="kt"&gt;byte&lt;/span&gt;&lt;span class="p"&gt;[]&lt;/span&gt; &lt;span class="nf"&gt;ConvertHtmlToPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Enable Docker compatibility mode&lt;/span&gt;
        &lt;span class="n"&gt;Installation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;LinuxAndDockerDependenciesAutoConfig&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure for containerized environment&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;EnableJavaScript&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderDelay&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;500&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="c1"&gt;// Wait for JS execution&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Azure App Service on Linux
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;Microsoft.AspNetCore.Mvc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;ApiController&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;Route&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"api/[controller]"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PdfController&lt;/span&gt; &lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;ControllerBase&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nf"&gt;HttpPost&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"generate"&lt;/span&gt;&lt;span class="p"&gt;)]&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="n"&gt;IActionResult&lt;/span&gt; &lt;span class="nf"&gt;GeneratePdf&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;&lt;span class="n"&gt;FromBody&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Works on Azure App Service Linux without additional configuration&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;File&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;BinaryData&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"application/pdf"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"document.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For complete documentation on Linux deployment:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/how-to/docker-linux/" rel="noopener noreferrer"&gt;Docker and Linux Guide&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/docs/questions/linux/" rel="noopener noreferrer"&gt;Linux Installation&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;p&gt;IronPDF operates under a commercial license model:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Free development and testing with watermark&lt;/li&gt;
&lt;li&gt;Licensed versions for production use&lt;/li&gt;
&lt;li&gt;Perpetual licenses available&lt;/li&gt;
&lt;li&gt;&lt;a href="https://ironpdf.com/licensing/" rel="noopener noreferrer"&gt;Licensing details&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Differences
&lt;/h3&gt;

&lt;p&gt;Migrating from SelectPdf requires code changes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;SelectPdf&lt;/th&gt;
&lt;th&gt;IronPDF&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;HtmlToPdf&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;ChromePdfRenderer&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;PdfDocument&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;PdfDocument&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SelectPdf.Converter.ConvertUrl()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;renderer.RenderUrlAsPdf()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;code&gt;SelectPdf.Converter.ConvertHtmlString()&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;&lt;code&gt;renderer.RenderHtmlAsPdf()&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most migrations involve updating class names and method calls. The conceptual approach remains similar.&lt;/p&gt;

&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Native Linux, macOS, and Windows support&lt;/li&gt;
&lt;li&gt;Docker container compatibility&lt;/li&gt;
&lt;li&gt;Azure App Service Linux deployment&lt;/li&gt;
&lt;li&gt;AWS Lambda support&lt;/li&gt;
&lt;li&gt;Kubernetes deployment capability&lt;/li&gt;
&lt;li&gt;Consistent behavior across platforms&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Commercial license required for production&lt;/li&gt;
&lt;li&gt;Package size is larger than SelectPdf due to embedded Chromium&lt;/li&gt;
&lt;li&gt;Initial render may take slightly longer as Chromium initializes&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;SelectPdf does not support Linux and there is no workaround available. The &lt;code&gt;Unable to load kernel32.dll&lt;/code&gt; error indicates a fundamental platform limitation. Developers requiring PDF generation on Linux environments need to evaluate alternative libraries. IronPDF provides cross-platform support with native Linux compatibility, eliminating platform-related deployment failures.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://ironsoftware.com/about-us/authors/jacobmellor/" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt; originally built IronPDF and leads technical development at Iron Software.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://github.com/selectpdf/selectpdf-free-html-to-pdf-converter/issues/2" rel="noopener noreferrer"&gt;SelectPdf GitHub Issue #2: Linux Support&lt;/a&gt;{:rel="nofollow"} - Original report of Linux incompatibility&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/how-to/docker-linux/" rel="noopener noreferrer"&gt;IronPDF Docker and Linux Documentation&lt;/a&gt; - Official guide for Linux deployment&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/docs/questions/linux/" rel="noopener noreferrer"&gt;IronPDF Linux Installation Guide&lt;/a&gt; - Platform-specific setup instructions&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For the latest IronPDF documentation and tutorials, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
    <item>
      <title>Fixing Memory Growth in PDFTron and Apryse SDK Applications (Fixed)</title>
      <dc:creator>IronSoftware</dc:creator>
      <pubDate>Thu, 02 Apr 2026 11:33:00 +0000</pubDate>
      <link>https://dev.to/ironsoftware/fixing-memory-growth-in-pdftron-and-apryse-sdk-applications-fixed-2elf</link>
      <guid>https://dev.to/ironsoftware/fixing-memory-growth-in-pdftron-and-apryse-sdk-applications-fixed-2elf</guid>
      <description>&lt;p&gt;Developers using PDFTron (now Apryse) SDK frequently encounter a frustrating problem: memory that grows continuously during document processing and never gets released. Applications that work fine with a few documents start crashing with "bad memory allocation" errors when processing batches. Web viewers consume more RAM with each document opened until the browser tab crashes. This article examines why these memory issues occur and explores a different architectural approach that avoids them.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Problem
&lt;/h2&gt;

&lt;p&gt;The PDFTron/Apryse SDK is built on native C++ libraries with wrappers for .NET, Java, Python, Ruby, and JavaScript. This architecture creates a fundamental tension: developers writing in managed languages like C# expect the garbage collector to handle memory cleanup, but the underlying native memory requires explicit disposal calls that the garbage collector cannot manage.&lt;/p&gt;

&lt;p&gt;When a .NET developer creates a &lt;code&gt;PDFDoc&lt;/code&gt; object, calls methods on it, and lets it go out of scope, the managed wrapper gets collected but the native memory often remains allocated. This pattern repeats across &lt;code&gt;PDFDraw&lt;/code&gt;, &lt;code&gt;ElementBuilder&lt;/code&gt;, &lt;code&gt;ElementWriter&lt;/code&gt;, &lt;code&gt;TextExtractor&lt;/code&gt;, and other core classes. In a batch processing scenario where thousands of documents flow through the system, memory accumulates until the process crashes.&lt;/p&gt;

&lt;p&gt;The StreamingPDFConversion API exhibits particularly problematic behavior. This API, designed for converting images and other formats to PDF, has documented memory leaks that persist across multiple SDK versions. Apryse acknowledged in their version 10.11.0 changelog that they "fixed a memory leak that could occur during conversion from TIFF to PDF with Convert.StreamingPDFConversion() or Convert.UniversalConversion()."&lt;/p&gt;

&lt;h3&gt;
  
  
  Error Messages and Symptoms
&lt;/h3&gt;

&lt;p&gt;Developers report various symptoms depending on their platform and use case:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OutOfMemoryException&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;of&lt;/span&gt; &lt;span class="n"&gt;type&lt;/span&gt; &lt;span class="err"&gt;'&lt;/span&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;OutOfMemoryException&lt;/span&gt;&lt;span class="err"&gt;'&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;thrown&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Error code: Out of Memory (browser crash)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;bad allocation errors during PDF to image conversion
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;





&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;System&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IO&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;IOException&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;Stream&lt;/span&gt; &lt;span class="n"&gt;was&lt;/span&gt; &lt;span class="n"&gt;too&lt;/span&gt; &lt;span class="kt"&gt;long&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The WebViewer JavaScript component shows similar patterns. Memory allocated when loading documents does not get released when documents are closed, leading to progressive degradation in browser tab performance.&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Is Affected
&lt;/h2&gt;

&lt;p&gt;This memory growth issue spans the entire Apryse/PDFTron product line:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Operating Systems&lt;/strong&gt;: Windows, Linux, macOS, iOS, Android&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SDK Platforms&lt;/strong&gt;: .NET Framework, .NET Core/.NET 5+, Java, Python, Ruby, Go, PHP, JavaScript/WebViewer&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Affected Versions&lt;/strong&gt;: Reports span from version 5.1.10 (2019) through version 10.1 (2023) and beyond, with some fixes appearing in 10.11.0 (2024) and 11.8.0 (2025)&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Use Cases&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Batch document conversion (converting hundreds or thousands of files)&lt;/li&gt;
&lt;li&gt;Long-running web applications with PDF viewing&lt;/li&gt;
&lt;li&gt;PDF merging operations (combining many documents into one)&lt;/li&gt;
&lt;li&gt;Image to PDF conversion via StreamingPDFConversion&lt;/li&gt;
&lt;li&gt;Mobile applications where users view multiple documents in a session&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The issue is particularly acute in cloud environments like AWS Lambda where memory limits are strict and disk caching may not be available as a workaround.&lt;/p&gt;

&lt;h2&gt;
  
  
  Evidence from the Developer Community
&lt;/h2&gt;

&lt;p&gt;The PDFTron memory leak problem has been reported consistently for over fifteen years across multiple platforms and languages.&lt;/p&gt;

&lt;h3&gt;
  
  
  Timeline
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Date&lt;/th&gt;
&lt;th&gt;Event&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2009-02-01&lt;/td&gt;
&lt;td&gt;First reports of bad allocation errors during batch PDF to image conversion&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://community.apryse.com/t/how-do-i-keep-memory-under-control-during-pdf-to-image-conversion-in-java/871" rel="noopener noreferrer"&gt;Apryse Community&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2019-07-01&lt;/td&gt;
&lt;td&gt;WebViewer memory leak identified in loadScript.js and webviewer-ui.js&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://github.com/PDFTron/webviewer-ui/issues/317" rel="noopener noreferrer"&gt;GitHub Issue #317&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2021-03-01&lt;/td&gt;
&lt;td&gt;iOS PTDocumentController memory leak confirmed by PDFTron on iOS 14&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://groups.google.com/g/pdfnet-sdk/c/ZtqYbAlBzh8" rel="noopener noreferrer"&gt;Google Groups&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-05-01&lt;/td&gt;
&lt;td&gt;React WebViewer memory leak reported&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://community.apryse.com/t/react-pdftron-memory-leak/5713" rel="noopener noreferrer"&gt;Apryse Community&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2022-11-01&lt;/td&gt;
&lt;td&gt;.NET SDK memory leak in Save() method identified&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://community.apryse.com/t/possible-memory-leak-in-pdftron-net-sdk/6999" rel="noopener noreferrer"&gt;Apryse Community&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2023-06-01&lt;/td&gt;
&lt;td&gt;StreamingPDFConversion memory leak confirmed&lt;/td&gt;
&lt;td&gt;
&lt;a href="https://community.apryse.com/t/possible-memory-leak-with-streamingpdfconversion/8035" rel="noopener noreferrer"&gt;Apryse Community&lt;/a&gt;{:rel="nofollow"}&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2024-07-24&lt;/td&gt;
&lt;td&gt;StreamingPDFConversion memory leak fixed in v10.11.0&lt;/td&gt;
&lt;td&gt;Apryse Changelog&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2025-10-08&lt;/td&gt;
&lt;td&gt;Additional memory leaks fixed in v11.8.0&lt;/td&gt;
&lt;td&gt;Apryse Changelog&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Community Reports
&lt;/h3&gt;

&lt;blockquote&gt;
&lt;p&gt;"Ever-growing memory usage with StreamingPDFConversion. Our app was crashing with errors related to bad memory allocation. Memory profiling was done with a simple script and it appeared to potentially be an issue in the SDK."&lt;br&gt;
— Developer report, Apryse Community, June 2023&lt;/p&gt;

&lt;p&gt;"~10mb memory leak each time the PDF viewer was loaded. Rather catastrophic memory leak. In src/helpers/loadScript.js there is a window.addEventListener('message'...) call that isn't properly unsubscribed."&lt;br&gt;
— Developer report, GitHub Issue #317, July 2019&lt;/p&gt;

&lt;p&gt;"Memory continues to grow as they view documents. Overriding viewWillDisappear and manually calling closeDocument seems to help a LOT, but the memory still grows pretty quickly."&lt;br&gt;
— iOS developer, Apryse Community, March 2021&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;A developer attempting to merge 8,000 PDF files reported "memory is exceeding what is available on the system" with "roughly linear correlation in memory usage while merging PDFs." Another developer working with a 175MB document containing 7,600 pages experienced browser crashes with out of memory errors.&lt;/p&gt;

&lt;p&gt;The issue also manifests when converting HTML to PDF. One developer reported that "HTML to PDF conversion fails when trying to create a PDF with over 3000 pages from an HTML string. Even with the timeout set to approximately 3 hours and 20 minutes (1200000ms), the conversion fails after about an hour."&lt;/p&gt;

&lt;h2&gt;
  
  
  Root Cause Analysis: Why PDFTron Memory Leak Occurs
&lt;/h2&gt;

&lt;p&gt;Multiple architectural factors contribute to the persistent memory issues in Apryse/PDFTron:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Native Memory Management&lt;/strong&gt;: The SDK wraps native C++ libraries. In managed languages, developers expect garbage collection to handle cleanup. However, native memory allocated by the C++ layer cannot be freed by the garbage collector. The SDK requires explicit &lt;code&gt;Dispose()&lt;/code&gt; or &lt;code&gt;Close()&lt;/code&gt; calls on most objects, but this is not intuitive for developers accustomed to automatic memory management.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Event Listener Leaks in WebViewer&lt;/strong&gt;: The JavaScript WebViewer component attaches event listeners that are not properly cleaned up when instances are destroyed. The GitHub issue identified specific leaks in &lt;code&gt;window.addEventListener('message'...)&lt;/code&gt; calls and closures over options objects in &lt;code&gt;window.WebViewer.l&lt;/code&gt; and &lt;code&gt;window.WebViewer.workerTransportPromise&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;iOS-Specific Deallocation Issues&lt;/strong&gt;: On iOS 14, Apryse confirmed that &lt;code&gt;PTDocumentController&lt;/code&gt; was not being deallocated when removed from the view hierarchy. This platform-specific bug caused memory to grow with each document viewed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Linear Memory Growth in Batch Operations&lt;/strong&gt;: When processing multiple documents, the SDK does not automatically release memory between operations. Without intermediate saves and explicit disposal, memory grows proportionally with the number of documents processed.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Stream Handling Issues&lt;/strong&gt;: The Save method in the .NET SDK uses unsafe code with &lt;code&gt;TRN_PDFDocSaveMemoryBuffer&lt;/code&gt;. When saving to streams, particularly with large documents, this can trigger &lt;code&gt;Stream was too long&lt;/code&gt; exceptions when the accumulated data exceeds internal limits.&lt;/p&gt;

&lt;h2&gt;
  
  
  Attempted Workarounds for Apryse SDK Memory Issues
&lt;/h2&gt;

&lt;p&gt;The developer community has documented various approaches to mitigate the PDFTron WebViewer memory and SDK memory issues, though none fully resolve the underlying problems.&lt;/p&gt;

&lt;h3&gt;
  
  
  Workaround 1: Explicit Disposal of All Objects
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Wrap every PDFTron object in a &lt;code&gt;using&lt;/code&gt; statement or explicitly call &lt;code&gt;Dispose()&lt;/code&gt; after use.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Apryse/PDFTron pattern requiring explicit disposal&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PDFDoc&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"input.pdf"&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;draw&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PDFDraw&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="n"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetDPI&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;92&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
        &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPageCount&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt; &lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;++)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetPage&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;draw&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Export&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;$"page_&lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;.png"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="c1"&gt;// Must ensure all objects are disposed&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires remembering to dispose every object, including nested ones&lt;/li&gt;
&lt;li&gt;Missing even one disposal in a loop can cause cumulative leaks&lt;/li&gt;
&lt;li&gt;Not intuitive for developers coming from fully managed environments&lt;/li&gt;
&lt;li&gt;Some leaks occur in SDK internals that developers cannot control&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 2: Enable Disk Caching
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Configure the SDK to use disk-based caching instead of keeping everything in memory.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="n"&gt;PDFNet&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SetDefaultDiskCachingEnabled&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Creates temporary files that need cleanup&lt;/li&gt;
&lt;li&gt;Slower than in-memory operations&lt;/li&gt;
&lt;li&gt;Not available in all environments (AWS Lambda, some containerized deployments)&lt;/li&gt;
&lt;li&gt;Does not fix all memory leak sources&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 3: Batch Processing with Intermediate Saves
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Process documents in small batches, saving results and disposing objects between batches.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Process in batches of 100 documents&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Directory&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFiles&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;inputDir&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="s"&gt;"*.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="p"&gt;&amp;lt;&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Length&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt; &lt;span class="n"&gt;batch&lt;/span&gt; &lt;span class="p"&gt;+=&lt;/span&gt; &lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;batchFiles&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;files&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Skip&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batch&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nf"&gt;Take&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="m"&gt;100&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="nf"&gt;ProcessBatch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;batchFiles&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Collect&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;GC&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WaitForPendingFinalizers&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Significantly more complex code&lt;/li&gt;
&lt;li&gt;Slower overall processing&lt;/li&gt;
&lt;li&gt;Requires managing intermediate files&lt;/li&gt;
&lt;li&gt;Still may not prevent all memory growth within each batch&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Workaround 4: WebViewer Instance Reuse
&lt;/h3&gt;

&lt;p&gt;&lt;strong&gt;Approach&lt;/strong&gt;: Instead of creating new WebViewer instances, reuse existing ones by loading new documents into them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Limitations&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Requires architectural changes to the application&lt;/li&gt;
&lt;li&gt;May not fit all use cases&lt;/li&gt;
&lt;li&gt;Still shows memory growth over time, just slower&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  A Different Approach: IronPDF
&lt;/h2&gt;

&lt;p&gt;For developers who have exhausted workaround options or cannot afford the complexity of managing native memory manually, switching to a library with a different architecture may be the practical solution.&lt;/p&gt;

&lt;p&gt;IronPDF uses an embedded Chromium rendering engine that operates within the managed .NET environment. The library implements the standard &lt;code&gt;IDisposable&lt;/code&gt; pattern, and its memory management integrates with .NET's garbage collection in a way that does not require developers to manually track and dispose every internal object.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why IronPDF Handles Memory Differently
&lt;/h3&gt;

&lt;p&gt;The architectural difference is fundamental. Rather than wrapping a native C++ library, IronPDF renders documents using Chromium processes that are managed by the library. When a document operation completes and objects go out of scope, the memory can be reclaimed through normal .NET garbage collection.&lt;/p&gt;

&lt;p&gt;For batch operations, IronPDF does not exhibit the linear memory growth pattern seen with PDFTron. Each document is processed, resources are released, and the next document starts from a clean state.&lt;/p&gt;

&lt;h3&gt;
  
  
  Code Example
&lt;/h3&gt;

&lt;p&gt;The following example demonstrates batch HTML-to-PDF conversion with proper resource handling:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.IO&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// Demonstrates batch PDF generation without memory accumulation.&lt;/span&gt;
&lt;span class="c1"&gt;/// Each document is processed independently with automatic resource cleanup.&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;BatchPdfGenerator&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;ConvertHtmlFilesToPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;htmlFilePaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;outputDirectory&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// ChromePdfRenderer implements IDisposable and manages its own lifecycle&lt;/span&gt;
        &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="c1"&gt;// Configure rendering options once&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PaperSize&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Rendering&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;PdfPaperSize&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;A4&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginTop&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
        &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;RenderingOptions&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;MarginBottom&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;25&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="kt"&gt;int&lt;/span&gt; &lt;span class="n"&gt;processedCount&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

        &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlPath&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;htmlFilePaths&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="k"&gt;try&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="c1"&gt;// Read HTML content&lt;/span&gt;
                &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;htmlContent&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;File&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ReadAllText&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Render to PDF - memory is managed automatically&lt;/span&gt;
                &lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Generate output filename&lt;/span&gt;
                &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Combine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
                    &lt;span class="n"&gt;outputDirectory&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
                    &lt;span class="n"&gt;Path&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;GetFileNameWithoutExtension&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;htmlPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;+&lt;/span&gt; &lt;span class="s"&gt;".pdf"&lt;/span&gt;
                &lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="c1"&gt;// Save to disk&lt;/span&gt;
                &lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

                &lt;span class="n"&gt;processedCount&lt;/span&gt;&lt;span class="p"&gt;++;&lt;/span&gt;

                &lt;span class="c1"&gt;// No manual memory cleanup required between documents&lt;/span&gt;
                &lt;span class="c1"&gt;// The 'using' statement ensures proper disposal&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
            &lt;span class="k"&gt;catch&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Exception&lt;/span&gt; &lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Error processing &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;htmlPath&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;: &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;ex&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;Message&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;

        &lt;span class="n"&gt;Console&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteLine&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;$"Processed &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="n"&gt;processedCount&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s"&gt; documents."&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For merging multiple documents, IronPDF provides a straightforward approach that does not accumulate memory linearly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;IronPdf&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Collections.Generic&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="nn"&gt;System.Linq&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;/// &amp;lt;summary&amp;gt;&lt;/span&gt;
&lt;span class="c1"&gt;/// Merges multiple PDF files without the linear memory growth&lt;/span&gt;
&lt;span class="c1"&gt;/// seen when merging large numbers of documents with some libraries.&lt;/span&gt;
&lt;span class="c1"&gt;/// &amp;lt;/summary&amp;gt;&lt;/span&gt;
&lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;class&lt;/span&gt; &lt;span class="nc"&gt;PdfMerger&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;public&lt;/span&gt; &lt;span class="k"&gt;void&lt;/span&gt; &lt;span class="nf"&gt;MergeDocuments&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;IEnumerable&lt;/span&gt;&lt;span class="p"&gt;&amp;lt;&lt;/span&gt;&lt;span class="kt"&gt;string&lt;/span&gt;&lt;span class="p"&gt;&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;pdfPaths&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="kt"&gt;string&lt;/span&gt; &lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;{&lt;/span&gt;
        &lt;span class="c1"&gt;// Load all PDFs - IronPDF handles memory efficiently&lt;/span&gt;
        &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;pdfPaths&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Select&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt; &lt;span class="p"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="n"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;FromFile&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;path&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
            &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;ToList&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

        &lt;span class="k"&gt;try&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Merge all documents&lt;/span&gt;
            &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;merged&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;PdfDocument&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Merge&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Save the result&lt;/span&gt;
            &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;outputPath&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

            &lt;span class="c1"&gt;// Dispose the merged document&lt;/span&gt;
            &lt;span class="n"&gt;merged&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="k"&gt;finally&lt;/span&gt;
        &lt;span class="p"&gt;{&lt;/span&gt;
            &lt;span class="c1"&gt;// Clean up source documents&lt;/span&gt;
            &lt;span class="k"&gt;foreach&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="k"&gt;in&lt;/span&gt; &lt;span class="n"&gt;documents&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
            &lt;span class="p"&gt;{&lt;/span&gt;
                &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Dispose&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
            &lt;span class="p"&gt;}&lt;/span&gt;
        &lt;span class="p"&gt;}&lt;/span&gt;
    &lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Key differences in this code&lt;/strong&gt;:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Standard &lt;code&gt;IDisposable&lt;/code&gt; pattern works as expected&lt;/li&gt;
&lt;li&gt;No native memory leaks from missed disposal calls&lt;/li&gt;
&lt;li&gt;Memory does not grow linearly during batch processing&lt;/li&gt;
&lt;li&gt;No need for explicit GC calls or batch processing workarounds&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  API Reference
&lt;/h3&gt;

&lt;p&gt;For detailed documentation on the classes and methods used:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/object-reference/api/IronPdf.ChromePdfRenderer.html" rel="noopener noreferrer"&gt;ChromePdfRenderer&lt;/a&gt; - HTML and URL to PDF conversion&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/how-to/merge-or-split-pdfs/" rel="noopener noreferrer"&gt;Merge or Split PDFs&lt;/a&gt; - Combining multiple documents&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://ironpdf.com/tutorials/html-to-pdf/" rel="noopener noreferrer"&gt;HTML to PDF Tutorial&lt;/a&gt; - Complete guide to HTML conversion&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Considerations
&lt;/h2&gt;

&lt;p&gt;Switching PDF libraries is not a trivial decision. Developers should evaluate several factors.&lt;/p&gt;

&lt;h3&gt;
  
  
  Licensing
&lt;/h3&gt;

&lt;p&gt;IronPDF is commercial software. Licenses are available per-developer and include free trial periods for evaluation. Pricing information is available on the &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;IronPDF website&lt;/a&gt;. For teams currently using Apryse's commercial license, the cost comparison may be straightforward. For those using PDFTron's legacy free tier (if applicable to their use case), there is a licensing cost to consider.&lt;/p&gt;

&lt;h3&gt;
  
  
  API Differences
&lt;/h3&gt;

&lt;p&gt;The APIs differ significantly. PDFTron uses a lower-level API with explicit element builders and writers. IronPDF uses a higher-level API centered on the &lt;code&gt;ChromePdfRenderer&lt;/code&gt; and &lt;code&gt;PdfDocument&lt;/code&gt; classes. Migration requires rewriting document generation code, not just swapping class names.&lt;/p&gt;

&lt;p&gt;Example comparison:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight csharp"&gt;&lt;code&gt;&lt;span class="c1"&gt;// PDFTron approach&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;PDFDoc&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;eb&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ElementBuilder&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="k"&gt;using&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;ew&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ElementWriter&lt;/span&gt;&lt;span class="p"&gt;())&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;doc&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;PageCreate&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
    &lt;span class="n"&gt;ew&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;Begin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;element&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;eb&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;CreateTextBegin&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;font&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="m"&gt;12&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="n"&gt;ew&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;WriteElement&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;element&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="c1"&gt;// ... many more low-level operations&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// IronPDF approach&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nf"&gt;ChromePdfRenderer&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="kt"&gt;var&lt;/span&gt; &lt;span class="n"&gt;pdf&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="n"&gt;renderer&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;RenderHtmlAsPdf&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"&amp;lt;html&amp;gt;&amp;lt;body&amp;gt;Content&amp;lt;/body&amp;gt;&amp;lt;/html&amp;gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;pdf&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;SaveAs&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;"output.pdf"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  What You Gain
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Standard .NET memory management without native memory quirks&lt;/li&gt;
&lt;li&gt;No need for explicit disposal of every internal object&lt;/li&gt;
&lt;li&gt;Batch processing without linear memory growth&lt;/li&gt;
&lt;li&gt;Chrome-based rendering for accurate HTML/CSS support&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  What to Consider
&lt;/h3&gt;

&lt;ul&gt;
&lt;li&gt;Learning curve for a new API&lt;/li&gt;
&lt;li&gt;Testing required to verify output matches expectations&lt;/li&gt;
&lt;li&gt;IronPDF uses Chromium, which has its own resource footprint&lt;/li&gt;
&lt;li&gt;Some advanced PDFTron features may not have direct equivalents&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Conclusion
&lt;/h2&gt;

&lt;p&gt;The PDFTron/Apryse memory leak issue stems from fundamental architectural decisions around native memory management. While workarounds exist, they add complexity and do not fully solve the problem. For development teams spending significant time debugging memory issues in production, evaluating an alternative library with managed memory handling may be more cost-effective than continuing to work around SDK limitations.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://github.com/jacob-mellor" rel="noopener noreferrer"&gt;Jacob Mellor&lt;/a&gt; is CTO at Iron Software, where he leads technical development and built the original IronPDF library. He has over 25 years of experience developing commercial software tools.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  References
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;a href="https://community.apryse.com/t/possible-memory-leak-with-streamingpdfconversion/8035" rel="noopener noreferrer"&gt;Possible memory leak with StreamingPDFConversion&lt;/a&gt;{:rel="nofollow"} - Apryse Community forum thread documenting streaming conversion memory issues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://community.apryse.com/t/possible-memory-leak-in-pdftron-net-sdk/6999" rel="noopener noreferrer"&gt;Possible memory leak in PDFTron .NET SDK&lt;/a&gt;{:rel="nofollow"} - .NET SDK memory leak investigation&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://github.com/PDFTron/webviewer-ui/issues/317" rel="noopener noreferrer"&gt;WebViewer Memory Leaks - GitHub Issue #317&lt;/a&gt;{:rel="nofollow"} - Detailed analysis of JavaScript memory leaks&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://community.apryse.com/t/react-pdftron-memory-leak/5713" rel="noopener noreferrer"&gt;React: PDFTron Memory Leak&lt;/a&gt;{:rel="nofollow"} - WebViewer memory issues in React applications&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://community.apryse.com/t/possible-memory-leak/3769" rel="noopener noreferrer"&gt;Possible memory leak - iOS&lt;/a&gt;{:rel="nofollow"} - iOS-specific memory growth issues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://community.apryse.com/t/pdftron-webviewer-out-of-memory-large-pdf-file-70mb/6655" rel="noopener noreferrer"&gt;PDFTron WebViewer Out of Memory&lt;/a&gt;{:rel="nofollow"} - Large file handling crashes&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://community.pdftron.com/t/running-out-of-memory-when-merging-8000-pdf-files-into-one/5474" rel="noopener noreferrer"&gt;Running out of memory when merging PDFs&lt;/a&gt;{:rel="nofollow"} - Batch merging memory issues&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://groups.google.com/g/pdfnet-sdk/c/ZtqYbAlBzh8" rel="noopener noreferrer"&gt;Memory Management - Google Groups&lt;/a&gt;{:rel="nofollow"} - iOS PTDocumentController deallocation issue&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://community.apryse.com/t/how-do-i-keep-memory-under-control-during-pdf-to-image-conversion-in-java/871" rel="noopener noreferrer"&gt;How to keep memory under control - Java&lt;/a&gt;{:rel="nofollow"} - Early reports of batch processing issues&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;em&gt;For the latest IronPDF documentation and tutorials, visit &lt;a href="https://ironpdf.com" rel="noopener noreferrer"&gt;ironpdf.com&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>csharp</category>
      <category>dotnet</category>
    </item>
  </channel>
</rss>
