Auswahl der besten C#-Bibliothek für die Dokumentenerstellung im Jahr 2026
Die Auswahl einer C#-PDF-Bibliothek wirkt sich auf die Lizenzierung Ihres Projekts, die Flexibilität bei der Bereitstellung und die langfristigen Wartungskosten aus. Die meisten Bibliotheken, die während der Evaluierung geeignet erscheinen, zeigen in der Produktion Einschränkungen - AGPL-Anforderungen, die Sie nicht erwartet haben, HTML-Rendering, das nicht zu Ihrem Browser passt, oder Speicherlecks, die nur unter Linux auftreten.
Dieser Artikel vergleicht die wichtigsten Optionen mit Codebeispielen, dokumentiert die Kompromisse, die in der Praxis von Bedeutung sind, und enthält einen Seite-an-Seite-Codevergleich, der dieselbe Rechnung in drei verschiedenen Bibliotheken generiert, damit Sie die API-Unterschiede direkt sehen können.
Schnellstart: HTML zu PDF in drei Zeilen
Installation über NuGet:
Installations-Paket IronPDF
Erzeugen Sie ein PDF:
using IronPdf;
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>");
pdf.SaveAs("output.pdf");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1>")
pdf.SaveAs("output.pdf")
Dies funktioniert unter Windows, Linux, macOS und Docker ohne zusätzliche Konfiguration. Die Ausgabe stimmt mit Chrome überein, daIronPDFdieselbe Chromium-Rendering-Engine einbettet.
Bewertungskriterien
Bevor Sie Bibliotheken vergleichen, sollten Sie wissen, was zu bewerten ist. Dies sind die Fragen, die Produktionsprobleme frühzeitig aufdecken:
| Kriterium | Was zu testen ist | Warum das wichtig ist |
|---|---|---|
| HTML/CSS-Rendering | Füttern Sie es mit Ihren aktuellen Vorlagen mit Flexbox/Grid | Die meisten Bibliotheken behaupten, HTML zu unterstützen, geben aber bestenfalls CSS 2.1 wieder |
| JavaScript-Ausführung | Test mit Chart.js oder dynamischem Tabelleninhalt | Bibliotheken ohne JS-Unterstützung erzeugen leere Abschnitte |
| Lizenzierungsmodell | Lesen Sie die vollständige Lizenz, nicht die Zusammenfassung | AGPL erfordert das Open-Sourcing Ihrer gesamten Anwendung |
| Plattform-Unterstützung | Bereitstellung in Ihrer Linux/Docker/ARM64-Zielumgebung | Der Erfolg von Windows sagt nichts über das Verhalten von Linux aus |
| Speicher unter Last | Generieren Sie 100+ Dokumente in einer Schleife | Einzeldokumententests verbergen Lecks, die Produktionsserver zum Absturz bringen |
| Veröffentlichte Preise | Prüfen Sie, ob die Preise auf der Website stehen | "Kontaktverkauf" bedeutet oft $15K-$210K/Jahr |
Vergleich von Bibliotheken
IronPDF- Eingebettetes Chromium, volle CSS/JS-Unterstützung
IronPDF bettet Chromium direkt in das NuGet-Paket ein. HTML-Rendering passt zu Chrome, weil es die Engine von Chrome ist. CSS Flexbox, Grid, benutzerdefinierte Eigenschaften und JavaScriptwerden alle wie erwartet ausgeführt.
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
var pdf = renderer.RenderHtmlAsPdf(@"
<html>
<head>
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.card { background: linear-gradient(135deg, #f8fafc, #e2e8f0);
border-radius: 8px; padding: 20px; text-align: center; }
</style>
</head>
<body>
<div class='grid'>
<div class='card'><h3>Revenue</h3><p>$1.2M</p></div>
<div class='card'><h3>Users</h3><p>45,230</p></div>
<div class='card'><h3>Uptime</h3><p>99.97%</p></div>
</div>
</body>
</html>");
pdf.SaveAs("dashboard.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print;
var pdf = renderer.RenderHtmlAsPdf(@"
<html>
<head>
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.card { background: linear-gradient(135deg, #f8fafc, #e2e8f0);
border-radius: 8px; padding: 20px; text-align: center; }
</style>
</head>
<body>
<div class='grid'>
<div class='card'><h3>Revenue</h3><p>$1.2M</p></div>
<div class='card'><h3>Users</h3><p>45,230</p></div>
<div class='card'><h3>Uptime</h3><p>99.97%</p></div>
</div>
</body>
</html>");
pdf.SaveAs("dashboard.pdf");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.CssMediaType = IronPdf.Rendering.PdfCssMediaType.Print
Dim pdf = renderer.RenderHtmlAsPdf("
<html>
<head>
<style>
.grid { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }
.card { background: linear-gradient(135deg, #f8fafc, #e2e8f0);
border-radius: 8px; padding: 20px; text-align: center; }
</style>
</head>
<body>
<div class='grid'>
<div class='card'><h3>Revenue</h3><p>$1.2M</p></div>
<div class='card'><h3>Users</h3><p>45,230</p></div>
<div class='card'><h3>Uptime</h3><p>99.97%</p></div>
</div>
</body>
</html>")
pdf.SaveAs("dashboard.pdf")
Zu beachtende Nachteile: Das eingebettete Chromium fügt dem Bereitstellungspaket ~200 MB hinzu. Für Standard-Server- und Container-Implementierungen ist dies ein einmaliger Download, der keine Auswirkungen auf die Laufzeit hat. Bei Umgebungen mit Größenbeschränkungen wie dem Azure Functions-Verbrauchsplan sollten Sie das Größenlimit für die Bereitstellung überprüfen. Die erste PDF-Generierung in einem kalten Prozess dauert 2-5 Sekunden für die Chromium-Initialisierung; die nachfolgenden Generationen laufen in 100-500ms. Der Basisspeicher beträgt ~150-200 MB - planen Sie die Container-Ressourcen entsprechend ein.
Lizenzierung: Unbefristete Lizenzen ab 749 $ (1 Entwickler). Die Preise werden auf ironPdf.com veröffentlicht. Keine Gebühren pro Dokument, keine AGPL, keine Umsatzschwellen.
iText 7 (iTextSharp) - AGPL-Lizenzierung, eingeschränktes HTML
iText ist eine leistungsfähige Bibliothek zur PDF-Bearbeitung mit einer langen Geschichte. Das pdfHTML-Add-on bietet eine HTML-zu-PDF-Konvertierung, verwendet aber keine Browser-Engine, sondern nähert sich CSS 2.1 mit einem eigenen Parser an.
Ein Produktionsteam eines mittelständischen SaaS-Unternehmens stellte dies fest, als es seine Rechnungsvorlagen von Razor Views migrierte. Die Vorlagen verwenden CSS Flexbox für responsive Spaltenlayouts. Nach der Integration von pdfHTML von iText wurde jede Rechnung als einspaltiger vertikaler Stapel gerendert. Die Eigenschaften display: flex, gap, und justify-content wurden stillschweigend ignoriert. Drei Wochen Entwicklungszeit gingen ins Land, bevor das Team feststellte, dass pdfHTML das vorhandene CSS nicht darstellen konnte.
Die AGPL-Realität: iText verwendet die AGPL-Lizenz. Wenn Ihre Anwendung über das Netzwerk zugänglich ist - dazu gehören alle Webanwendungen, APIs und SaaS-Produkte - müssen Sie den gesamten Quellcode Ihrer Anwendung unter der AGPL veröffentlichen. Nicht nur das PDF-Modul. Alles. iText und die Muttergesellschaft Apryse setzen dies aktiv durch.
Kommerzielle Lizenzierung: iText stellt im Jahr 2024 auf eine abonnementbasierte Lizenzierung um. Die Preise werden nicht veröffentlicht - für ein Angebot wenden Sie sich bitte an den Vertrieb. Daten von Dritten deuten auf $15.000-$210.000 jährlich hin, je nach Nutzungsvolumen.
PdfSharp - MIT lizenziert, kein HTML
PdfSharp ist wirklich frei unter der MIT-Lizenz und wurde bereits 34,9 Millionen Mal von NuGet heruntergeladen. Der Kompromiss ist die Fähigkeit: Es bietet eine koordinatenbasierte Zeichen-API ohne HTML-Parser, ohne CSS-Engine und ohne Vorlagensystem.
Ein Team, das ein Reporting-Dashboard erstellt, wählte PdfSharp, weil es kostenlos und bekannt ist. Sie verbrachten vier Monate damit, koordinatenbasierten Layout-Code zu schreiben - X/Y-Positionen für jedes Textelement zu berechnen, Tabellenränder Pixel für Pixel zu zeichnen und Seitenumbrüche manuell zu bearbeiten. Als sie schließlich ihre Ausgabe mit dem verglichen, was die gleiche HTML-Vorlage in einem Browser erzeugte, stellten sie fest, dass sie eine schlechtere Version dessen erstellt hatten, was eine Chromium-basierte Bibliothek automatisch tut.
PdfSharp eignet sich gut zum Zusammenführen von PDFs, Hinzufügen von Wasserzeichen und Erstellen einfacher strukturierter Dokumente aus Daten. Wenn Sie kein HTML-Rendering benötigen, bleibt es eine legitime Option.
QuestPDF - Elegante API, kein HTML, Umsatzschwelle
QuestPDF bietet eine flüssige C#-API für die programmgesteuerte Erstellung von Dokumenten. Das API-Design ist wirklich gut - es ist eine der besseren .NET-Bibliotheks-APIs in jeder Kategorie.
Zwei Einschränkungen sind wichtig: QuestPDF rendert kein HTML (dies ist eine bewusste architektonische Entscheidung, keine fehlende Funktion), und die Community-Lizenz deckt Unternehmen mit einem jährlichen Bruttoumsatz von weniger als 1 Million Dollar ab. Sobald Ihr Unternehmen diese Schwelle überschreitet, wird eine Gewerbliche Lizenz erforderlich. Unternehmen, die sich der Schwelle nähern, sollten für diese Umstellung ein Budget einplanen, bevor es dringend wird.
Trotz der klaren Positionierung von QuestPDF gegenüber HTML stellen Entwickler dies regelmäßig fest, nachdem sie mit der Implementierung begonnen haben, da die Bibliothek in den Suchergebnissen für "C#-PDF-Bibliotheken" neben HTML-fähigen Bibliotheken erscheint.
wkhtmltopdf Wrappers - Verlassene, ungepatchte CVEs
die Zeit von wkhtmltopdf ist vorbei. Die GitHub Organisation wurde im Juli 2024 archiviert. Die zugrunde liegende QtWebKit-Engine wurde 2015 von Qt veraltet. Bekannte CVEs - einschließlich CVE-2022-35583(CVSS 9.8, SSRF, das die Exfiltration von AWS-Anmeldeinformationen ermöglicht) - werden nie gepatcht.
C#-Wrapper wie DinkToPdf, NReco.PdfGenerator und WkHtmlToXSharp verpacken alle das gleiche aufgegebene Binärprogramm. Die Rendering-Engine ist ungefähr auf dem Stand von Safari 2011 eingefroren: kein Flexbox, kein Grid, begrenztes JavaScript. Dies ist keine praktikable Option für neue Projekte.
PuppeteerSharp- Vollständiges Rendering, Betriebskomplexität
Puppeteer Sharp steuert Headless Chrome über .NET-Bindungen. Die Wiedergabequalität entspricht der von Chrome, weil es Chrome ist. Der Kompromiss ist operativ: Sie verwalten externe Browserprozesse, einschließlich Downloads, Pooling, Speicherüberwachung und Wiederherstellung bei Abstürzen.
using PuppeteerSharp;
// Downloads ~280MB Chromium on first run
await new BrowserFetcher().DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(
new LaunchOptions { Headless = true });
await using var page = await browser.NewPageAsync();
await page.SetContentAsync(html);
return await page.PdfAsync(new PdfOptions { Format = PaperFormat.A4, PrintBackground = true });
using PuppeteerSharp;
// Downloads ~280MB Chromium on first run
await new BrowserFetcher().DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(
new LaunchOptions { Headless = true });
await using var page = await browser.NewPageAsync();
await page.SetContentAsync(html);
return await page.PdfAsync(new PdfOptions { Format = PaperFormat.A4, PrintBackground = true });
Imports PuppeteerSharp
' Downloads ~280MB Chromium on first run
Await (New BrowserFetcher()).DownloadAsync()
Await Using browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {.Headless = True})
Await Using page = Await browser.NewPageAsync()
Await page.SetContentAsync(html)
Return Await page.PdfAsync(New PdfOptions With {.Format = PaperFormat.A4, .PrintBackground = True})
End Using
End Using
In der Produktion benötigen Sie außerdem Browser-Prozess-Pooling, Überwachung von Speicherlecks (Chromium-Prozesse können auslaufen), Wiederherstellung bei Abstürzen und Bereinigung von Ressourcen. Die Docker-Bereitstellung erfordert die Installation von Chromium-Abhängigkeiten - eine umfangreiche Dockerdatei im Vergleich zu einem Standard-.NET-Image. PuppeteerSharpist realisierbar, wenn Ihr Team den operativen Aufwand tragen kann.
Aspose.PDF - Umfangreiche Funktionen, Linux-Speicherprobleme
Aspose.PDF bietet eine umfassende PDF-Funktionalität mit guter Dokumentation. Das wichtigste Problem ist die Linux-Stabilität: Asposehängt von System.Drawing.Common ab, das unter Linux libgdiplus benötigt - eine nicht gewartete Bibliothek mit dokumentierten Speicherlecks. Die Berichte für Entwickler umfassen mehrere Jahre:
Mehrere Dutzend Anfragen führen dazu, dass dem Dienst in der Unix-Umgebung der Speicher ausgeht, was aber in der Windows-Umgebung nicht der Fall ist
Für reine Windows-Einsätze ist Asposeweiterhin geeignet. Für plattformübergreifende oder containerisierte Implementierungen stellt die Abhängigkeit von System.Drawing.Common ein ständiges Risiko dar. Die Preise für kommerzielle Lizenzen beginnen bei etwa $999 pro Entwickler.
Funktionsvergleich
| Feature | IronPDF | iText 7 | PdfSharp | QuestPDF | wkhtmltopdf | Puppeteer | Aspose |
|---|---|---|---|---|---|---|---|
| HTML zu PDF | Vollständig (Chromium) | Begrenzt (CSS 2.1) | Nein | Nein | Veraltet | Vollständig (Chrome) | Beschränkt |
| CSS Flexbox/Grid | Ja | Nein | Nein | Nein | Nein | Ja | Nein |
| JavaScript | Ja | Nein | Nein | Nein | Beschränkt | Ja | Nein |
| Linux (ohne libgdiplus) | Ja | Ja | Teilweise* | Ja | Nicht anwendbar | Ja | Nein |
| Docker-Einsatz | .NET-Standardbild | Standard | Teilweise* | Standard | Komplex | Komplex | Benötigt libgdiplus |
| Aktive Wartung | Ja | Ja | Ja | Ja | Aufgegeben | Ja | Ja |
| Veröffentlichte Preise | Ja ($749+) | Nein ($15K-$210K/Jahr) | Frei (MIT) | Ja (kostenlos <$1M) | Kostenlos | Frei (MIT) | Ja (ab $999) |
| Unbefristete Lizenz | Ja | Nein (Abonnement) | Nicht anwendbar | Nicht anwendbar | Nicht anwendbar | Nicht anwendbar | Ja |
| AGPL-frei | Ja | Nein (erfordert Werbung) | Ja | Ja | Ja | Ja | Ja |
*PdfSharp hat plattformspezifische Probleme mit einigen Konfigurationen dokumentiert.
Leistungsvergleich
Getestet auf einer Mid-Tier-Cloud-VM (4 vCPU, 8 GB RAM) mit einer HTML-Rechnungsvorlage mit 200 Elementen, durchschnittlich über 50 Iterationen nach der Aufwärmphase:
| Szenario | IronPDF | PuppeteerSharp | iText pdfHTML | wkhtmltopdf |
|---|---|---|---|---|
| Einfache HTML-Seite | ~150ms | ~500ms | ~200ms | ~200ms |
| Komplexes CSS-Layout (Flexbox/Grid) | ~250ms | ~600ms | Misslungen/Teilweise | ~400ms (abgebrochen) |
| JavaScript-lastige Seite | ~350ms | ~800ms | Fällt aus | Misslungen/Teilweise |
| Speicher pro Vorgang | ~80MB | ~150MB | ~60MB | ~50MB |
| Kaltstart (erste Generation) | 2-5s | 3-8s | <1s | <1s |
iText und wkhtmltopdf zeigen schnellere Kaltstarts, weil sie keine Browser-Engine initialisieren - aber sie können auch nicht denselben Inhalt rendern. Der Leistungsvergleich ist nur für Szenarien aussagekräftig, in denen alle Bibliotheken eine korrekte Ausgabe liefern.
Code-Vergleich: Dieselbe Rechnung, drei Bibliotheken
Die Unterschiede zwischen diesen Bibliotheken werden beim Aufbau desselben Dokuments am deutlichsten. Hier ist eine auf drei Arten erstellte Rechnung.
IronPDF- HTML/CSS-Ansatz
using IronPdf;
public class InvoiceGenerator
{
public byte[] GenerateInvoice(InvoiceData data)
{
var renderer = new ChromePdfRenderer();
string html = $@"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: 'Segoe UI', sans-serif; margin: 40px; }}
h1 {{ color: #2c3e50; }}
table {{ width: 100%; border-collapse: collapse; }}
th {{ background: #3498db; color: white; padding: 12px; text-align: left; }}
td {{ border-bottom: 1px solid #e0e0e0; padding: 10px; }}
.total {{ font-weight: bold; font-size: 1.2em; text-align: right; margin-top: 20px; }}
</style>
</head>
<body>
<h1>Invoice #{data.InvoiceNumber}</h1>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
{string.Join("", data.Items.Select(i =>
$"<tr><td>{i.Name}</td><td>{i.Quantity}</td><td>${i.Price:F2}</td></tr>"))}
</table>
<p class='total'>Total: ${data.Total:F2}</p>
</body>
</html>";
var pdf = renderer.RenderHtmlAsPdf(html);
return pdf.BinaryData;
}
}
using IronPdf;
public class InvoiceGenerator
{
public byte[] GenerateInvoice(InvoiceData data)
{
var renderer = new ChromePdfRenderer();
string html = $@"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: 'Segoe UI', sans-serif; margin: 40px; }}
h1 {{ color: #2c3e50; }}
table {{ width: 100%; border-collapse: collapse; }}
th {{ background: #3498db; color: white; padding: 12px; text-align: left; }}
td {{ border-bottom: 1px solid #e0e0e0; padding: 10px; }}
.total {{ font-weight: bold; font-size: 1.2em; text-align: right; margin-top: 20px; }}
</style>
</head>
<body>
<h1>Invoice #{data.InvoiceNumber}</h1>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
{string.Join("", data.Items.Select(i =>
$"<tr><td>{i.Name}</td><td>{i.Quantity}</td><td>${i.Price:F2}</td></tr>"))}
</table>
<p class='total'>Total: ${data.Total:F2}</p>
</body>
</html>";
var pdf = renderer.RenderHtmlAsPdf(html);
return pdf.BinaryData;
}
}
Imports IronPdf
Public Class InvoiceGenerator
Public Function GenerateInvoice(data As InvoiceData) As Byte()
Dim renderer = New ChromePdfRenderer()
Dim html As String = $"
<!DOCTYPE html>
<html>
<head>
<style>
body {{ font-family: 'Segoe UI', sans-serif; margin: 40px; }}
h1 {{ color: #2c3e50; }}
table {{ width: 100%; border-collapse: collapse; }}
th {{ background: #3498db; color: white; padding: 12px; text-align: left; }}
td {{ border-bottom: 1px solid #e0e0e0; padding: 10px; }}
.total {{ font-weight: bold; font-size: 1.2em; text-align: right; margin-top: 20px; }}
</style>
</head>
<body>
<h1>Invoice #{data.InvoiceNumber}</h1>
<table>
<tr><th>Item</th><th>Qty</th><th>Price</th></tr>
{String.Join("", data.Items.Select(Function(i) $"<tr><td>{i.Name}</td><td>{i.Quantity}</td><td>${i.Price:F2}</td></tr>"))}
</table>
<p class='total'>Total: ${data.Total:F2}</p>
</body>
</html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
Return pdf.BinaryData
End Function
End Class
QuestPDF - Fließender API-Ansatz
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
public class InvoiceGenerator
{
public byte[] GenerateInvoice(InvoiceData data)
{
var document = Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(40);
page.DefaultTextStyle(x => x.FontFamily("Segoe UI"));
page.Header()
.Text($"Invoice #{data.InvoiceNumber}")
.FontSize(24).FontColor(Colors.Blue.Darken2);
page.Content().Column(column =>
{
column.Item().Table(table =>
{
table.ColumnsDefinition(cols =>
{
cols.RelativeColumn(3);
cols.RelativeColumn(1);
cols.RelativeColumn(1);
});
table.Header(header =>
{
header.Cell().Background(Colors.Blue.Medium).Padding(8)
.Text("Item").FontColor(Colors.White);
header.Cell().Background(Colors.Blue.Medium).Padding(8)
.Text("Qty").FontColor(Colors.White);
header.Cell().Background(Colors.Blue.Medium).Padding(8)
.Text("Price").FontColor(Colors.White);
});
foreach (var item in data.Items)
{
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2)
.Padding(8).Text(item.Name);
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2)
.Padding(8).Text(item.Quantity.ToString());
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2)
.Padding(8).Text($"${item.Price:F2}");
}
});
column.Item().AlignRight().PaddingTop(20)
.Text($"Total: ${data.Total:F2}").FontSize(16).Bold();
});
});
});
using var stream = new MemoryStream();
document.GeneratePdf(stream);
return stream.ToArray();
}
}
using QuestPDF.Fluent;
using QuestPDF.Infrastructure;
public class InvoiceGenerator
{
public byte[] GenerateInvoice(InvoiceData data)
{
var document = Document.Create(container =>
{
container.Page(page =>
{
page.Size(PageSizes.A4);
page.Margin(40);
page.DefaultTextStyle(x => x.FontFamily("Segoe UI"));
page.Header()
.Text($"Invoice #{data.InvoiceNumber}")
.FontSize(24).FontColor(Colors.Blue.Darken2);
page.Content().Column(column =>
{
column.Item().Table(table =>
{
table.ColumnsDefinition(cols =>
{
cols.RelativeColumn(3);
cols.RelativeColumn(1);
cols.RelativeColumn(1);
});
table.Header(header =>
{
header.Cell().Background(Colors.Blue.Medium).Padding(8)
.Text("Item").FontColor(Colors.White);
header.Cell().Background(Colors.Blue.Medium).Padding(8)
.Text("Qty").FontColor(Colors.White);
header.Cell().Background(Colors.Blue.Medium).Padding(8)
.Text("Price").FontColor(Colors.White);
});
foreach (var item in data.Items)
{
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2)
.Padding(8).Text(item.Name);
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2)
.Padding(8).Text(item.Quantity.ToString());
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2)
.Padding(8).Text($"${item.Price:F2}");
}
});
column.Item().AlignRight().PaddingTop(20)
.Text($"Total: ${data.Total:F2}").FontSize(16).Bold();
});
});
});
using var stream = new MemoryStream();
document.GeneratePdf(stream);
return stream.ToArray();
}
}
Imports QuestPDF.Fluent
Imports QuestPDF.Infrastructure
Imports System.IO
Public Class InvoiceGenerator
Public Function GenerateInvoice(data As InvoiceData) As Byte()
Dim document = Document.Create(Sub(container)
container.Page(Sub(page)
page.Size(PageSizes.A4)
page.Margin(40)
page.DefaultTextStyle(Function(x) x.FontFamily("Segoe UI"))
page.Header() _
.Text($"Invoice #{data.InvoiceNumber}") _
.FontSize(24).FontColor(Colors.Blue.Darken2)
page.Content().Column(Sub(column)
column.Item().Table(Sub(table)
table.ColumnsDefinition(Sub(cols)
cols.RelativeColumn(3)
cols.RelativeColumn(1)
cols.RelativeColumn(1)
End Sub)
table.Header(Sub(header)
header.Cell().Background(Colors.Blue.Medium).Padding(8) _
.Text("Item").FontColor(Colors.White)
header.Cell().Background(Colors.Blue.Medium).Padding(8) _
.Text("Qty").FontColor(Colors.White)
header.Cell().Background(Colors.Blue.Medium).Padding(8) _
.Text("Price").FontColor(Colors.White)
End Sub)
For Each item In data.Items
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2) _
.Padding(8).Text(item.Name)
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2) _
.Padding(8).Text(item.Quantity.ToString())
table.Cell().BorderBottom(1).BorderColor(Colors.Grey.Lighten2) _
.Padding(8).Text($"${item.Price:F2}")
Next
End Sub)
column.Item().AlignRight().PaddingTop(20) _
.Text($"Total: ${data.Total:F2}").FontSize(16).Bold()
End Sub)
End Sub)
End Sub)
Using stream As New MemoryStream()
document.GeneratePdf(stream)
Return stream.ToArray()
End Using
End Function
End Class
PdfSharp - Ansatz für Koordinatenzeichnungen
using PdfSharpCore.Drawing;
using PdfSharpCore.Pdf;
public class InvoiceGenerator
{
public byte[] GenerateInvoice(InvoiceData data)
{
var document = new PdfDocument();
var page = document.AddPage();
var gfx = XGraphics.FromPdfPage(page);
var titleFont = new XFont("Arial", 24);
var headerFont = new XFont("Arial", 12, XFontStyleEx.Bold);
var bodyFont = new XFont("Arial", 12);
double y = 40;
gfx.DrawString($"Invoice #{data.InvoiceNumber}", titleFont,
XBrushes.DarkBlue, 40, y);
y += 50;
// Table header — manually positioned
double[] colX = { 40, 300, 400 };
double rowHeight = 30;
gfx.DrawRectangle(XBrushes.SteelBlue, 40, y, 500, rowHeight);
gfx.DrawString("Item", headerFont, XBrushes.White, colX[0] + 10, y + 20);
gfx.DrawString("Qty", headerFont, XBrushes.White, colX[1] + 10, y + 20);
gfx.DrawString("Price", headerFont, XBrushes.White, colX[2] + 10, y + 20);
y += rowHeight;
// Each row drawn individually with explicit coordinates
foreach (var item in data.Items)
{
gfx.DrawRectangle(XPens.LightGray, 40, y, 500, rowHeight);
gfx.DrawString(item.Name, bodyFont, XBrushes.Black, colX[0] + 10, y + 20);
gfx.DrawString(item.Quantity.ToString(), bodyFont, XBrushes.Black, colX[1] + 10, y + 20);
gfx.DrawString($"${item.Price:F2}", bodyFont, XBrushes.Black, colX[2] + 10, y + 20);
y += rowHeight;
}
y += 20;
gfx.DrawString($"Total: ${data.Total:F2}", headerFont, XBrushes.Black, 440, y);
using var stream = new MemoryStream();
document.Save(stream);
return stream.ToArray();
}
}
using PdfSharpCore.Drawing;
using PdfSharpCore.Pdf;
public class InvoiceGenerator
{
public byte[] GenerateInvoice(InvoiceData data)
{
var document = new PdfDocument();
var page = document.AddPage();
var gfx = XGraphics.FromPdfPage(page);
var titleFont = new XFont("Arial", 24);
var headerFont = new XFont("Arial", 12, XFontStyleEx.Bold);
var bodyFont = new XFont("Arial", 12);
double y = 40;
gfx.DrawString($"Invoice #{data.InvoiceNumber}", titleFont,
XBrushes.DarkBlue, 40, y);
y += 50;
// Table header — manually positioned
double[] colX = { 40, 300, 400 };
double rowHeight = 30;
gfx.DrawRectangle(XBrushes.SteelBlue, 40, y, 500, rowHeight);
gfx.DrawString("Item", headerFont, XBrushes.White, colX[0] + 10, y + 20);
gfx.DrawString("Qty", headerFont, XBrushes.White, colX[1] + 10, y + 20);
gfx.DrawString("Price", headerFont, XBrushes.White, colX[2] + 10, y + 20);
y += rowHeight;
// Each row drawn individually with explicit coordinates
foreach (var item in data.Items)
{
gfx.DrawRectangle(XPens.LightGray, 40, y, 500, rowHeight);
gfx.DrawString(item.Name, bodyFont, XBrushes.Black, colX[0] + 10, y + 20);
gfx.DrawString(item.Quantity.ToString(), bodyFont, XBrushes.Black, colX[1] + 10, y + 20);
gfx.DrawString($"${item.Price:F2}", bodyFont, XBrushes.Black, colX[2] + 10, y + 20);
y += rowHeight;
}
y += 20;
gfx.DrawString($"Total: ${data.Total:F2}", headerFont, XBrushes.Black, 440, y);
using var stream = new MemoryStream();
document.Save(stream);
return stream.ToArray();
}
}
Imports PdfSharpCore.Drawing
Imports PdfSharpCore.Pdf
Imports System.IO
Public Class InvoiceGenerator
Public Function GenerateInvoice(data As InvoiceData) As Byte()
Dim document As New PdfDocument()
Dim page = document.AddPage()
Dim gfx = XGraphics.FromPdfPage(page)
Dim titleFont As New XFont("Arial", 24)
Dim headerFont As New XFont("Arial", 12, XFontStyleEx.Bold)
Dim bodyFont As New XFont("Arial", 12)
Dim y As Double = 40
gfx.DrawString($"Invoice #{data.InvoiceNumber}", titleFont, XBrushes.DarkBlue, 40, y)
y += 50
' Table header — manually positioned
Dim colX As Double() = {40, 300, 400}
Dim rowHeight As Double = 30
gfx.DrawRectangle(XBrushes.SteelBlue, 40, y, 500, rowHeight)
gfx.DrawString("Item", headerFont, XBrushes.White, colX(0) + 10, y + 20)
gfx.DrawString("Qty", headerFont, XBrushes.White, colX(1) + 10, y + 20)
gfx.DrawString("Price", headerFont, XBrushes.White, colX(2) + 10, y + 20)
y += rowHeight
' Each row drawn individually with explicit coordinates
For Each item In data.Items
gfx.DrawRectangle(XPens.LightGray, 40, y, 500, rowHeight)
gfx.DrawString(item.Name, bodyFont, XBrushes.Black, colX(0) + 10, y + 20)
gfx.DrawString(item.Quantity.ToString(), bodyFont, XBrushes.Black, colX(1) + 10, y + 20)
gfx.DrawString($"${item.Price:F2}", bodyFont, XBrushes.Black, colX(2) + 10, y + 20)
y += rowHeight
Next
y += 20
gfx.DrawString($"Total: ${data.Total:F2}", headerFont, XBrushes.Black, 440, y)
Using stream As New MemoryStream()
document.Save(stream)
Return stream.ToArray()
End Using
End Function
End Class
Die IronPDF-Version verwendet HTML/CSS - Fähigkeiten, über die die meisten Entwickler bereits verfügen. Die QuestPDF-Version erfordert das Erlernen einer domänenspezifischen, fließenden API, bietet aber Struktur. Bei der PdfSharp-Version muss jede Pixelposition manuell berechnet werden - jeder Spaltenversatz, jede Zeilenhöhe, jeder einzeln gezeichnete Rand.
Welche Bibliothek soll ich wählen?
Wenn ich diese Bibliotheken bewerte, ist der Entscheidungsbaum sehr einfach:
Brauchen Sie HTML-zu-PDF mit modernem CSS? Die praktischen Optionen sindIronPDFoder PuppeteerSharp.IronPDFarbeitet intern mit Chromium; Mit PuppeteerSharpmüssen Sie externe Browserprozesse verwalten. wkhtmltopdf ist keine Option für neue Projekte. pdfHTML von iText kann Flexbox oder Grid nicht darstellen.
Dokumente programmatisch aus Daten erstellen, kein HTML? Die flüssige API von QuestPDF ist produktiv und gut durchdacht. PdfSharp bietet eine niedrigere Kontrollebene, erfordert aber deutlich mehr Code für gleichwertige Layouts.
Plattformübergreifende Bereitstellung (Linux, Docker, Cloud)? IronPDF, QuestPDF und PuppeteerSharpfunktionieren unter Linux ohne libgdiplus-Abhängigkeiten. Aspose.PDF hat Speicherlecks unter Linux dokumentiert. PdfSharp hat teilweise Plattformunterstützung mit bekannten Problemen.
Lizenzbedingungen? PdfSharp (MIT) und PuppeteerSharp(MIT) sind kostenlos und ohne Bedingungen. QuestPDF ist unter $1M Umsatz kostenlos. iText erfordert entweder die Einhaltung der AGPL oder eine kommerzielle Lizenzierung ($15K-$210K/Jahr). Die unbefristete Lizenz vonIronPDFbeginnt bei $749. Asposebeginnt bei ~$999.
Bevor Sie sich festlegen
Testen Sie mit Ihrem tatsächlichen Inhalt, nicht mit "Hello World" Führen Sie die Bereitstellung auf Ihrer Zielplattform frühzeitig durch. Messen Sie das Gedächtnis über 100+ Dokumente, nicht nur eines. Lesen Sie den vollständigen Lizenztext zusammen mit Ihrem Rechtsteam. Prüfen Sie die Kaltstart-Latenz, wenn Sie auf Serverless abzielen.
IronPDF bietet eine Testversion mit vollem Funktionsumfang zur Evaluierung anhand Ihrer spezifischen Anforderungen.