KARşıLAşTıRMA

C#'ta HTML'den PDF'e - Kütüphane Seçeneklerinin Gerçekliği

C#'da HTML'yi PDF'ye dönüştürmek, aslında HTML'yi render'layan bir kütüphane gerektirir — etiketler alt kümesinin bir ayrıştırıcısı ve CSS 2.1'i tahmin edeni değil. Stack Overflow başlıklarında ve Reddit tartışmalarında önerilen çoğu kütüphane ya modern CSS'yi render'layamaz, ticari kullanım için diskalifiye eden lisans kısıtlamaları taşır veya düzeltilmemiş güvenlik açığıyle terk edilmiş durumdadır.

Bu makale, geliştiricilerin 'HTML to PDF C#' aradıklarında karşıladıkları kütüphaneleri karşılaştırır, her birinin neyi renderlayabileceğini ve render'layamayacağını belgelendirir, metodoloji ile performans kriterleri içerisindedir ve her yaklaşımın gerçek operasyonel maliyetini gösterir.

Quickstart: HTML'den PDF'ye in C

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

NuGet üzerinden yükleyin: Install-Package IronPdf. Ek bağımlılıklar olmadan Windows, Linux, macOS ve Docker'a dağıtılır.

HTML'den PDF'ye Dönüşüm Neden Zor?

HTML'i doğru şekilde PDF'ye renderlemek, bir web tarayıcısının kullandığı beş bileşeni aynı şekilde uygulamayı gerektirir: bir HTML ayrıştırıcı, bir CSS motoru (Flexbox, Grid, kaskad, özgüllük ve medya sorguları dahil), bir JavaScript çalışma zamanı, bir düzen motoru ve bunu PDF'ye alta piksellik hassasiyette birleştiren bir render hattı.

Geleneksel PDF kütüphaneleri ilk iki bileşeni kısmen uygular ve JavaScript'i tamamen geçer. Bu nedenle basit HTML ile başa çıkabilirler ancak modern bir tarayıcının doğru render'layacağı her şeyde kırılırlar. Tarayıcı çıktısını eşleştirmenin tek yolu bir tarayıcı motoru kullanmaktır.

Hangi Kütüphaneler Gerçekten HTML'yi PDF'ye Dönüştürür?

wkhtmltopdfSarmalayıcıları — DLL Yükleme Hatası Ekosistemi

Bu makalelere geliştiricileri getiren en yaygın arama sorgusu, şu varyasyonlardan biridir:

System.DllNotFoundException: 'libwkhtmltox' DLL'i yüklenemedi

Platforma özgü varyantlar şunlardır:

'wkhtmltox' veya bağımlılıklarından birini yükleme başarısız
    (Linux — libwkhtmltox.so not found)

Belirtilen modül bulunamadı. (0x8007007E)
    (Windows — wkhtmltox.dll path not configured)

dyld: Kütüphane yüklenemedi: libwkhtmltox.dylib
    (macOS — not supported on ARM64/Apple Silicon)

Bu hatalar DinkToPdf, NReco.PdfGenerator, WkHtmlToXSharp ve aynı terkedilmiş ikili etrafındaki diğer C# sarmalayıcılarından gelmektedir. wkhtmltopdf GitHub organizasyonu Temmuz 2024'te arşivlendi. Altında yatan QtWebKit motoru Qt tarafından 2015'te kaldırıldı. proje durum sayfası bunu açıkça kullanım dışı olarak işaretliyor.

DLL yükleme sorunlarının ötesinde, render motoru yaklaşık olarak Safari 2011 kapasitesinde donmuş durumda. Flexbox yok, Grid yok, sınırlı CSS3, güvensiz JavaScript. Ve yamalı olmayan kritik zafiyetler var: ⟨a href="https://github.com/wkhtmltopdf/wkhtmltopdf/issues/5249"⟩CVE-2022-35583⟨/a⟩ (CVSS 9.8), özel olarak oluşturulmuş HTML aracılığıyla AWS kimlik bilgilerini dışa sızdırabilen SSRF saldırılarına olanak tanır.

wkhtmltopdf'nin zamanı geçti. DLL yükleme hataları daha derin bir sorunun belirtisidir: ileriye yönelik hiçbir yolu olmayan terk edilmiş bir yazılıma bağımlısınız.

