How to Migrate from MuPDF to IronPDF in C#
Why Migrate from MuPDF to IronPDF
The MuPDF Challenges
MuPDF is a capable PDF toolkit, but its dual AGPL/commercial license (from Artifex) and rendering-first design create real friction for .NET developers building commercial HTML-driven applications. Two main .NET wrappers exist: MuPDFCore (community, by arklumpus, AGPL-3.0) and MuPDF.NET (Artifex's official C# bindings, mirroring PyMuPDF).
-
AGPL License Trap: Both MuPDF and the wrappers ship under AGPL-3.0 by default. Distributing a closed-source product on AGPL code requires either open-sourcing under AGPL or purchasing a commercial license from Artifex (pricing is quote-based, not published).
-
Rendering-First Focus: While MuPDF.NET can merge, redact, sign, and stamp watermarks (mirroring PyMuPDF), most of the API and tooling is shaped around viewing and structured-text extraction rather than HTML-driven document generation.
-
No HTML-to-PDF Engine: Neither MuPDF.NET nor MuPDFCore ships an HTML/CSS engine. Generating PDFs from HTML requires shelling out to a separate browser engine (Chromium, wkhtmltopdf, PrinceXML) and only loading the result with MuPDF.
-
Native Dependencies: Both wrappers ship
MuPDFCore.NativeAssets/MuPDF.NativeAssetspackages with per-RID binaries (win-x64, linux-x64, osx-x64). Cross-platform deployment works, but Docker images need the matching native package and base image (glibc vs musl). -
No HTML Watermarks / Headers / Footers: Stamping is image- and text-based per page; there is no
{page}/{total-pages}template engine the way Chromium-based renderers expose. - C Interop Surface: Wrappers expose context/document lifetimes that map onto the underlying C library — disposal order matters, native crashes can take down the whole process, and marshalling cost is non-trivial for large documents.
MuPDF vs IronPDF Comparison
| Feature | MuPDF | IronPDF |
|---|---|---|
| License | AGPL-3.0 or quote-based commercial (Artifex) | Commercial with published pricing |
| Primary Focus | Rendering, structured text, low-level toolkit | HTML-driven generation + manipulation |
| HTML to PDF | Not supported (no HTML engine) | Full Chromium engine |
| PDF Creation | Page-level only (insert text/images/vectors) | HTML, URL, images |
| PDF Manipulation | Supported in MuPDF.NET (InsertPdf, Select, DeletePage) |
Supported (Merge, CopyPages, RemovePages) |
| Dependencies | Native MuPDF + RID NativeAssets | Managed wrapper + bundled Chromium |
| Platform Support | Win/Linux/macOS via NativeAssets | Win/Linux/macOS/Docker |
| Async Support | Mostly synchronous; some async in MuPDFCore | Async APIs across renderer and document |
| .NET Integration | P/Invoke wrappers around C library | .NET wrapper + native Chromium |
IronPDF runs as a managed .NET library across modern .NET versions without native interop complexity.
Migration Complexity Assessment
Estimated Effort by Feature
| Feature | Migration Complexity |
|---|---|
| Document Loading | Very Low |
| Text Extraction | Very Low |
| PDF Merging | Low |
| Image Rendering | Low |
| HTML to PDF | N/A (New Capability) |
| Security/Watermarks | N/A (New Capability) |
Paradigm Shift
The fundamental shift in this MuPDF migration is from rendering-only viewer to complete PDF solution:
MuPDF.NET: Document → doc[i] → GetText / GetPixmap / InsertPdf
MuPDFCore: MuPDFContext → MuPDFDocument → Pages[i] → Render / SaveImage
IronPDF: PdfDocument.FromFile() → Full manipulation → Create/Edit/Merge/Secure
Before You Start
Prerequisites
- .NET Environment: .NET Framework 4.6.2+ or .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet Access: Ability to install NuGet packages
- IronPDF License: Obtain your license key from ironpdf.com
NuGet Package Changes
# Remove MuPDF packages (whichever wrapper you used)
dotnet remove package MuPDF.NET
dotnet remove package MuPDFCore
dotnet remove package MuPDFCore.NativeAssets.Linux
dotnet remove package MuPDFCore.NativeAssets.MacOS
dotnet remove package MuPDFCore.NativeAssets.Windows
dotnet remove package MuPDF.NativeAssets
# Install IronPDF
dotnet add package IronPdf
# Remove MuPDF packages (whichever wrapper you used)
dotnet remove package MuPDF.NET
dotnet remove package MuPDFCore
dotnet remove package MuPDFCore.NativeAssets.Linux
dotnet remove package MuPDFCore.NativeAssets.MacOS
dotnet remove package MuPDFCore.NativeAssets.Windows
dotnet remove package MuPDF.NativeAssets
# Install IronPDF
dotnet add package IronPdf
Also remove native MuPDF binaries from your deployment:
- Delete
mupdf.dll,libmupdf.so,libmupdf.dylib - Remove platform-specific folders (
runtimes/*/native/) - Update Docker files to remove MuPDF installation
License Configuration
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup (Program.cs or Startup.cs)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup (Program.vb or Startup.vb)
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
Identify MuPDF Usage
# Find all MuPDF references
grep -r "MuPDF\|MuPDFCore\|MuPDFDocument" --include="*.cs" .
# Find all MuPDF references
grep -r "MuPDF\|MuPDFCore\|MuPDFDocument" --include="*.cs" .
Complete API Reference
Document Loading
| MuPDF | IronPDF |
|---|---|
new Document(path) (MuPDF.NET) / new MuPDFDocument(ctx, path) (MuPDFCore) |
PdfDocument.FromFile(path) |
new Document("pdf", stream) (MuPDF.NET) |
PdfDocument.FromStream(stream) |
doc.Close() / Dispose() |
pdf.Dispose() |
Page Access
| MuPDF | IronPDF |
|---|---|
doc.PageCount (MuPDF.NET) / document.Pages.Count (MuPDFCore) |
pdf.PageCount |
doc[index] (MuPDF.NET) / document.Pages[index] (MuPDFCore) |
pdf.Pages[index] |
doc[i].GetText() / structured-text iteration (MuPDFCore) |
page.Text |
Text Extraction
| MuPDF | IronPDF |
|---|---|
Loop over doc[i].GetText() |
pdf.ExtractAllText() |
PDF Creation (Not Available in MuPDF)
| MuPDF | IronPDF |
|---|---|
| (no HTML engine) | ChromePdfRenderer.RenderHtmlAsPdf(html) |
| (no HTML engine) | ChromePdfRenderer.RenderUrlAsPdf(url) |
PDF Manipulation
| MuPDF | IronPDF |
|---|---|
docA.InsertPdf(docB) (MuPDF.NET) |
PdfDocument.Merge(pdf1, pdf2) |
page.InsertImage(...) per page (image/text stamps only) |
pdf.ApplyWatermark(html) |
doc.Save(path, encryption: ..., ownerPw: ..., userPw: ...) |
pdf.SecuritySettings |
Code Migration Examples
Example 1: HTML to PDF Conversion (MuPDF Cannot Do This)
Before (MuPDF):
// NuGet: Install-Package MuPDF.NET
using MuPDFCore;
using System.IO;
class Program
{
static void Main()
{
// MuPDF doesn't support HTML to PDF conversion directly
// You would need to use another library to convert HTML to a supported format first
// This is a limitation - MuPDF is primarily a PDF renderer/viewer
// Alternative: Use a browser engine or intermediate conversion
string html = "<html><body><h1>Hello World</h1></body></html>";
// Not natively supported in MuPDF
throw new NotSupportedException("MuPDF does not support direct HTML to PDF conversion");
}
}
// NuGet: Install-Package MuPDF.NET
using MuPDFCore;
using System.IO;
class Program
{
static void Main()
{
// MuPDF doesn't support HTML to PDF conversion directly
// You would need to use another library to convert HTML to a supported format first
// This is a limitation - MuPDF is primarily a PDF renderer/viewer
// Alternative: Use a browser engine or intermediate conversion
string html = "<html><body><h1>Hello World</h1></body></html>";
// Not natively supported in MuPDF
throw new NotSupportedException("MuPDF does not support direct HTML to PDF conversion");
}
}
Imports MuPDFCore
Imports System.IO
Class Program
Shared Sub Main()
' MuPDF doesn't support HTML to PDF conversion directly
' You would need to use another library to convert HTML to a supported format first
' This is a limitation - MuPDF is primarily a PDF renderer/viewer
' Alternative: Use a browser engine or intermediate conversion
Dim html As String = "<html><body><h1>Hello World</h1></body></html>"
' Not natively supported in MuPDF
Throw New NotSupportedException("MuPDF does not support direct HTML to PDF conversion")
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Hello World</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Hello World</h1></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
Dim renderer = New ChromePdfRenderer()
Dim html As String = "<html><body><h1>Hello World</h1></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Sub
End Class
This example highlights MuPDF's most significant limitation: it cannot convert HTML to PDF at all. The MuPDF code explicitly throws NotSupportedException because HTML-to-PDF conversion is simply not a capability MuPDF provides. If you needed this functionality with MuPDF, you had to use a separate library like wkhtmltopdf or a browser engine, then load the resulting PDF with MuPDF for viewing.
IronPDF's ChromePdfRenderer uses a full Chromium engine to render HTML with complete CSS3, JavaScript, and modern web standards support. The RenderHtmlAsPdf() method accepts HTML strings directly. See the HTML to PDF documentation for additional rendering options including URL rendering and HTML file conversion.
Example 2: Text Extraction
Before (MuPDF):
// NuGet: Install-Package MuPDF.NET
using MuPDF.NET;
using System;
using System.Text;
class Program
{
static void Main()
{
Document doc = new Document("input.pdf");
StringBuilder allText = new StringBuilder();
for (int i = 0; i < doc.PageCount; i++)
{
string pageText = doc[i].GetText();
allText.AppendLine(pageText);
}
Console.WriteLine(allText.ToString());
}
}
// NuGet: Install-Package MuPDF.NET
using MuPDF.NET;
using System;
using System.Text;
class Program
{
static void Main()
{
Document doc = new Document("input.pdf");
StringBuilder allText = new StringBuilder();
for (int i = 0; i < doc.PageCount; i++)
{
string pageText = doc[i].GetText();
allText.AppendLine(pageText);
}
Console.WriteLine(allText.ToString());
}
}
Imports MuPDF.NET
Imports System
Imports System.Text
Module Program
Sub Main()
Dim doc As New Document("input.pdf")
Dim allText As New StringBuilder()
For i As Integer = 0 To doc.PageCount - 1
Dim pageText As String = doc(i).GetText()
allText.AppendLine(pageText)
Next
Console.WriteLine(allText.ToString())
End Sub
End Module
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var pdf = PdfDocument.FromFile("input.pdf");
string text = pdf.ExtractAllText();
Console.WriteLine(text);
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using System;
class Program
{
static void Main()
{
var pdf = PdfDocument.FromFile("input.pdf");
string text = pdf.ExtractAllText();
Console.WriteLine(text);
}
}
Imports IronPdf
Imports System
Class Program
Shared Sub Main()
Dim pdf = PdfDocument.FromFile("input.pdf")
Dim text As String = pdf.ExtractAllText()
Console.WriteLine(text)
End Sub
End Class
The MuPDF.NET approach opens a Document, iterates doc.PageCount with a for loop, calls doc[i].GetText() for each page, and builds up the text with a StringBuilder.
IronPDF reduces this to three lines: load the document with PdfDocument.FromFile(), call ExtractAllText(), and print the result. No manual iteration, no StringBuilder. Learn more about text extraction from PDFs.
Example 3: Merging Multiple PDFs
Before (MuPDF):
// NuGet: Install-Package MuPDF.NET
using MuPDF.NET;
class Program
{
static void Main()
{
Document doc1 = new Document("file1.pdf");
Document doc2 = new Document("file2.pdf");
// Append every page of doc2 to the end of doc1.
doc1.InsertPdf(doc2);
doc1.Save("merged.pdf");
}
}
// NuGet: Install-Package MuPDF.NET
using MuPDF.NET;
class Program
{
static void Main()
{
Document doc1 = new Document("file1.pdf");
Document doc2 = new Document("file2.pdf");
// Append every page of doc2 to the end of doc1.
doc1.InsertPdf(doc2);
doc1.Save("merged.pdf");
}
}
Imports MuPDF.NET
Class Program
Shared Sub Main()
Dim doc1 As New Document("file1.pdf")
Dim doc2 As New Document("file2.pdf")
' Append every page of doc2 to the end of doc1.
doc1.InsertPdf(doc2)
doc1.Save("merged.pdf")
End Sub
End Class
After (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var pdf1 = PdfDocument.FromFile("file1.pdf");
var pdf2 = PdfDocument.FromFile("file2.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
var pdf1 = PdfDocument.FromFile("file1.pdf");
var pdf2 = PdfDocument.FromFile("file2.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
Dim pdf1 = PdfDocument.FromFile("file1.pdf")
Dim pdf2 = PdfDocument.FromFile("file2.pdf")
Dim merged = PdfDocument.Merge(pdf1, pdf2)
merged.SaveAs("merged.pdf")
End Sub
End Class
MuPDF.NET supports merging via Document.InsertPdf, which mirrors PyMuPDF's insert_pdf() and appends every page of one document to another in place. MuPDFCore does not expose an equivalent high-level merge API.
IronPDF's static PdfDocument.Merge() method accepts multiple PDF documents and returns a single merged document, leaving the inputs untouched. For merging many documents, pass a list: PdfDocument.Merge(pdfList). See the merge and split PDFs documentation for additional options.
Critical Migration Notes
Remove Native Binaries
MuPDF requires platform-specific native libraries. After migrating to IronPDF, remove all MuPDF native binaries:
# Delete native libraries
rm -f mupdf*.dll libmupdf*.so libmupdf*.dylib
# Remove runtime folders
rm -rf runtimes/*/native/
# Update Docker files to remove MuPDF installation
# Delete native libraries
rm -f mupdf*.dll libmupdf*.so libmupdf*.dylib
# Remove runtime folders
rm -rf runtimes/*/native/
# Update Docker files to remove MuPDF installation
IronPDF is fully managed .NET code—no native binaries to manage across platforms.
Dispose Pattern Simplified
MuPDFCore requires an explicit MuPDFContext; MuPDF.NET hides it but still needs Close() / Dispose():
// MuPDFCore: explicit context required
using (var context = new MuPDFContext())
using (var document = new MuPDFDocument(context, "input.pdf"))
{
// Work with document
}
// MuPDF.NET: implicit context, manual close
Document doc = new Document("input.pdf");
try { /* work */ } finally { doc.Close(); }
// IronPDF: simpler pattern
var pdf = PdfDocument.FromFile("input.pdf");
// Work with pdf
// MuPDFCore: explicit context required
using (var context = new MuPDFContext())
using (var document = new MuPDFDocument(context, "input.pdf"))
{
// Work with document
}
// MuPDF.NET: implicit context, manual close
Document doc = new Document("input.pdf");
try { /* work */ } finally { doc.Close(); }
// IronPDF: simpler pattern
var pdf = PdfDocument.FromFile("input.pdf");
// Work with pdf
Imports MuPDFCore
Imports MuPDF.NET
Imports IronPDF
' MuPDFCore: explicit context required
Using context As New MuPDFContext()
Using document As New MuPDFDocument(context, "input.pdf")
' Work with document
End Using
End Using
' MuPDF.NET: implicit context, manual close
Dim doc As New Document("input.pdf")
Try
' work
Finally
doc.Close()
End Try
' IronPDF: simpler pattern
Dim pdf = PdfDocument.FromFile("input.pdf")
' Work with pdf
Page Iteration Pattern Change
MuPDF uses index-based iteration with explicit page count:
// MuPDF.NET
for (int i = 0; i < doc.PageCount; i++)
{
var pageText = doc[i].GetText();
}
// MuPDFCore
for (int i = 0; i < document.Pages.Count; i++)
{
var pageText = document.Pages[i].GetText();
}
// IronPDF (foreach supported)
foreach (var page in pdf.Pages)
{
var pageText = page.Text;
}
// MuPDF.NET
for (int i = 0; i < doc.PageCount; i++)
{
var pageText = doc[i].GetText();
}
// MuPDFCore
for (int i = 0; i < document.Pages.Count; i++)
{
var pageText = document.Pages[i].GetText();
}
// IronPDF (foreach supported)
foreach (var page in pdf.Pages)
{
var pageText = page.Text;
}
' MuPDF.NET
For i As Integer = 0 To doc.PageCount - 1
Dim pageText = doc(i).GetText()
Next
' MuPDFCore
For i As Integer = 0 To document.Pages.Count - 1
Dim pageText = document.Pages(i).GetText()
Next
' IronPDF (foreach supported)
For Each page In pdf.Pages
Dim pageText = page.Text
Next
New Capabilities Available
After migrating to IronPDF, you gain capabilities that MuPDF cannot provide:
// PDF Creation from HTML (not possible in MuPDF)
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello</h1>");
// Watermarks (not possible in MuPDF)
pdf.ApplyWatermark("<div style='color:red;opacity:0.3;'>DRAFT</div>");
// Password Protection (not possible in MuPDF)
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "user";
// Headers and Footers (no HTML header/footer template in MuPDF)
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:center;'>Document Title</div>",
MaxHeight = 25
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:center;'>Page {page} of {total-pages}</div>",
MaxHeight = 25
};
// PDF Creation from HTML (not possible in MuPDF)
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello</h1>");
// Watermarks (not possible in MuPDF)
pdf.ApplyWatermark("<div style='color:red;opacity:0.3;'>DRAFT</div>");
// Password Protection (not possible in MuPDF)
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "user";
// Headers and Footers (no HTML header/footer template in MuPDF)
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:center;'>Document Title</div>",
MaxHeight = 25
};
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = "<div style='text-align:center;'>Page {page} of {total-pages}</div>",
MaxHeight = 25
};
Troubleshooting
Issue 1: MuPDFDocument Not Found
Problem: MuPDFDocument class doesn't exist in IronPDF.
Solution: Use PdfDocument.FromFile():
// MuPDF
using (MuPDFDocument document = new MuPDFDocument("input.pdf"))
// IronPDF
var pdf = PdfDocument.FromFile("input.pdf");
// MuPDF
using (MuPDFDocument document = new MuPDFDocument("input.pdf"))
// IronPDF
var pdf = PdfDocument.FromFile("input.pdf");
Imports MuPDF
Imports IronPDF
Using document As New MuPDFDocument("input.pdf")
End Using
Dim pdf = PdfDocument.FromFile("input.pdf")
Issue 2: Pages.Count Not Found
Problem: document.Pages.Count pattern doesn't work.
Solution: Use pdf.PageCount:
// MuPDF
for (int i = 0; i < document.Pages.Count; i++)
// IronPDF
for (int i = 0; i < pdf.PageCount; i++)
// Or use: foreach (var page in pdf.Pages)
// MuPDF
for (int i = 0; i < document.Pages.Count; i++)
// IronPDF
for (int i = 0; i < pdf.PageCount; i++)
// Or use: foreach (var page in pdf.Pages)
' MuPDF
For i As Integer = 0 To document.Pages.Count - 1
' IronPDF
For i As Integer = 0 To pdf.PageCount - 1
' Or use: For Each page In pdf.Pages
Issue 3: GetText() Not Found
Problem: page.GetText() method doesn't exist.
Solution: Use page.Text property or pdf.ExtractAllText():
// MuPDF
string pageText = document.Pages[i].GetText();
// IronPDF
string pageText = pdf.Pages[i].Text;
// Or for all text:
string allText = pdf.ExtractAllText();
// MuPDF
string pageText = document.Pages[i].GetText();
// IronPDF
string pageText = pdf.Pages[i].Text;
// Or for all text:
string allText = pdf.ExtractAllText();
' MuPDF
Dim pageText As String = document.Pages(i).GetText()
' IronPDF
Dim pageText As String = pdf.Pages(i).Text
' Or for all text:
Dim allText As String = pdf.ExtractAllText()
Issue 4: InsertPdf Not Found
Problem: MuPDF.NET's Document.InsertPdf (mirrors PyMuPDF's insert_pdf) has no direct equivalent name in IronPDF, and MuPDFCore exposes no high-level merge at all.
Solution: Use static PdfDocument.Merge():
// MuPDF.NET
docA.InsertPdf(docB);
// IronPDF
var merged = PdfDocument.Merge(pdf1, pdf2);
// MuPDF.NET
docA.InsertPdf(docB);
// IronPDF
var merged = PdfDocument.Merge(pdf1, pdf2);
Migration Checklist
Pre-Migration
- Inventory all MuPDF usages in codebase
- Document all rendering operations (DPI, scale factors)
- Identify any PDF creation needs (currently using external tools)
- List text extraction requirements
- Review deployment scripts for native binary handling
- Obtain IronPDF license key
Package Changes
- Remove
MuPDF.NETpackage - Remove
MuPDFCorepackage - Remove
MuPDFCore.NativeAssets.*/MuPDF.NativeAssetspackages - Install
IronPdfNuGet package:dotnet add package IronPdf - Update namespace imports
Code Changes
- Add license key configuration at startup
- Replace
Document(MuPDF.NET) /MuPDFDocument(MuPDFCore) withPdfDocument.FromFile() - Replace
doc.PageCount/document.Pages.Countwithpdf.PageCount - Replace
doc[i].GetText()withpage.Textorpdf.ExtractAllText() - Replace
Document.InsertPdfcalls withPdfDocument.Merge() - Remove explicit context/dispose boilerplate
- Add PDF creation code if needed (HTML to PDF)
Post-Migration
- Remove native MuPDF binaries from project
- Update Docker files to remove MuPDF installation
- Remove platform-specific runtime folders
- Run regression tests comparing rendered output
- Test on all target platforms (Windows, Linux, macOS)
- Consider adding new capabilities (watermarks, security, headers/footers)

