2026'da Belge Oluşturma için En İyi C# Kütüphanesini Seçmek
Bir C# PDF kütüphanesi seçmek, projenizin lisanslama maruziyetini, dağıtım esnekliğini ve uzun vadeli bakım maliyetini etkiler. Değerlendirme sırasında uygun görünen çoğu kütüphane üretim aşamasında sınırlamalar ortaya çıkartır — beklenmeyen AGPL gereksinimleri, tarayıcınızla eşleşmeyen HTML renderlemesi veya sadece Linux üzerinde ortaya çıkan bellek sızıntıları.
Bu makale, başlıca seçenekleri kod örnekleriyle karşılaştırır, uygulamada önemli olan ödünleşimleri belgeler ve üç farklı kütüphane arasında aynı faturayı üreten yan yana bir kod karşılaştırması içerir, böylece API farklılıklarını doğrudan görebilirsiniz.
Hızlı Başlangıç: HTML'i Üç Satırda PDF'ye Dönüştürme
NuGet ile yükleyin:
Install-Package IronPdfBir PDF oluşturun:
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")Bu, ek yapılandırma gerektirmeden Windows, Linux, macOS ve Docker üzerinde çalışır. Çıktı, IronPDF'in aynı Chromium renderleme motorunu eklemesinden dolayı Chrome ile eşleşir.
Değerlendirme Kriterleri
Kütüphaneleri karşılaştırmadan önce, neyi değerlendireceğinizi bilmek önemlidir. Bunlar, üretim sorunlarını erken aşamada açığa çıkaran sorulardır:
| Kriter | Ne Yapmalı | Neden Önemlidir |
|---|---|---|
| HTML/CSS renderlemesi | Gerçek şablonlarınızı Flexbox/Grid ile besleyin | Çoğu kütüphane HTML desteğini iddia eder ama en iyi CSS 2.1 render edebilirler |
| JavaScriptyürütme | Chart.js veya dinamik tablo içeriği ile test edin | JS desteği olmayan kütüphaneler boş bölümler üretir |
| Lisanslama modeli | Lisansın tamamını okuyun, yalnızca özeti değil | AGPL, bütün uygulamanızı açık kaynak yapmanızı gerektirir |
| Platform desteği | Hedef Linux/Docker/ARM64 ortamınıza dağıtın | Windows başarısı, Linux davranışını öngörmez |
| Yük altındaki bellek | Bir döngüde 100+ doküman oluşturun | Tek doküman testleri, üretim sunucularını çökertecek sızıntıları gizler |
| Yayınlanmış fiyatlandırma | Fiyatlandırmanın web sitesinde olup olmadığını kontrol edin | 'Satışla iletişime geç' genellikle yıllık $15K–$210K anlamına gelir |
Kütüphane Karşılaştırması
IronPDF— Gömülü Chromium, Tam CSS/JS Desteği
IronPDF, Chromium'u doğrudan NuGet paketine gömüyor. HTML renderlemesi Chrome ile eşleşiyor çünkü aynı Chrome motorunu kullanıyor. CSS Flexbox, Grid, özel özellikler veJavaScriptbeklenildiği gibi çalışır.
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")Dikkate alınması gereken ödünleşimler: Gömülü Chromium, dağıtım paketine yaklaşık ~200MB ekler. Standart sunucu ve konteyner dağıtımları için, bu tek seferlik bir indirmedir ve çalışma zamanı etkisi yoktur. Azure Functions gibi boyuta kısıtlı ortamlar için dağıtım boyutu sınırını kontrol edin. Soğuk bir süreçteki ilk PDF oluşturma, Chromium başlatılması için 2–5 saniye sürer; ardışık üretimler 100–500ms arasında çalışır. Bellek tabanı ~150–200MB'dır — konteyner kaynaklarını buna göre planlayın.
Lisanslama: Süresiz lisanslar $2,998 (1 geliştirici) başlangıç fiyatıyla. ironpdf.com adresinde yayınlanan fiyatlar. Belge başına ücret yok, AGPL yok, gelir eşiği yok.
iText(iText) — AGPL Lisanslama, Sınırlı HTML
iText, uzun bir geçmişe sahip bir PDF düzenleme kütüphanesidir. pdfHTML eklentisi HTML'den PDF'ye dönüştürme sağlar ancak bir tarayıcı motoru kullanmaz — CSS 2.1'i yaklaşık olarak bir özel parser kullanır.
Orta ölçekli bir SaaS şirketindeki üretim ekibi, fatura şablonlarını Razor görünümlerinden geçirdiğinde bunu keşfetti. Şablonlar, duyarlı sütun düzenleri için CSS Flexbox kullandı. iText'in pdfHTML'ini entegre ettikten sonra, her fatura, tek sütunlu dikey bir yığın olarak render edildi. display: flex, gap ve justify-content özellikleri sessizce göz ardı edildi. pdfHTML'in mevcut CSS'lerini render edemeyeceğini fark etmeden önce üç hafta geliştirme süresi harcandı.
AGPL gerçeği: iText, AGPL lisansını kullanır. Uygulamanız ağ üzerinden erişilebilir - bu her web uygulaması, API ve SaaS ürününü kapsar - uygulamanızın kaynak kodunu AGPL altına almanız gerekmektedir. Sadece PDF modülü değil. Her şey.iTextve parent şirketi Apryse bunu aktif olarak uygular.
Ticari lisanslama: iText, 2024'te abonelik tabanlı lisanslamaya geçti. Fiyatlar yayınlanmıyor — teklif için satışla iletişime geçiyorsunuz. Üçüncü parti veriler, kullanım hacmine bağlı olarak yıllık $15.000–$210.000 arasında değerlendiriyor.
PDFSharp— MIT Lisanslı, HTML Yok
PdfSharp, 34,9 milyon NuGet indirmesi ile MIT lisansı altında gerçekten ücretsizdir. Kapabilitenin getirdiği ödün, bir HTML parser, bir CSS motoru ve bir şablon sistemi olmadan bir koordinat tabanlı çizim API'si sağlamasıdır.
Bir raporlama panosu inşa eden bir ekip, ücretsiz ve iyi bilinen olduğu için PdfSharp seçti. Dört ay boyunca her metin elemanı için X/Y pozisyonları hesaplayarak, tablo kenarlıklarını piksel piksel çizerek, sayfa kırılmalarını manuel olarak işleyerek koordinat tabanlı yerleşim kodu yazdı. Nihayet çıktılarını, aynı HTML şablonun tarayıcıda ürettiğiyle karşılaştırdıklarında, Chromium tabanlı bir kütüphanenin otomatik olarak yaptığını daha kötü bir versiyonunu inşa ettiklerini fark ettiler.
PdfSharp, PDF birleştirme, filigran ekleme ve verilerden basit yapısal belgeler oluşturma işinde iyi çalışır. HTML renderlemeye ihtiyacınız yoksa, hala meşru bir seçenek olarak kalır.
QuestPDF— Şık API, HTML Yok, Gelir Eşiği
QuestPDF, belgeleri programatik olarak oluşturmak için akıcı bir C# API sunar. API tasarımı gerçekten iyi — herhangi bir kategoride en iyi .NET kütüphane API'lerinden biridir.
İki kısıtlama önem taşır:QuestPDFHTML renderlemez (tasarım gereği — bu bir eksiklik değil, kasıtlı bir mimari seçimdir) ve Toplum Lisansı, yıllık toplam gelirde $1M altında olan işletmeleri kapsar. Şirketiniz bu eşiği aştığında, bir ticari lisans zorunlu hale gelir. Eşiğe yaklaşan şirketler, bu dönüşümü acil hale gelmeden önce bütçelendirmelidir.
QuestPDF'in HTML'e karşı net yaklaşımına rağmen, geliştiriciler uygulamaya başladıktan sonra düzenli olarak bunu keşfeder çünkü kütüphane, HTML yetenekli kütüphanelerle birlikte "C# PDF kütüphanesi" arama sonuçlarında çıkar.
wkhtmltopdfÇerçeveleri — Terk Edilmiş, Yamalanmamış CVE'ler
wkhtmltopdf'nin zamanı geçti. GitHub organizasyonu Temmuz 2024'te arşivlendi. Temeldeki QtWebKit motoru 2015 yılında Qt tarafından kullanım dışı bırakıldı. Bilinen CVE'ler — CVE-2022-35583(CVSS 9.8, SSRF, AWS kimlik bilgisi sızmasına izin veren) dahil — asla yamalanmayacak.
DinkToPdf, NReco.PdfGenerator ve WkHtmlToXSharp gibi C# çerçeveleri hepsi aynı terk edilmiş binary'yi kaplar. Renderleme motoru yaklaşık olarak Safari 2011 kabiliyetinde dondurulmuş: Flexbox yok, Grid yok, sınırlı JavaScript. Bu, yeni projeler için geçerli bir seçenek değil.
Puppeteer Sharp— Tam Renderleme, Operasyonel Karmaşıklık
Puppeteer Sharp, Başsız Chrome'u .NET bağlamaları aracılığıyla kontrol eder. Renderleme kalitesi Chrome ile eşleşiyor çünkü aynı Chrome motorudur. Ödün, operasyonel: harici tarayıcı süreçlerini yönetiyorsunuz, indirmeleri, havuzlamayı, bellek izlemesini ve çöküş kurtarmayı içeren.
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Üretimde, tarayıcı süreci havuzlamasına, bellek sızıntı izlemesine (Chromium süreçleri sızabilir), çöküş kurtarma ve kaynak temizlemeye de ihtiyacınız var. Docker dağıtımı, standart bir .NET imajına kıyasla önemli bir Dockerfile gerektirir.PuppeteerSharp, ekibiniz operasyonel yükü absorbe edebilirse uygulanabilir.
Aspose.PDF — Geniş Özellikler, Linux Bellek Sorunları
Aspose.PDF, iyi bir belgelenme ile geniş çapta PDF işlevselliği sunar. Önemli sorun, Linux stabilitesi: Aspose, Linux'ta libgdiplus gerektiren System.Drawing.Common'a bağlı — belgelenmiş bellek sızıntılarına sahip, bakımsız bir kütüphane. Geliştirici raporları yıllar sürer:
"Birkaç düzine istek, Unix ortamında belleğin tükenmesine neden olur, ancak bu Windows tabanlı ortamda olmaz" — Aspose Forumu, Mart 2022
Sadece Windows dağıtımları için,Asposehala yetkin. Çapraz platform veya kapsüllü dağıtımlar için, System.Drawing.Common bağımlılığı sürekli bir risk yaratır. Ticari lisanslama geliştirici başına yaklaşık $999'dan başlar.
Özellik Karşılaştırması
| Özellik | IronPDF | iText | PDFSharp | QuestPDF | wkhtmltopdf | Puppeteer | Aspose |
|---|---|---|---|---|---|---|---|
| HTML'den PDF'ye | Tam (Chromium) | Sınırlı (CSS 2.1) | Hayır | Hayır | Kullanım dışı | Tam (Chrome) | Sınırlı |
| CSS Flexbox/Grid | Evet | Hayır | Hayır | Hayır | Hayır | Evet | Hayır |
| JavaScript | Evet | Hayır | Hayır | Hayır | Sınırlı | Evet | Hayır |
| Linux (libgdiplus yok) | Evet | Evet | Kısmi* | Evet | Yok | Evet | Hayır |
| Docker dağıtımı | Standart .NET imajı | Standart | Kısmi* | Standart | Karmaşık | Karmaşık | libgdiplus gerektirir |
| Aktif bakım | Evet | Evet | Evet | Evet | Terkedilmiş | Evet | Evet |
| Yayınlanmış fiyatlandırma | Evet ($2,998+) | Hayır ($15K–$210K/yıl) | Ücretsiz (MIT) | Evet (ücretsiz <$1M) | Ücretsiz | Ücretsiz (MIT) | Evet ($999+) |
| Süresiz lisans | Evet | Hayır (abonelik) | Yok | Yok | Yok | Yok | Evet |
| AGPL'siz | Evet | Hayır (ticari gerektirir) | Evet | Evet | Evet | Evet | Evet |
*PDFSharp bazı yapılandırmalarla platforma özgü sorunları belgelemiştir.
Performans Karşılaştırması
Orta seviye bir bulut VM'si (4 çekirdek CPU, 8GB RAM) üzerinde 200 elementlik HTML fatura şablonu ile test edildi, ısınma sonrasında 50 iterasyon üzerinden ortalandi:
| Senaryo | IronPDF | Puppeteer Sharp | iText pdfHTML | wkhtmltopdf |
|---|---|---|---|---|
| Basit HTML sayfası | ~150ms | ~500ms | ~200ms | ~200ms |
| Karmaşık CSS yerleşimi (Flexbox/Grid) | ~250ms | ~600ms | Başarısız/Kısmi | ~400ms (bozuk) |
| JavaScriptağırlıklı sayfa | ~350ms | ~800ms | Başarısız | Başarısız/Kısmi |
| İşlem başına bellek | ~80MB | ~150MB | ~60MB | ~50MB |
| Soğuk başlangıç (ilk nesil) | 2-5s | 3-8s | <1s | <1s |
iText ve wkhtmltopdf, bir tarayıcı motoru başlatmadıkları için daha hızlı soğuk başlangıçlar gösterir — ancak aynı içeriği işleyemezler. Performans karşılaştırması, sadece tüm kütüphanelerin doğru çıktı ürettiği senaryolar için anlamlıdır.
Aynı Fatura, Üç Kütüphane ile Kod Karşılaştırması
Bu kütüphaneler arasındaki farklar, aynı belgeyi oluştururken en net şekilde görülür. İşte üç farklı şekilde üretilmiş bir fatura.
IronPDF— HTML/CSS Yaklaşımı
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 ClassQuestPDF— Akıcı API Yaklaşımı
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 ClassPDFSharp— Koordinat Çizim Yaklaşımı
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 ClassIronPDF versiyonu HTML/CSS kullanır — çoğu geliştiricinin zaten sahip olduğu beceriler.QuestPDFversiyonu, bir alan-özel akıcı API öğrenmeyi gerektirir ancak yapı sağlar. PdfSharp versiyonu, her piksel pozisyonunun manuel hesaplanmasını gerektirir — her sütun ofseti, her satır yüksekliği, her kenarlık ayrı ayrı çizilir.
Hangi Kütüphaneyi Seçmeliyim?
Bu kütüphaneleri değerlendirirken karar ağacı oldukça basittir:
Modern CSS ile HTML'den PDF'ye mi ihtiyaç var? Pratik seçeneklerIronPDFya daPuppeteerSharp.IronPDFChromium'u dahili olarak işler;PuppeteerSharp, harici tarayıcı süreçlerini yönetmenizi gerektirir.wkhtmltopdfyeni projeler için bir seçenek değildir. iText'in pdfHTML'i Flexbox veya Grid'i işleyemez.
Verilerden programatik olarak belgeler oluşturma, HTML kullanmadan? QuestPDF'nin akıcı API'si verimli ve iyi tasarlanmıştır. PdfSharp, daha düşük seviyeli kontrol sağlar ama eşdeğer yerleşimler için önemli ölçüde daha fazla kod gerektirir.
Çok platformlu dağıtım (Linux, Docker, bulut)? IronPDF,QuestPDFvePuppeteer SharpLinux üzerinde libgdiplus bağımlılığı olmadan çalışır. Aspose.PDF, Linux üzerinde belgelenmiş bellek sızıntılarına sahiptir. PdfSharp, bilinen sorunlarla kısmi platform desteğine sahiptir.
Lisanslama kısıtlamaları? PdfSharp (MIT) vePuppeteer Sharp(MIT), koşulsuz olarak ücretsizdir.QuestPDF1 milyon dolarlık gelirin altında ücretsizdir.iTextAGPL uyumluluğu ya da ticari lisanslama gerektirir (yıllık 15K–210K$). IronPDF'nin süresiz lisansı $2,998 fiyatıyla başlar.Aspose~$999'dan başlar.
Karar Vermeden Önce
Gerçek içeriğinizle test edin, 'Merhaba Dünya' ile değil. Hedef platformunuza erken dağıtım yapın. 100+ belge üzerinden bellek ölçün, bir belge değil. Lisans metnini hukuki ekibinizle birlikte tamamen okuyun. Sunucusuz hedefliyorsanız soğuk başlangıç gecikmesini kontrol edin.
IronPDF, denemeniz için tüm işlevselliği ile bir deneme sürümü sunar.