iText(pdfHTML Eklentisi) — Sınırlı CSS, AGPL Lisanslı

iText'in pdfHTML modülü, HTML'yi özel bir ayrıştırıcı kullanarak PDF'ye dönüştürür — bir tarayıcı motoru değil. Temel HTML/CSS kodlarını işler ancak Flexbox, Grid veya JavaScript'i render etmez.

Hata modu sessizdir: pdfHTML, desteklenmeyen CSS ile karşılaştığında istisnalar fırlatmaz. Yapabildiklerini işler ve geri kalanını yoksayar. display: flex, gap: 20px ve justify-content: space-between ile bir konteyner, arada boşluk olmadan dikey istiflenmiş elemanlar olarak işler. Geliştiriciler bunu entegrasyon sonrasında keşfeder, değilken.

Lisanslama: AGPL — tüm ağ erişim uygulanabilir uygulamanızı açık kaynak haline getirmenizi veya ticari lisans satın almanızı gerektirir. Fiyatlandırma yayınlanmamıştır; üçüncü parti veriler yıllık 15.000–210.000 dolar arasını gösterir.

Bellek Kullanımı Nasıl Karşılaştırılır?

iText'in pdfHTML, işlemler için tüm belgeyi belleğe yükler. Tipik iş belgeleri için bu yönetilebilir ancak gömülü resimlerle büyük HTML raporları, yayınlama yaklaşımlarıyla karşılaştırıldığında önemli bellek baskısına neden olabilir.

NedenPDFSharpHTML Desteklemez?

PdfSharp "HTML to PDF" arama sonuçlarında popülerliği (34,9 milyon NuGet indirme) ve sıkça önerilmesi nedeniyle görünür. Ancak PdfSharp'nin bir HTML ayrıştırıcısı yok. Koordinat tabanlı bir çizim API'si sağlar: açık X/Y pozisyonları ile DrawString(), DrawRectangle(), DrawImage().

Sık önerilen geçici çözüm, HtmlRenderer.PdfSharp, yalnızca HTML 4.01 ve CSS Seviye 2'yi destekler. HTML'iniz 2010 sonrasında tanıtılan bir CSS özelliği kullanıyorsa — Flexbox (2012), Grid (2017), özel özellikler (2017), border-radius (2011) — işlenmeyecektir.

PdfSharp'yi seçen ve HTML desteği bekleyen geliştiriciler, ya her elemanı koordinat tabanlı kodla elle konumlandırır ya da HTML işleme için ikinci bir kütüphane ekler — bu noktada PdfSharp gereksiz olur.

Puppeteer SharpNeden Kaynak Yoğun?

Puppeteer Sharp, Başsız Chrome'u .NET bağlamaları aracılığıyla kontrol eder. Render doğruluğu Chrome ile eşleşmektedir çünkü Chrome'dur. Maliyet, operasyoneldir: dış tarayıcı süreçlerini yönetirsiniz.

ÜretimPuppeteer Sharpdağıtımı, öğreticilerdeki 5 satırlık örnek kod değil, eşzamanlı PDF üretimi için gereken tarayıcı havuzu kodu olarak işte böyle görünüyor:

using PuppeteerSharp;
using System.Collections.Concurrent;

public class PdfBrowserPool : IAsyncDisposable
{
    private readonly ConcurrentBag<IBrowser> _available = new();
    private readonly SemaphoreSlim _semaphore;
    private readonly int _maxBrowsers;

    public PdfBrowserPool(int maxBrowsers = 4)
    {
        _maxBrowsers = maxBrowsers;
        _semaphore = new SemaphoreSlim(maxBrowsers, maxBrowsers);
    }

