KARşıLAşTıRMA

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 IronPdf

Bir 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")
$vbLabelText   $csharpLabel

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:

KriterNe YapmalıNeden Önemlidir
HTML/CSS renderlemesiGerç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ütmeChart.js veya dinamik tablo içeriği ile test edinJS desteği olmayan kütüphaneler boş bölümler üretir
Lisanslama modeliLisansın tamamını okuyun, yalnızca özeti değilAGPL, bütün uygulamanızı açık kaynak yapmanızı gerektirir
Platform desteğiHedef Linux/Docker/ARM64 ortamınıza dağıtınWindows başarısı, Linux davranışını öngörmez
Yük altındaki bellekBir döngüde 100+ doküman oluşturunTek doküman testleri, üretim sunucularını çökertecek sızıntıları gizler
Yayınlanmış fiyatlandırmaFiyatlandı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")
$vbLabelText   $csharpLabel

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
$vbLabelText   $csharpLabel

Ü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ı

ÖzellikIronPDFiTextPDFSharpQuestPDFwkhtmltopdfPuppeteerAspose
HTML'den PDF'yeTam (Chromium)Sınırlı (CSS 2.1)HayırHayırKullanım dışıTam (Chrome)Sınırlı
CSS Flexbox/GridEvetHayırHayırHayırHayırEvetHayır
JavaScriptEvetHayırHayırHayırSınırlıEvetHayır
Linux (libgdiplus yok)EvetEvetKısmi*EvetYokEvetHayır
Docker dağıtımıStandart .NET imajıStandartKısmi*StandartKarmaşıkKarmaşıklibgdiplus gerektirir
Aktif bakımEvetEvetEvetEvetTerkedilmişEvetEvet
Yayınlanmış fiyatlandırmaEvet ($2,998+)Hayır ($15K–$210K/yıl)Ücretsiz (MIT)Evet (ücretsiz <$1M)ÜcretsizÜcretsiz (MIT)Evet ($999+)
Süresiz lisansEvetHayır (abonelik)YokYokYokYokEvet
AGPL'sizEvetHayır (ticari gerektirir)EvetEvetEvetEvetEvet

*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:

SenaryoIronPDFPuppeteer SharpiText pdfHTMLwkhtmltopdf
Basit HTML sayfası~150ms~500ms~200ms~200ms
Karmaşık CSS yerleşimi (Flexbox/Grid)~250ms~600msBaşarısız/Kısmi~400ms (bozuk)
JavaScriptağırlıklı sayfa~350ms~800msBaşarısızBaşarısız/Kısmi
İşlem başına bellek~80MB~150MB~60MB~50MB
Soğuk başlangıç (ilk nesil)2-5s3-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 Class
$vbLabelText   $csharpLabel

QuestPDF— 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 Class
$vbLabelText   $csharpLabel

PDFSharp— 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 Class
$vbLabelText   $csharpLabel

IronPDF 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.

Lütfen dikkate alınApryse, Aspose, DinkToPdf, NReco, PDFSharp, PuppeteerSharp, QuestPDF, iText, ve wkhtmltopdf, ilgili sahiplerinin tescilli markalarıdır. Bu site, Apryse,AsposePty Ltd, CodeFlint, DinkToPdf, NReco, PDFTron, PuppeteerSharp, empira Software GmbH,iTextGroup veyawkhtmltopdfile bağlantılı, onaylı ya da sponsorlu değildir. Tüm ürün adları, logolar ve markalar kendi sahiplerine aittir. Karşılaştırmalar, yalnızca bilgilendirme amaçlıdır ve yazı sırasında halka açık bilgilerle alakalı olarak yansıtılmaktadır.