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");
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");
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 unter der MIT-Lizenz tatsächlich kostenlos und wurde 34,9 Millionen Mal auf 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 entwickelt, wählte PdfSharp, weil es kostenlos und bekannt war. 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 });
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;
}
}
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();
}
}
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();
}
}
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. Die Version PdfSharp erfordert die manuelle Berechnung jeder Pixelposition – jeden Spaltenversatz, jede Zeilenhöhe, jeden einzeln gezeichneten Rahmen.
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 Steuerung auf niedrigerer Ebene, 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 bietet nur teilweise Plattformunterstützung und weist bekannte Probleme auf.
Lizenzbeschränkungen? PdfSharp (MIT) und PuppeteerSharp(MIT) sind bedingungslos kostenlos. 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.