    public async Task InitializeAsync()
    {
        await new BrowserFetcher().DownloadAsync(); // ~280MB download
        for (int i = 0; i < _maxBrowsers; i++)
        {
            var browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                Headless = true,
                Args = new[] { "--no-sandbox", "--disable-setuid-sandbox",
                               "--disable-dev-shm-usage" }
            });
            _available.Add(browser);
        }
    }

    public async Task<byte[]> ConvertHtmlToPdf(string html)
    {
        await _semaphore.WaitAsync();
        IBrowser browser = null;
        try
        {
            if (!_available.TryTake(out browser))
                throw new InvalidOperationException("No browser available");

            await using var page = await browser.NewPageAsync();
            await page.SetContentAsync(html, new NavigationOptions
            {
                WaitUntil = new[] { WaitUntilNavigation.Networkidle0 }
            });
            var result = await page.PdfAsync(new PdfOptions
            {
                Format = PaperFormat.A4,
                PrintBackground = true
            });
            return result;
        }
        catch (Exception ex) when (ex is NavigationException or TargetClosedException)
        {
            // Browser crashed — replace it
            browser?.Dispose();
            browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                Headless = true,
                Args = new[] { "--no-sandbox", "--disable-setuid-sandbox" }
            });
            throw; // Re-throw after recovery
        }
        finally
        {
            if (browser != null) _available.Add(browser);
            _semaphore.Release();
        }
    }

    public async ValueTask DisposeAsync()
    {
        foreach (var browser in _available)
        {
            await browser.CloseAsync();
            browser.Dispose();
        }
    }
}
using PuppeteerSharp;
using System.Collections.Concurrent;

public class PdfBrowserPool : IAsyncDisposable
{
    private readonly ConcurrentBag<IBrowser> _available = new();
    private readonly SemaphoreSlim _semaphore;
    private readonly int _maxBrowsers;

    public PdfBrowserPool(int maxBrowsers = 4)
    {
        _maxBrowsers = maxBrowsers;
        _semaphore = new SemaphoreSlim(maxBrowsers, maxBrowsers);
    }

    public async Task InitializeAsync()
    {
        await new BrowserFetcher().DownloadAsync(); // ~280MB download
        for (int i = 0; i < _maxBrowsers; i++)
        {
            var browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                Headless = true,
                Args = new[] { "--no-sandbox", "--disable-setuid-sandbox",
                               "--disable-dev-shm-usage" }
            });
            _available.Add(browser);
        }
    }

    public async Task<byte[]> ConvertHtmlToPdf(string html)
    {
        await _semaphore.WaitAsync();
        IBrowser browser = null;
        try
        {
            if (!_available.TryTake(out browser))
                throw new InvalidOperationException("No browser available");

            await using var page = await browser.NewPageAsync();
            await page.SetContentAsync(html, new NavigationOptions
            {
                WaitUntil = new[] { WaitUntilNavigation.Networkidle0 }
            });
            var result = await page.PdfAsync(new PdfOptions
            {
                Format = PaperFormat.A4,
                PrintBackground = true
            });
            return result;
        }
        catch (Exception ex) when (ex is NavigationException or TargetClosedException)
        {
            // Browser crashed — replace it
            browser?.Dispose();
            browser = await Puppeteer.LaunchAsync(new LaunchOptions
            {
                Headless = true,
                Args = new[] { "--no-sandbox", "--disable-setuid-sandbox" }
            });
            throw; // Re-throw after recovery
        }
        finally
        {
            if (browser != null) _available.Add(browser);
            _semaphore.Release();
        }
    }

    public async ValueTask DisposeAsync()
    {
        foreach (var browser in _available)
        {
            await browser.CloseAsync();
            browser.Dispose();
        }
    }
}
Imports PuppeteerSharp
Imports System.Collections.Concurrent
Imports System.Threading

