PuppeteerSharp에서 IronPDF로의 마이그레이션 방법 (C#)
PuppeteerSharp에서 IronPDF로 마이그레이션을 통해 300MB 이상의 종속성을 가지는 브라우저 자동화 도구에서 자동 메모리 관리를 제공하는 목적 지향적 PDF 라이브러리로 PDF 생성 워크플로우를 변환합니다. 이 가이드는 Chromium 다운로드를 제거하고, 메모리 누수 문제를 해결하며, 종합적인 PDF 조작 기능을 제공하는 완벽하고 단계별 마이그레이션 경로를 제공합니다.
PuppeteerSharp에서 IronPDF로 마이그레이션해야 하는 이유
PuppeteerSharp이해하기
PuppeteerSharp는 Google's Puppeteer의 .NET 포트로, C#에 브라우저 자동화 기능을 제공합니다. Chrome의 내장된 PDF로 인쇄 기능을 사용하여 PDF를 생성합니다—브라우저에서 Ctrl+P를 누르는 것과 동일합니다. 이것은 화면에서 보이는 것과 다른 종이 최적화 출력물을 생성합니다.
PuppeteerSharp는 문서 생성을 위한 것이 아닌 웹 테스트와 스크래핑을 위해 설계되었습니다. PuppeteerSharp를 사용하여 PDF를 생성하면 상당한 생산 문제를 야기합니다.
브라우저 자동화 문제
PuppeteerSharp는 문서 생성이 아닌 브라우저 자동화를 위해 설계되었습니다. 따라서 PDF에 사용하는데 근본적인 문제가 발생합니다:
-
300MB 이상의 Chromium 다운로드가 처음 사용 전에 필요합니다. PuppeteerSharp의 중요한 단점은 Chromium 바이너리로 인해 배포 크기가 크다는 것입니다. 이 큰 크기는 Docker 이미지를 늘리고 서버리스 환경에서 콜드 스타트 문제를 일으킬 수 있습니다.
-
로드 중 메모리 누수로 인해 브라우저를 수동으로 회수해야 합니다. 무거운 로드에서 PuppeteerSharp는 메모리 누수가 발생할 수 있습니다. 브라우저 인스턴스의 메모리 누적은 프로세스 관리 및 회수를 위한 수동 개입이 필요합니다.
-
브라우저 수명주기 관리를 위한 복잡한 비동기 패턴.
-
PDF로 인쇄 출력 (화면 캡처가 아닌 Ctrl+P와 동등). 레이아웃이 다시 흐르고, 기본적으로 배경이 생략되며, 출력은 브라우저 뷰포트를 일치시키기보다는 인쇄를 위해 페이지화됩니다.
-
PDF/A 또는 PDF/UA 지원 없음 (규정 준수 요구 사항). PuppeteerSharp는 PDF/A(아카이브용) 또는 PDF/UA(접근성) 규격 문서를 생성할 수 없습니다.
- PDF 조작 불가 - 생성만 가능, 병합/분할/편집 불가. PuppeteerSharp는 PDF 생성을 효율적으로 하지만, 병합, 분할, 보안 강화 또는 편집 같은 추가 조작 능력이 없습니다.
PuppeteerSharpvsIronPDF비교
| 측면 | PuppeteerSharp | IronPDF |
|---|---|---|
| 주된 목적 | 브라우저 자동화 | PDF 생성 |
| Chromium 의존성 | 300MB+ 별도 다운로드 | 내장 최적화 엔진 |
| API 복잡성 | 비동기 브라우저/페이지 생명주기 | 동기 단일 행 |
| 초기화 | BrowserFetcher.DownloadAsync() + LaunchAsync |
new ChromePdfRenderer() |
| 메모리 관리 | 수동 브라우저 재활용 필요 | 자동 |
| 로드 하의 메모리 | 500MB+ 누수 발생 | ~50MB 안정성 |
| 콜드 스타트 | 45+ 초 | ~20 초 |
| PDF/A 지원 | 사용 불가 | 지원됨 |
| PDF/UA 접근성 | 사용 불가 | 지원됨 |
| PDF 편집 | 사용 불가 | 병합, 분할, 스탬프, 편집 |
| 디지털 서명 | 사용 불가 | 지원됨 |
| 스레드 안전성 | 제한적 | 전체 |
| 전문가 지원 | Community | SLA가 포함된 상업용 |
플랫폼 지원
|라이브러리|.NET Framework 4.7.2|.NET Core 3.1|.NET 6-8|.NET 10| | --------- | :---: | :---: | :---: | :---: ||IronPDF| 전체 | 전체 | 전체 | 전체 ||PuppeteerSharp| 제한적 | 전체 | 전체 | 대기 중 | IronPDF의 광범위한 .NET 플랫폼 지원은 개발자가 다양한 환경에서 호환성 문제가 없이 이를 활용할 수 있도록 보장하여 2025년과 2026년을 위한 현대적인 .NET 애플리케이션에 유연한 선택을 제공합니다.
시작하기 전에
필수 조건
- .NET 환경: .NET Framework 4.6.2+ 또는 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 접근 권한: NuGet 패키지를 설치할 수 있는 능력
- IronPDF 라이선스: ironpdf.com에서 라이선스 키를 획득하세요
NuGet 패키지 변경 사항
# Remove PuppeteerSharp
dotnet remove package PuppeteerSharp
# Remove downloaded Chromium binaries (~300MB recovered)
# Delete the .local-chromium folder
# Add IronPDF
dotnet add package IronPdf
# Remove PuppeteerSharp
dotnet remove package PuppeteerSharp
# Remove downloaded Chromium binaries (~300MB recovered)
# Delete the .local-chromium folder
# Add IronPDF
dotnet add package IronPdf
IronPDF와 함께 BrowserFetcher.DownloadAsync() 불필요 - 렌더링 엔진이 자동으로 번들링됩니다.
라이선스 구성
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
// Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
' Add at application startup
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
완전한 API 참조
네임스페이스 변경
// Before: PuppeteerSharp
using PuppeteerSharp;
using PuppeteerSharp.Media;
using System.Threading.Tasks;
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;
// Before: PuppeteerSharp
using PuppeteerSharp;
using PuppeteerSharp.Media;
using System.Threading.Tasks;
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;
' Before: PuppeteerSharp
Imports PuppeteerSharp
Imports PuppeteerSharp.Media
Imports System.Threading.Tasks
' After: IronPDF
Imports IronPdf
Imports IronPdf.Rendering
핵심 API 매핑
| PuppeteerSharp API | IronPDF API | 노트 |
|---|---|---|
new BrowserFetcher().DownloadAsync() |
필요 없음 | 브라우저 다운로드 없음 |
Puppeteer.LaunchAsync(options) |
필요 없음 | 브라우저 관리 없음 |
browser.NewPageAsync() |
필요 없음 | 페이지 컨텍스트 없음 |
page.GoToAsync(url) |
renderer.RenderUrlAsPdf(url) |
직접 렌더링 |
page.SetContentAsync(html) |
renderer.RenderHtmlAsPdf(html) |
직접 렌더링 |
page.PdfAsync(path) |
pdf.SaveAs(path) |
렌더링 후 |
await page.CloseAsync() |
필요 없음 | 자동 정리 |
await browser.CloseAsync() |
필요 없음 | 자동 정리 |
PdfOptions.Format |
RenderingOptions.PaperSize |
용지 크기 |
PdfOptions.Landscape |
RenderingOptions.PaperOrientation |
방향 |
PdfOptions.MarginOptions |
RenderingOptions.MarginTop/Bottom/Left/Right |
개별 여백 |
PdfOptions.PrintBackground |
RenderingOptions.PrintHtmlBackgrounds |
배경 인쇄 |
PdfOptions.HeaderTemplate |
RenderingOptions.HtmlHeader |
HTML 헤더 |
PdfOptions.FooterTemplate |
RenderingOptions.HtmlFooter |
HTML 푸터 |
page.WaitForSelectorAsync() |
RenderingOptions.WaitFor.HtmlElementId |
요소 대기 |
코드 마이그레이션 예제
예제 1: 기본 HTML을 PDF로 변환
이전 (PuppeteerSharp):
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<h1>Hello World</h1><p>This is a PDF document.</p>");
await page.PdfAsync("output.pdf");
}
}
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<h1>Hello World</h1><p>This is a PDF document.</p>");
await page.PdfAsync("output.pdf");
}
}
Imports PuppeteerSharp
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim browserFetcher = New BrowserFetcher()
Await browserFetcher.DownloadAsync()
Using browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {
.Headless = True
})
Using page = Await browser.NewPageAsync()
Await page.SetContentAsync("<h1>Hello World</h1><p>This is a PDF document.</p>")
Await page.PdfAsync("output.pdf")
End Using
End Using
End Function
End Module
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF document.</p>");
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF document.</p>");
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main(args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Hello World</h1><p>This is a PDF document.</p>")
pdf.SaveAs("output.pdf")
End Sub
End Class
이 예제는 근본적인 아키텍처 차이를 보여줍니다. PuppeteerSharp는 여섯 개의 비동기 작업이 필요합니다: BrowserFetcher.DownloadAsync() (300MB 이상의 Chromium 다운로드), Puppeteer.LaunchAsync(), browser.NewPageAsync(), page.SetContentAsync(), 및 page.PdfAsync(), 그리고 적절한 처리를 위한 await using.
IronPDF는 이 모든 복잡성을 제거합니다: ChromePdfRenderer를 생성하고, RenderHtmlAsPdf()를 호출하고, SaveAs()를 실행하세요. 비동기 패턴 없음, 브라우저 수명주기 없음, Chromium 다운로드 없음. IronPDF의 접근법은 현대 .NET 애플리케이션과의 더 나은 통합과 더 나은 문법을 제공합니다. HTML에서 PDF로의 문서에서 포괄적인 예제를 참조하세요.
예제 2: URL에서 PDF로 변환
이전 (PuppeteerSharp):
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.GoToAsync("https://www.example.com");
await page.PdfAsync("webpage.pdf");
}
}
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.GoToAsync("https://www.example.com");
await page.PdfAsync("webpage.pdf");
}
}
Imports PuppeteerSharp
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim browserFetcher = New BrowserFetcher()
Await browserFetcher.DownloadAsync()
Using browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {
.Headless = True
})
Using page = Await browser.NewPageAsync()
Await page.GoToAsync("https://www.example.com")
Await page.PdfAsync("webpage.pdf")
End Using
End Using
End Function
End Module
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main(ByVal args As String())
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End Class
PuppeteerSharp는 URL로 이동하는 데 GoToAsync()를 사용한 다음 PdfAsync()를 사용합니다. IronPDF는 탐색 및 PDF 생성을 하나의 호출로 처리하는 단일 RenderUrlAsPdf() 메서드를 제공합니다. 더 많은 정보를 보려면 튜토리얼을 참조하세요.
예제 3: 여백을 설정한 사용자 지정 페이지 설정
이전 (PuppeteerSharp):
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using PuppeteerSharp.Media;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>");
await page.PdfAsync("custom.pdf", new PdfOptions
{
Format = PaperFormat.A4,
Landscape = true,
MarginOptions = new MarginOptions
{
Top = "20mm",
Bottom = "20mm",
Left = "20mm",
Right = "20mm"
}
});
}
}
// NuGet: Install-Package PuppeteerSharp
using PuppeteerSharp;
using PuppeteerSharp.Media;
using System.Threading.Tasks;
class Program
{
static async Task Main(string[] args)
{
var browserFetcher = new BrowserFetcher();
await browserFetcher.DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(new LaunchOptions
{
Headless = true
});
await using var page = await browser.NewPageAsync();
await page.SetContentAsync("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>");
await page.PdfAsync("custom.pdf", new PdfOptions
{
Format = PaperFormat.A4,
Landscape = true,
MarginOptions = new MarginOptions
{
Top = "20mm",
Bottom = "20mm",
Left = "20mm",
Right = "20mm"
}
});
}
}
Imports PuppeteerSharp
Imports PuppeteerSharp.Media
Imports System.Threading.Tasks
Module Program
Async Function Main(args As String()) As Task
Dim browserFetcher = New BrowserFetcher()
Await browserFetcher.DownloadAsync()
Await Using browser = Await Puppeteer.LaunchAsync(New LaunchOptions With {
.Headless = True
})
Await Using page = Await browser.NewPageAsync()
Await page.SetContentAsync("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>")
Await page.PdfAsync("custom.pdf", New PdfOptions With {
.Format = PaperFormat.A4,
.Landscape = True,
.MarginOptions = New MarginOptions With {
.Top = "20mm",
.Bottom = "20mm",
.Left = "20mm",
.Right = "20mm"
}
})
End Using
End Using
End Function
End Module
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
var pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>");
pdf.SaveAs("custom.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main(string[] args)
{
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape;
renderer.RenderingOptions.MarginTop = 20;
renderer.RenderingOptions.MarginBottom = 20;
renderer.RenderingOptions.MarginLeft = 20;
renderer.RenderingOptions.MarginRight = 20;
var pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>");
pdf.SaveAs("custom.pdf");
}
}
Imports IronPdf
Imports IronPdf.Rendering
Class Program
Shared Sub Main(args As String())
Dim renderer = New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.PaperOrientation = PdfPaperOrientation.Landscape
renderer.RenderingOptions.MarginTop = 20
renderer.RenderingOptions.MarginBottom = 20
renderer.RenderingOptions.MarginLeft = 20
renderer.RenderingOptions.MarginRight = 20
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Custom PDF</h1><p>With landscape orientation and margins.</p>")
pdf.SaveAs("custom.pdf")
End Sub
End Class
이 예제는 두 라이브러리 간의 PDF 옵션 매핑을 보여줍니다. PuppeteerSharp는 문자열 값("20mm")이 포함된 Format, Landscape 및 MarginOptions와 함께 PdfOptions를 사용합니다. IronPDF는 직접적인 용지 크기 열거형, 방향 열거형 및 밀리미터 단위의 숫자 여백 값을 가진 RenderingOptions 속성을 사용합니다.
주요 매핑:
Format = PaperFormat.A4→PaperSize = PdfPaperSize.A4Landscape = true→PaperOrientation = PdfPaperOrientation.LandscapeMarginOptions.Top = "20mm"→MarginTop = 20(숫자 밀리미터)
메모리 누수 문제
PuppeteerSharp는 지속적인 부하 하에서 메모리 축적으로 악명이 높습니다:
// ❌PuppeteerSharp- Memory grows with each operation
// Requires explicit browser recycling every N operations
for (int i = 0; i < 1000; i++)
{
var page = await browser.NewPageAsync();
await page.SetContentAsync($"<h1>Document {i}</h1>");
await page.PdfAsync($"doc_{i}.pdf");
await page.CloseAsync(); // Memory still accumulates!
}
// Must periodically: await browser.CloseAsync(); and re-launch
// ✅IronPDF- Stable memory, reuse renderer
var renderer = new ChromePdfRenderer();
for (int i = 0; i < 1000; i++)
{
var pdf = renderer.RenderHtmlAsPdf($"<h1>Document {i}</h1>");
pdf.SaveAs($"doc_{i}.pdf");
// Memory managed automatically
}
// ❌PuppeteerSharp- Memory grows with each operation
// Requires explicit browser recycling every N operations
for (int i = 0; i < 1000; i++)
{
var page = await browser.NewPageAsync();
await page.SetContentAsync($"<h1>Document {i}</h1>");
await page.PdfAsync($"doc_{i}.pdf");
await page.CloseAsync(); // Memory still accumulates!
}
// Must periodically: await browser.CloseAsync(); and re-launch
// ✅IronPDF- Stable memory, reuse renderer
var renderer = new ChromePdfRenderer();
for (int i = 0; i < 1000; i++)
{
var pdf = renderer.RenderHtmlAsPdf($"<h1>Document {i}</h1>");
pdf.SaveAs($"doc_{i}.pdf");
// Memory managed automatically
}
' ❌PuppeteerSharp- Memory grows with each operation
' Requires explicit browser recycling every N operations
For i As Integer = 0 To 999
Dim page = Await browser.NewPageAsync()
Await page.SetContentAsync($"<h1>Document {i}</h1>")
Await page.PdfAsync($"doc_{i}.pdf")
Await page.CloseAsync() ' Memory still accumulates!
Next
' Must periodically: Await browser.CloseAsync() and re-launch
' ✅IronPDF- Stable memory, reuse renderer
Dim renderer As New ChromePdfRenderer()
For i As Integer = 0 To 999
Dim pdf = renderer.RenderHtmlAsPdf($"<h1>Document {i}</h1>")
pdf.SaveAs($"doc_{i}.pdf")
' Memory managed automatically
Next
IronPDF는 PuppeteerSharp가 요구하는 브라우저 풀링 인프라가 필요 없습니다:
// Before (PuppeteerSharp - delete entire class)
public class PuppeteerBrowserPool
{
private readonly ConcurrentBag<IBrowser> _browsers;
private readonly SemaphoreSlim _semaphore;
private int _operationCount;
// ... recycling logic ...
}
// After (IronPDF - simple reuse)
public class PdfService
{
private readonly ChromePdfRenderer _renderer = new();
public byte[] Generate(string html)
{
return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
}
// Before (PuppeteerSharp - delete entire class)
public class PuppeteerBrowserPool
{
private readonly ConcurrentBag<IBrowser> _browsers;
private readonly SemaphoreSlim _semaphore;
private int _operationCount;
// ... recycling logic ...
}
// After (IronPDF - simple reuse)
public class PdfService
{
private readonly ChromePdfRenderer _renderer = new();
public byte[] Generate(string html)
{
return _renderer.RenderHtmlAsPdf(html).BinaryData;
}
}
' Before (PuppeteerSharp - delete entire class)
Public Class PuppeteerBrowserPool
Private ReadOnly _browsers As ConcurrentBag(Of IBrowser)
Private ReadOnly _semaphore As SemaphoreSlim
Private _operationCount As Integer
' ... recycling logic ...
End Class
' After (IronPDF - simple reuse)
Public Class PdfService
Private ReadOnly _renderer As New ChromePdfRenderer()
Public Function Generate(html As String) As Byte()
Return _renderer.RenderHtmlAsPdf(html).BinaryData
End Function
End Class
중요한 마이그레이션 노트
비동기에서 동기 변환
PuppeteerSharp는 async/await을 요구합니다; IronPDF는 동기 작업을 지원합니다:
// PuppeteerSharp: Async required
public async Task<byte[]> GeneratePdfAsync(string html)
{
await new BrowserFetcher().DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(...);
await using var page = await browser.NewPageAsync();
await page.SetContentAsync(html);
return await page.PdfDataAsync();
}
// IronPDF: Sync default
public byte[] GeneratePdf(string html)
{
var renderer = new ChromePdfRenderer();
return renderer.RenderHtmlAsPdf(html).BinaryData;
}
// Or async when needed
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
// PuppeteerSharp: Async required
public async Task<byte[]> GeneratePdfAsync(string html)
{
await new BrowserFetcher().DownloadAsync();
await using var browser = await Puppeteer.LaunchAsync(...);
await using var page = await browser.NewPageAsync();
await page.SetContentAsync(html);
return await page.PdfDataAsync();
}
// IronPDF: Sync default
public byte[] GeneratePdf(string html)
{
var renderer = new ChromePdfRenderer();
return renderer.RenderHtmlAsPdf(html).BinaryData;
}
// Or async when needed
public async Task<byte[]> GeneratePdfAsync(string html)
{
var renderer = new ChromePdfRenderer();
var pdf = await renderer.RenderHtmlAsPdfAsync(html);
return pdf.BinaryData;
}
Imports System.Threading.Tasks
Imports PuppeteerSharp
' PuppeteerSharp: Async required
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
Await (New BrowserFetcher()).DownloadAsync()
Await Using browser = Await Puppeteer.LaunchAsync(...)
Await Using page = Await browser.NewPageAsync()
Await page.SetContentAsync(html)
Return Await page.PdfDataAsync()
End Using
End Using
End Function
' IronPDF: Sync default
Public Function GeneratePdf(html As String) As Byte()
Dim renderer = New ChromePdfRenderer()
Return renderer.RenderHtmlAsPdf(html).BinaryData
End Function
' Or async when needed
Public Async Function GeneratePdfAsync(html As String) As Task(Of Byte())
Dim renderer = New ChromePdfRenderer()
Dim pdf = Await renderer.RenderHtmlAsPdfAsync(html)
Return pdf.BinaryData
End Function
마진 단위 변환
PuppeteerSharp는 문자열 단위를 사용합니다; IronPDF는 숫자 밀리미터를 사용합니다:
//PuppeteerSharp- string units
MarginOptions = new MarginOptions
{
Top = "1in", // 25.4mm
Bottom = "0.75in", // 19mm
Left = "1cm", // 10mm
Right = "20px" // ~7.5mm at 96dpi
}
//IronPDF- numeric millimeters
renderer.RenderingOptions.MarginTop = 25; // mm
renderer.RenderingOptions.MarginBottom = 19;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 8;
//PuppeteerSharp- string units
MarginOptions = new MarginOptions
{
Top = "1in", // 25.4mm
Bottom = "0.75in", // 19mm
Left = "1cm", // 10mm
Right = "20px" // ~7.5mm at 96dpi
}
//IronPDF- numeric millimeters
renderer.RenderingOptions.MarginTop = 25; // mm
renderer.RenderingOptions.MarginBottom = 19;
renderer.RenderingOptions.MarginLeft = 10;
renderer.RenderingOptions.MarginRight = 8;
MarginOptions = New MarginOptions With {
.Top = "1in", ' 25.4mm
.Bottom = "0.75in", ' 19mm
.Left = "1cm", ' 10mm
.Right = "20px" ' ~7.5mm at 96dpi
}
renderer.RenderingOptions.MarginTop = 25 ' mm
renderer.RenderingOptions.MarginBottom = 19
renderer.RenderingOptions.MarginLeft = 10
renderer.RenderingOptions.MarginRight = 8
헤더/푸터 플레이스홀더 변환
| PuppeteerSharp 클래스 | IronPDF 플레이스홀더 |
|---|---|
<span class='pageNumber'> |
{page} |
<span class='totalPages'> |
{total-pages} |
<span class='date'> |
{date} |
<span class='title'> |
{html-title} |
이동 후 새로운 기능
IronPDF로 마이그레이션한 후, PuppeteerSharp가 제공할 수 없는 기능을 얻을 수 있습니다:
PDF 병합
var pdf1 = renderer.RenderHtmlAsPdf(html1);
var pdf2 = renderer.RenderHtmlAsPdf(html2);
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
var pdf1 = renderer.RenderHtmlAsPdf(html1);
var pdf2 = renderer.RenderHtmlAsPdf(html2);
var merged = PdfDocument.Merge(pdf1, pdf2);
merged.SaveAs("merged.pdf");
Dim pdf1 = renderer.RenderHtmlAsPdf(html1)
Dim pdf2 = renderer.RenderHtmlAsPdf(html2)
Dim merged = PdfDocument.Merge(pdf1, pdf2)
merged.SaveAs("merged.pdf")
워터마크
var watermark = new TextStamper
{
Text = "CONFIDENTIAL",
FontSize = 48,
Opacity = 30,
Rotation = -45
};
pdf.ApplyStamp(watermark);
var watermark = new TextStamper
{
Text = "CONFIDENTIAL",
FontSize = 48,
Opacity = 30,
Rotation = -45
};
pdf.ApplyStamp(watermark);
Dim watermark As New TextStamper With {
.Text = "CONFIDENTIAL",
.FontSize = 48,
.Opacity = 30,
.Rotation = -45
}
pdf.ApplyStamp(watermark)
비밀번호 보호
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.OwnerPassword = "admin";
pdf.SecuritySettings.UserPassword = "readonly";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.OwnerPassword = "admin"
pdf.SecuritySettings.UserPassword = "readonly"
pdf.SecuritySettings.AllowUserCopyPasteContent = False
디지털 서명
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
var signature = new PdfSignature("certificate.pfx", "password");
pdf.Sign(signature);
Dim signature = New PdfSignature("certificate.pfx", "password")
pdf.Sign(signature)
PDF/A 규정 준수
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b);
pdf.SaveAsPdfA("archive.pdf", PdfAVersions.PdfA3b)
성능 비교 요약
| 미터법 | PuppeteerSharp | IronPDF | 개선 |
|---|---|---|---|
| 첫 번째 PDF (콜드 스타트) | 45초 이상 | 약 20초 | 55% 이상 빠름 |
| 후속 PDF들 | 변하기 쉬운 | 일관적 | 예측 가능 |
| 메모리 사용량 | 500MB 이상 (증가함) | 약 50MB (안정적임) | 메모리 90% 감소 |
| 디스크 공간 (Chromium) | 300MB+ | 0 | 다운로드 제거 |
| 브라우저 다운로드 | 필요함 | 필요 없음 | 설정 없음 |
| 스레드 안전성 | 제한적 | 전체 | 신뢰할 수 있는 동시성 |
| PDF 생성 시간 | 45초 | 20초 | 55% 더 빠름 |
마이그레이션 체크리스트
사전 마이그레이션
- 코드베이스에서 모든PuppeteerSharp사용 식별
- 문서 여백 값을 기록 (문자열을 밀리미터로 변환)
- 변환을 위한 헤더/푸터 플레이스홀더 구문을 기록합니다
- 브라우저 풀링/재활용 인프라 삭제
- ironpdf.com에서IronPDF라이선스 키 획득
패키지 변경 사항
PuppeteerSharpNuGet 패키지 제거- 약 300MB의 디스크 공간을 회수하기 위해
.local-chromium폴더 삭제 IronPdfNuGet Install-Package:dotnet add package IronPdf
코드 변경 사항
- 네임스페이스 가져오기 업데이트
BrowserFetcher.DownloadAsync()호출 제거Puppeteer.LaunchAsync()및 브라우저 관리 제거page.SetContentAsync()+page.PdfAsync()를RenderHtmlAsPdf()로 대체page.GoToAsync()+page.PdfAsync()를RenderUrlAsPdf()로 대체- 여백 문자열을 밀리미터 값으로 변환합니다
- 헤더/푸터 플레이스홀더 구문을 변환합니다
- 모든 브라우저/페이지 폐기 코드를 제거합니다
- 브라우저 풀링 인프라 삭제
- 애플리케이션 시작 시 라이선스 초기화 추가
마이그레이션 이후
- PDF 출력의 시각적 비교
- 메모리 안정성을 위한 부하 테스트 (재활용 없이 안정해야 함)
- 페이지 번호로 헤더/푸터 렌더링을 확인합니다
- 필요에 따라 새 기능(보안, 워터마크, 병합) 추가