Public Class PdfBrowserPool
    Implements IAsyncDisposable

    Private ReadOnly _available As New ConcurrentBag(Of IBrowser)()
    Private ReadOnly _semaphore As SemaphoreSlim
    Private ReadOnly _maxBrowsers As Integer

    Public Sub New(Optional maxBrowsers As Integer = 4)
        _maxBrowsers = maxBrowsers
        _semaphore = New SemaphoreSlim(maxBrowsers, maxBrowsers)
    End Sub

    Public Async Function InitializeAsync() As Task
        Await (New BrowserFetcher()).DownloadAsync() ' ~280MB download
        For i As Integer = 0 To _maxBrowsers - 1
            Dim browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {
                .Headless = True,
                .Args = New String() {"--no-sandbox", "--disable-setuid-sandbox", "--disable-dev-shm-usage"}
            })
            _available.Add(browser)
        Next
    End Function

    Public Async Function ConvertHtmlToPdf(html As String) As Task(Of Byte())
        Await _semaphore.WaitAsync()
        Dim browser As IBrowser = Nothing
        Try
            If Not _available.TryTake(browser) Then
                Throw New InvalidOperationException("No browser available")
            End If

            Await Using page = Await browser.NewPageAsync()
                Await page.SetContentAsync(html, New NavigationOptions With {
                    .WaitUntil = New WaitUntilNavigation() {WaitUntilNavigation.Networkidle0}
                })
                Dim result = Await page.PdfAsync(New PdfOptions With {
                    .Format = PaperFormat.A4,
                    .PrintBackground = True
                })
                Return result
            End Using
        Catch ex As Exception When TypeOf ex Is NavigationException OrElse TypeOf ex Is TargetClosedException
            ' Browser crashed — replace it
            browser?.Dispose()
            browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {
                .Headless = True,
                .Args = New String() {"--no-sandbox", "--disable-setuid-sandbox"}
            })
            Throw ' Re-throw after recovery
        Finally
            If browser IsNot Nothing Then _available.Add(browser)
            _semaphore.Release()
        End Try
    End Function

    Public Async Function DisposeAsync() As ValueTask Implements IAsyncDisposable.DisposeAsync
        For Each browser In _available
            Await browser.CloseAsync()
            browser.Dispose()
        Next
    End Function
End Class
$vbLabelText   $csharpLabel

Bu, tek bir PDF üretmeden önce ~60 satır altyapı kodudur. Ayrıca bellek sızıntısı izlemesi (Zamanla Chromium süreçleri bellek biriktirir), sağlık kontrolleri ve 20+ Chromium bağımlılığı ile bir Dockerfile gereklidir. Docker görüntü boyutu 300–400MB artar.

Bunu eşdeğerIronPDFyaklaşımı ile karşılaştırın:

using IronPdf;

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
// Browser pooling, process management, crash recovery — handled internally
using IronPdf;

var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
// Browser pooling, process management, crash recovery — handled internally
Imports IronPdf

Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
' Browser pooling, process management, crash recovery — handled internally
$vbLabelText   $csharpLabel

Puppeteer Sharp, ekibiniz operasyonel yükü absorbe edebilirse uygulanabilir. Tarayıcı altyapısına değil uygulamaya odaklanmak isteyen ekipler içinIronPDFaynı render işlemini dahili olarak ele alır.

QuestPDFNeden HTML'yi Dönüştüremez?

QuestPDF, Reddit ve Stack Overflow'da neredeyse her 'HTML to PDF C#' tartışmasında görünmektedir. Bu tutarlı bir model oluşturur: geliştiriciler HTML dönüştürme bekleyerek QuestPDF'yi satın alır veya entegre eder, ardından hiç HTML render etmediğini keşfeder.

QuestPDF programatik belge oluşturma için akıcı bir C# API'sidir. Pozisyonu açıkça 'HTML-to-PDF dönüşümüyle mücadele etmemeyi bırak' şeklindedir — HTML yaklaşımını C# kodu ile değiştirir. Bu kasti bir tasarım tercihi. 2022 ile 2024 arasındaki GitHub tartışmaları geliştiricilerin bu durumu uygulanmayı başlattıklarında keşfettiklerini göstermektedir. Yönetici ekibi sürekli olarak HTML desteğinin planlanmadığını doğrular.

Mevcut iş akışınızda HTML şablonlar — faturalar için Razor görünümleri, raporlar için gösterge paneli HTML'leri, arşivleme için web içeriği — kullanılıyorsa,QuestPDFher şablonu C# akıcı API kodu olarak yeniden yazmayı gerektirir. Yapılandırılmış verilerle sıfırdan belge düzenleri oluşturduğunuz yeni projeler için QuestPDF'nin API'si iyi tasarlanmış ve etkili.

Topluluk Lisansı, yıllık brüt geliri 1M$ altında olan işletmeleri kapsar. Bunun üzerinde ticari lisanslama gereklidir.

Aspose.PDF Ne Durumda?

Aspose.PDF, ticari lisanslama ile geniş bir PDF işlevselliği sağlar (geliştirici başına ~999 dolardan başlar). HTML dönüştürme, bir tarayıcı yerine özel bir motor kullanmaktadır — iText'e benzer biçimde, temel HTML'i işler ancak modern CSS özelliklerini doğru bir şekilde render etmez.

Asıl endişe platform istikrarıdır: Aspose, Linux üzerinde libgdiplus gerektiren System.Drawing.Common'a dayanır. Microsoft, bunu .NET 6+ üzerindeki non-Windows platformları için kullanımdan kaldırdı. Geliştiriciler, Windows üzerinde meydana gelmeyen Linux dağıtımlarına özgü bellek sızıntılarını bildirir. Yalnızca Windows ortamları için Aspose, yeterlidir. Çapraz platform ya da konteynırlaştırılmış dağıtımlar için bağımlılık zinciri sürekli risk yaratır.

IronPDFHTML-to-PDF Dönüşümünü Nasıl Yönetir?

IronPDF, Chromium'u doğrudan NuGet paketine gömüyor. CSS Flexbox, Grid, özel özellikler, @font-face, medya sorguları ve JavaScript, Chrome'da olduğu gibi çalışır. Çıktı tarayıcı ile eşleşir çünkü aynı render motorunu kullanır.

using IronPdf;

var renderer = new ChromePdfRenderer();

string html = @"
<!DOCTYPE html>
<html>
<head>
    <style>
        :root { --primary: #2563eb; }
        body { font-family: 'Segoe UI', sans-serif; padding: 40px; }
        .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 20px; }
        .card {
            background: linear-gradient(135deg, #f8fafc, #e2e8f0);
            border-radius: 12px; padding: 24px; text-align: center;
        }
        .card h3 { color: #6b7280; font-size: 0.8rem; text-transform: uppercase; margin: 0; }
        .card .value { font-size: 2rem; font-weight: 700; color: var(--primary); }
        table { width: 100%; border-collapse: collapse; margin-top: 30px; }
        th { background: var(--primary); color: white; padding: 12px; text-align: left; }
        td { padding: 10px; border-bottom: 1px solid #e5e7eb; }
    </style>
</head>
<body>
    <div class='grid'>
        <div class='card'><h3>Revenue</h3><div class='value'>$1.2M</div></div>
        <div class='card'><h3>Users</h3><div class='value'>45,230</div></div>
        <div class='card'><h3>Uptime</h3><div class='value'>99.97%</div></div>
    </div>
    <table>
        <tr><th>Product</th><th>Revenue</th><th>Growth</th></tr>
        <tr><td>Enterprise</td><td>$680K</td><td>+12%</td></tr>
        <tr><td>Professional</td><td>$356K</td><td>+8%</td></tr>
    </table>
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("report.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();

string html = @"
<!DOCTYPE html>
<html>
<head>
    <style>
        :root { --primary: #2563eb; }
        body { font-family: 'Segoe UI', sans-serif; padding: 40px; }
        .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 20px; }
        .card {
            background: linear-gradient(135deg, #f8fafc, #e2e8f0);
            border-radius: 12px; padding: 24px; text-align: center;
        }
        .card h3 { color: #6b7280; font-size: 0.8rem; text-transform: uppercase; margin: 0; }
        .card .value { font-size: 2rem; font-weight: 700; color: var(--primary); }
        table { width: 100%; border-collapse: collapse; margin-top: 30px; }
        th { background: var(--primary); color: white; padding: 12px; text-align: left; }
        td { padding: 10px; border-bottom: 1px solid #e5e7eb; }
    </style>
</head>
<body>
    <div class='grid'>
        <div class='card'><h3>Revenue</h3><div class='value'>$1.2M</div></div>
        <div class='card'><h3>Users</h3><div class='value'>45,230</div></div>
        <div class='card'><h3>Uptime</h3><div class='value'>99.97%</div></div>
    </div>
    <table>
        <tr><th>Product</th><th>Revenue</th><th>Growth</th></tr>
        <tr><td>Enterprise</td><td>$680K</td><td>+12%</td></tr>
        <tr><td>Professional</td><td>$356K</td><td>+8%</td></tr>
    </table>
</body>
</html>";

var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("report.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

Dim html As String = "
<!DOCTYPE html>
<html>
<head>
    <style>
        :root { --primary: #2563eb; }
        body { font-family: 'Segoe UI', sans-serif; padding: 40px; }
        .grid { display: grid; grid-template-columns: repeat(auto-fit, minmax(180px, 1fr)); gap: 20px; }
        .card {
            background: linear-gradient(135deg, #f8fafc, #e2e8f0);
            border-radius: 12px; padding: 24px; text-align: center;
        }
        .card h3 { color: #6b7280; font-size: 0.8rem; text-transform: uppercase; margin: 0; }
        .card .value { font-size: 2rem; font-weight: 700; color: var(--primary); }
        table { width: 100%; border-collapse: collapse; margin-top: 30px; }
        th { background: var(--primary); color: white; padding: 12px; text-align: left; }
        td { padding: 10px; border-bottom: 1px solid #e5e7eb; }
    </style>
</head>
<body>
    <div class='grid'>
        <div class='card'><h3>Revenue</h3><div class='value'>$1.2M</div></div>
        <div class='card'><h3>Users</h3><div class='value'>45,230</div></div>
        <div class='card'><h3>Uptime</h3><div class='value'>99.97%</div></div>
    </div>
    <table>
        <tr><th>Product</th><th>Revenue</th><th>Growth</th></tr>
        <tr><td>Enterprise</td><td>$680K</td><td>+12%</td></tr>
        <tr><td>Professional</td><td>$356K</td><td>+8%</td></tr>
    </table>
</body>
</html>"

Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("report.pdf")
$vbLabelText   $csharpLabel

Bu, minmax, özel özellikler, linear-gradient, border-radius ve :root seçicileri ile CSS Grid kullanır. Bu özelliklerin her biri iText'in pdfHTML'inde başarısız olur, wkhtmltopdf'de bozulur ve PdfSharp veya QuestPDF'de mevcut değildir.

Diğer Kütüphanelerden Nasıl Geçiş Yapılır?

iText veya wkhtmltopdf'den geçen ekipler için,IronPDFdoğrudan URL'leri kabul eder — mevcut iş akışınız HTML dosyaları oluşturduğunda veya sayfalar sunduğunda kullanışlıdır:

using IronPdf;

var renderer = new ChromePdfRenderer();

// Convert from URL — useful when migrating fromwkhtmltopdfURL-based workflows
var pdf = renderer.RenderUrlAsPdf("https://localhost:5001/reports/quarterly");
pdf.SaveAs("report.pdf");

// Convert from local HTML file
var pdfFromFile = renderer.RenderHtmlFileAsPdf("templates/invoice.html");
pdfFromFile.SaveAs("invoice.pdf");
using IronPdf;

var renderer = new ChromePdfRenderer();

// Convert from URL — useful when migrating fromwkhtmltopdfURL-based workflows
var pdf = renderer.RenderUrlAsPdf("https://localhost:5001/reports/quarterly");
pdf.SaveAs("report.pdf");

// Convert from local HTML file
var pdfFromFile = renderer.RenderHtmlFileAsPdf("templates/invoice.html");
pdfFromFile.SaveAs("invoice.pdf");
Imports IronPdf

Dim renderer As New ChromePdfRenderer()

' Convert from URL — useful when migrating from wkhtmltopdf URL-based workflows
Dim pdf = renderer.RenderUrlAsPdf("https://localhost:5001/reports/quarterly")
pdf.SaveAs("report.pdf")

' Convert from local HTML file
Dim pdfFromFile = renderer.RenderHtmlFileAsPdf("templates/invoice.html")
pdfFromFile.SaveAs("invoice.pdf")
$vbLabelText   $csharpLabel

Kullanım

IronPDF, Windows (x64), Linux (x64, ARM64), macOS (x64, Apple Silicon) ve Docker konteynerlerinde çalışır. Docker yapılandırması standart bir .NET görüntüsüdür:

FROM mcr.microsoft.com/dotnet/aspnet:8.0
WORKDIR /app
COPY . .
ENTRYPOINT ["dotnet", "MyApp.dll"]

Chromium kurulumu yok, yerel kütüphane bağımlılıkları yok, sandbox yapılandırması yok.

Lisanslama: $2,998'dan başlayan Süresiz Lisanslar. ironpdf.com adresinde yayınlanan fiyatlar. AGPL yok, belge başına ücret yok, gelir eşik limitleri yok.

Performans Kıyaslamaları

Ubuntu 22.04 ve .NET 8 çalıştıran bir Standard_D4s_v3 Azure VM (4 vCPU, 16GB RAM) üzerinde test edildi. Test belgesi: CSS Grid düzeni, gömülü resimler ve JavaScript tarafından üretilen bir grafik içeren 200 öğelik bir HTML fatura şablonu. Ölçümlerin her biri, 5 yineleme ısınma döneminin ardından 50 yineleme üzerinde ortalamasını aldık.

Senaryo IronPDF Puppeteer Sharp iText pdfHTML wkhtmltopdf
Basit HTML (JS olmadan) ~150ms ~500ms ~200ms ~200ms
Karmaşık CSS (Flexbox/Grid) ~250ms ~600ms Bozuk çıktı Bozuk çıktı
JavaScript-render edilmiş içerik ~350ms ~800ms Başarısız (JS motoru yok) 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 vewkhtmltopdfdaha hızlı soğuk başlatma süreleri gösterir çünkü bir tarayıcı motoru başlatmazlar. Ancak bu karşılaştırma yalnızca tüm kütüphanelerin doğru çıktı ürettiği senaryolar için anlamlıdır — ve karmaşık CSS veya JavaScript içeriği için, yalnızcaIronPDFvePuppeteer Sharpkullanılabilir sonuçlar üretir.

Not: Bunlar belirtilen donanım üzerindeki tipik gözlemleri temsil eder. Performansınız, HTML karmaşıklığı, belge uzunluğu ve sunucu kaynaklarıyla değişiklik gösterecektir. Gerçek iş yüklerinizi test etmeden önce kararlar vermeyin.

Özellik Karşılaştırması

Özellik IronPDF iText Puppeteer Sharp wkhtmltopdf PDFSharp QuestPDF Aspose
HTML'den PDF'ye Evet (Chromium) Sınırlı (CSS 2.1) Evet (Chrome) Kullanım dışı Hayır Hayır Sınırlı
CSS Flexbox/Grid Evet Hayır Evet Hayır Hayır Hayır Hayır
JavaScript yürütme Evet Hayır Evet Sınırlı Hayır Hayır Hayır
Çapraz platform (libgdiplus yok) Evet Evet Evet Yok Kısmi Evet Hayır
Yayınlanmış fiyatlandırma $2,998+ Hayır ($15K–$210K/yıl) Ücretsiz (MIT) Ücretsiz Ücretsiz (MIT) Ücretsiz <$1M 999$+
Aktif bakım Evet Evet Evet Terkedilmiş Evet Evet Evet

Hangi Kütüphaneyi Seçmeliyim?

Modern CSS ile HTML şablonları → IronPDF, dış işlem yönetimi olmadan gömülü Chromium sağlar. Ekibiniz tarayıcı altyapısını yönetebiliyorsa,Puppeteer Sharpuygun bir alternatif.

Verilere dayalı, HTML'siz programatik belge oluşturma → QuestPDF, zarif bir akıcı API sunar. HTML dönüşümü bekleyerek tercih etmeyin.

Basit PDF manipülasyonu (birleştirme, bölme, filigran) → PDFSharp ücretsizdir ve HTML dışı görevler için yeteneklidir.

Yeni projeler için kaçınılacaklar:wkhtmltopdf(terk edilmiş, CVE'ler), ticari lisans olmadaniText(AGPL tuzağı), Linux üzerindeAspose(bellek sızıntıları).

Asıl soru, iş akışınızın HTML şablonları kullanıp kullanmadığıdır. Eğer kullanıyorsa, yalnızca Chromium tabanlı çözümler modern CSS ile doğru çıktı üretir. Eğer kullanmıyorsa, tercih API tercihi ve lisanslama kısıtlamalarına bağlıdır.

Lütfen dikkate alınAspose, DinkToPdf, NReco, PDFSharp, PuppeteerSharp, QuestPDF,iTextvewkhtmltopdfkendi sahiplerinin tescilli ticari markalarıdır. Bu siteAsposePty Ltd, CodeFlint, DinkToPdf, NReco, PuppeteerSharp, empira Software GmbH,iTextGroup veyawkhtmltopdfile ilişkili değil, onaylanmamış veya sponsor olunmamıştır. 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.