Scryber.Core에서 IronPDF로의 마이그레이션 방법 (C#)
Scryber.Core에서 IronPDF로 마이그레이션하면 PDF 생성 워크플로우가 맞춤형 XHTML+CSS 레이아웃 엔진에서 전체 CSS3 및JavaScript지원이 포함된 Chromium 기반 렌더러로 이동합니다. 이 가이드는 LGPL v3라이선스 고려사항, Scryber의 XHTML-엄격 템플릿 모델, 두 엔진 간의 렌더링 차이점을 포괄하는 단계별 마이그레이션 경로를 제공합니다.
Scryber.Core에서 IronPDF로 전환하는 이유
Scryber.Core 이해하기
Scryber.Core (Richard Hewitson이 유지 관리함, 현재 버전 9.3.1)는 자체 레이아웃 엔진을 사용하는 XHTML+CSS 템플릿을 구문 분석하는 오픈 소스 라이브러리입니다 — 브라우저가 아닙니다. CSS 스타일을 지원하며, doc.Params를 통한 Handlebars 스타일 {{ }} 데이터 바인딩과 SVG도 지원하여, 브라우저에 의존하지 않고 HTML 기반의 PDF를 원하는 개발자에게 매력적입니다.
비록 Scryber.Core이 HTML 템플릿 기반의 PDF 생성을 위한 실행 가능한 옵션이지만, 여러 제약 조건은 팀을 마이그레이션하도록 이끕니다.
주요 마이그레이션 이유
- LGPL v3 라이선스 문제: Scryber 자체를 수정하면 원본 공개 의무가 적용됩니다; 폐쇄형 소스 앱에서는 정적 링크가 허용되지만, 여전히 수정 사항을 배포하는 방식에 제약을 줍니다.
- XHTML 엄격 입력: 템플릿은 유효한 XML이어야 합니다 — 대부분의 실제 HTML은 Scryber가 구문 분석하기 전에 정리가 필요합니다.
- 비브라우저 렌더러: 맞춤형 XHTML/CSS 레이아웃 엔진 — 최신 CSS (그리드, 전체 플렉스 박스, 컨테이너 쿼리) 및 JavaScript는 실행되지 않습니다.
- 작은 커뮤니티: 주류 라이브러리보다 덜 작업된 예시가 많습니다.
- JavaScript 실행 없음: 정적 렌더링만 가능 — 차트, SPA, 동적 위젯은 미리 렌더링되어야 합니다.
- 네이티브 URL-to-PDF 기능 없음: HTML을 직접 가져와야 합니다(예:
HttpClient사용). - 커뮤니티 지원: 상업적 지원 옵션이 제한적입니다.
Scryber.Core와IronPDF비교
| 측면 | Scryber.Core | IronPDF |
|---|---|---|
| 라이선스 | LGPL v3 | 상업적 |
| 렌더링 엔진 | 맞춤형 XHTML/CSS 레이아웃 엔진 | Chromium |
| CSS 지원 | 서브셋 (그리드 없음, 부분 플렉스 박스) | 전체 CSS3 |
| JavaScript | 실행되지 않음 | 전체 (Chromium V8) |
| 템플릿 바인딩 | Handlebars 스타일 {{ }} + <template> |
표준 (Razor, RazorLight 등) |
| 입력 엄격성 | 잘 형성된 XHTML 필요 | 현실 세계의 HTML 수락 |
| 비동기 지원 | PDFAsync MVC 헬퍼; sync core |
전체 비동기 API |
| 문서화 | 문서 읽기 사이트 + 샘플 | 광범위함 |
| 커뮤니티 지원 | 작음 | 더 크다 |
| 상업적 지원 | 커뮤니티 지원 | 상업적 지원 가능 |
IronPDF는 상업용 지원, 문서화, Scryber.Core에 비해 더 큰 사용자 기반을 제공합니다. 이 라이브러리는 LGPL 의무 없이 상업적 사용을 위해 라이선스가 부여됩니다.
시작하기 전에
필수 조건
- .NET 환경: .NET Framework 4.6.2+ 또는 .NET Core 3.1+ / .NET 5/6/7/8/9+
- NuGet 접근 권한: NuGet 패키지를 설치할 수 있는 능력
- IronPDF 라이선스: ironpdf.com에서 라이선스 키를 획득하세요
NuGet 패키지 변경 사항
# Remove Scryber.Core
dotnet remove package Scryber.Core
# Install IronPDF
dotnet add package IronPdf
# Remove Scryber.Core
dotnet remove package Scryber.Core
# Install IronPDF
dotnet add package IronPdf
라이선스 구성
// 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: Scryber.Core
using Scryber.Components; // Document, Page, etc.
using Scryber.Drawing; // Units, colours
using Scryber.PDF; // RenderOptions / OutputCompressionType
using Scryber.Styles; // Style elements (older XML template usage)
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;
// Before: Scryber.Core
using Scryber.Components; // Document, Page, etc.
using Scryber.Drawing; // Units, colours
using Scryber.PDF; // RenderOptions / OutputCompressionType
using Scryber.Styles; // Style elements (older XML template usage)
// After: IronPDF
using IronPdf;
using IronPdf.Rendering;
Imports Scryber.Components ' Document, Page, etc.
Imports Scryber.Drawing ' Units, colours
Imports Scryber.PDF ' RenderOptions / OutputCompressionType
Imports Scryber.Styles ' Style elements (older XML template usage)
' After: IronPDF
Imports IronPdf
Imports IronPdf.Rendering
핵심 API 매핑
| Scryber.Core | IronPDF |
|---|---|
Document.ParseDocument(reader, "", ParseSourceType.DynamicContent) |
renderer.RenderHtmlAsPdf(html) |
Document.ParseDocument(path) |
renderer.RenderHtmlFileAsPdf(path) |
doc.SaveAsPDF(path) |
pdf.SaveAs(path) |
doc.SaveAsPDF(stream) |
pdf.BinaryData (byte[]) |
doc.Info.Title |
pdf.MetaData.Title |
doc.Info.Author |
pdf.MetaData.Author |
@page 템플릿의 CSS |
renderer.RenderingOptions.PaperSize / 여백 |
doc.RenderOptions |
renderer.RenderingOptions |
Handlebars {{value}} + doc.Params |
Razor / 문자열 보간 |
코드 마이그레이션 예제
예제 1: 기본 HTML을 PDF로 변환
이전 (Scryber.Core):
// NuGet: Install-Package Scryber.Core
using Scryber.Components;
using System.IO;
class Program
{
static void Main()
{
// Scryber requires well-formed XHTML wrapped in an html root with the xhtml namespace
string html = @"<html xmlns='http://www.w3.org/1999/xhtml'>
<body><h1>Hello World</h1><p>This is a PDF document.</p></body>
</html>";
using (var reader = new StringReader(html))
using (var doc = Document.ParseDocument(reader, string.Empty, ParseSourceType.DynamicContent))
using (var stream = new FileStream("output.pdf", FileMode.Create))
{
doc.SaveAsPDF(stream);
}
}
}
// NuGet: Install-Package Scryber.Core
using Scryber.Components;
using System.IO;
class Program
{
static void Main()
{
// Scryber requires well-formed XHTML wrapped in an html root with the xhtml namespace
string html = @"<html xmlns='http://www.w3.org/1999/xhtml'>
<body><h1>Hello World</h1><p>This is a PDF document.</p></body>
</html>";
using (var reader = new StringReader(html))
using (var doc = Document.ParseDocument(reader, string.Empty, ParseSourceType.DynamicContent))
using (var stream = new FileStream("output.pdf", FileMode.Create))
{
doc.SaveAsPDF(stream);
}
}
}
Imports Scryber.Components
Imports System.IO
Class Program
Shared Sub Main()
' Scryber requires well-formed XHTML wrapped in an html root with the xhtml namespace
Dim html As String = "<html xmlns='http://www.w3.org/1999/xhtml'>" &
"<body><h1>Hello World</h1><p>This is a PDF document.</p></body>" &
"</html>"
Using reader As New StringReader(html),
doc As Document = Document.ParseDocument(reader, String.Empty, ParseSourceType.DynamicContent),
stream As New FileStream("output.pdf", FileMode.Create)
doc.SaveAsPDF(stream)
End Using
End Sub
End Class
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var renderer = new ChromePdfRenderer();
string html = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("output.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim renderer = New ChromePdfRenderer()
Dim html As String = "<html><body><h1>Hello World</h1><p>This is a PDF document.</p></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("output.pdf")
End Sub
End Class
Scryber.Core는 XHTML 문자열을 StringReader에 래핑하고, Document.ParseDocument에 ParseSourceType.DynamicContent를 사용해 전달한 후, SaveAsPDF를 통해 PDF를 FileStream에 작성합니다. XHTML 네임스페이스 선언이 필요합니다 — Scryber는 올바르게 형성되지 않은 XML HTML을 거부합니다.
IronPDF는 RenderHtmlAsPdf()가 있는 ChromePdfRenderer 인스턴스를 사용하여 HTML을 직접 렌더링하고, SaveAs()을 사용해 저장합니다. 현실 세계의 HTML5가 그대로 수락됩니다. HTML에서 PDF로의 문서를 참조하여 더 많은 예제를 확인하세요.
예제 2: URL에서 PDF로 변환
이전 (Scryber.Core):
// NuGet: Install-Package Scryber.Core
// Scryber has no native URL-to-PDF method — fetch the HTML yourself, then parse.
using Scryber.Components;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var client = new HttpClient();
string html = await client.GetStringAsync("https://www.example.com");
// Most live HTML is not valid XHTML; expect to clean it
// (e.g., HtmlAgilityPack) before Scryber will parse it.
using (var reader = new StringReader(html))
using (var doc = Document.ParseDocument(reader, string.Empty, ParseSourceType.DynamicContent))
using (var stream = new FileStream("webpage.pdf", FileMode.Create))
{
doc.SaveAsPDF(stream);
}
}
}
// NuGet: Install-Package Scryber.Core
// Scryber has no native URL-to-PDF method — fetch the HTML yourself, then parse.
using Scryber.Components;
using System.IO;
using System.Net.Http;
using System.Threading.Tasks;
class Program
{
static async Task Main()
{
using var client = new HttpClient();
string html = await client.GetStringAsync("https://www.example.com");
// Most live HTML is not valid XHTML; expect to clean it
// (e.g., HtmlAgilityPack) before Scryber will parse it.
using (var reader = new StringReader(html))
using (var doc = Document.ParseDocument(reader, string.Empty, ParseSourceType.DynamicContent))
using (var stream = new FileStream("webpage.pdf", FileMode.Create))
{
doc.SaveAsPDF(stream);
}
}
}
Imports Scryber.Components
Imports System.IO
Imports System.Net.Http
Imports System.Threading.Tasks
Module Program
Async Function Main() As Task
Using client As New HttpClient()
Dim html As String = Await client.GetStringAsync("https://www.example.com")
' Most live HTML is not valid XHTML; expect to clean it
' (e.g., HtmlAgilityPack) before Scryber will parse it.
Using reader As New StringReader(html)
Using doc As Document = Document.ParseDocument(reader, String.Empty, ParseSourceType.DynamicContent)
Using stream As New FileStream("webpage.pdf", FileMode.Create)
doc.SaveAsPDF(stream)
End Using
End Using
End Using
End Using
End Function
End Module
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
class Program
{
static void Main()
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
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()
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderUrlAsPdf("https://www.example.com");
pdf.SaveAs("webpage.pdf");
}
}
Imports IronPdf
Class Program
Shared Sub Main()
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim renderer As New ChromePdfRenderer()
Dim pdf = renderer.RenderUrlAsPdf("https://www.example.com")
pdf.SaveAs("webpage.pdf")
End Sub
End Class
Scryber.Core에는 네이티브 URL-to-PDF 진입 지점이 없습니다. HttpClient.GetStringAsync()를 사용하여 HTML을 직접 가져와 Document.ParseDocument()에 입력합니다. Scryber는 올바르게 형성된 XHTML이 필요하기 때문에, 대부분의 라이브 페이지는 파싱하기 전에 정리를 해야 합니다 (예: HtmlAgilityPack 사용). JavaScript는 실행되지 않으므로 동적으로 렌더링된 컨텐츠는 사라집니다.
IronPDF의 RenderUrlAsPdf()는 하나의 호출로 잡아내기,JavaScript실행 및 CSS 렌더링을Chromium엔진을 통해 처리합니다. 더 많은 정보는 튜토리얼에서 확인하세요.
예제 3: 사용자 지정 페이지 설정 및 여백
이전 (Scryber.Core):
// NuGet: Install-Package Scryber.Core
// Page size and margins are normally declared in the XHTML/CSS template;
// the runtime RenderOptions object exposes output-side settings such as compression.
using Scryber.Components;
using Scryber.PDF;
using System.IO;
class Program
{
static void Main()
{
// Page size and margins go in CSS @page; this is the Scryber idiom.
string html = @"<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<style>
@page { size: A4 portrait; margin: 40pt; }
</style>
</head>
<body><h1>Custom PDF</h1><p>With custom margins and settings.</p></body>
</html>";
using (var reader = new StringReader(html))
using (var doc = Document.ParseDocument(reader, string.Empty, ParseSourceType.DynamicContent))
using (var stream = new FileStream("custom.pdf", FileMode.Create))
{
// Output-side options (compression / conformance) are on RenderOptions.
doc.RenderOptions.Compression = OutputCompressionType.FlateDecode;
doc.SaveAsPDF(stream);
}
}
}
// NuGet: Install-Package Scryber.Core
// Page size and margins are normally declared in the XHTML/CSS template;
// the runtime RenderOptions object exposes output-side settings such as compression.
using Scryber.Components;
using Scryber.PDF;
using System.IO;
class Program
{
static void Main()
{
// Page size and margins go in CSS @page; this is the Scryber idiom.
string html = @"<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<style>
@page { size: A4 portrait; margin: 40pt; }
</style>
</head>
<body><h1>Custom PDF</h1><p>With custom margins and settings.</p></body>
</html>";
using (var reader = new StringReader(html))
using (var doc = Document.ParseDocument(reader, string.Empty, ParseSourceType.DynamicContent))
using (var stream = new FileStream("custom.pdf", FileMode.Create))
{
// Output-side options (compression / conformance) are on RenderOptions.
doc.RenderOptions.Compression = OutputCompressionType.FlateDecode;
doc.SaveAsPDF(stream);
}
}
}
Imports Scryber.Components
Imports Scryber.PDF
Imports System.IO
Module Program
Sub Main()
' Page size and margins go in CSS @page; this is the Scryber idiom.
Dim html As String = "<html xmlns='http://www.w3.org/1999/xhtml'>" &
"<head>" &
"<style>" &
"@page { size: A4 portrait; margin: 40pt; }" &
"</style>" &
"</head>" &
"<body><h1>Custom PDF</h1><p>With custom margins and settings.</p></body>" &
"</html>"
Using reader As New StringReader(html),
doc As Document = Document.ParseDocument(reader, String.Empty, ParseSourceType.DynamicContent),
stream As New FileStream("custom.pdf", FileMode.Create)
' Output-side options (compression / conformance) are on RenderOptions.
doc.RenderOptions.Compression = OutputCompressionType.FlateDecode
doc.SaveAsPDF(stream)
End Using
End Sub
End Module
이후 (IronPDF):
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main()
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 40;
renderer.RenderingOptions.MarginBottom = 40;
string html = "<html><body><h1>Custom PDF</h1><p>With custom margins and settings.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom.pdf");
}
}
// NuGet: Install-Package IronPdf
using IronPdf;
using IronPdf.Rendering;
class Program
{
static void Main()
{
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY";
var renderer = new ChromePdfRenderer();
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4;
renderer.RenderingOptions.MarginTop = 40;
renderer.RenderingOptions.MarginBottom = 40;
string html = "<html><body><h1>Custom PDF</h1><p>With custom margins and settings.</p></body></html>";
var pdf = renderer.RenderHtmlAsPdf(html);
pdf.SaveAs("custom.pdf");
}
}
Imports IronPdf
Imports IronPdf.Rendering
Class Program
Shared Sub Main()
IronPdf.License.LicenseKey = "YOUR-LICENSE-KEY"
Dim renderer As New ChromePdfRenderer()
renderer.RenderingOptions.PaperSize = PdfPaperSize.A4
renderer.RenderingOptions.MarginTop = 40
renderer.RenderingOptions.MarginBottom = 40
Dim html As String = "<html><body><h1>Custom PDF</h1><p>With custom margins and settings.</p></body></html>"
Dim pdf = renderer.RenderHtmlAsPdf(html)
pdf.SaveAs("custom.pdf")
End Sub
End Class
Scryber.Core에서는 페이지 크기 및 여백이 @page CSS를 통해 템플릿에 선언되며, doc.RenderOptions는 압축 (OutputCompressionType.FlateDecode)과 같은 출력 측 설정을 노출합니다.
IronPDF는 페이지 기하를 렌더러의 RenderingOptions로 이동합니다: PaperSize (PdfPaperSize.A4으로 설정), MarginTop 및 밀리미터 단위의 MarginBottom. 페이지 기하학은 템플릿이 아닌 API 표면에 존재합니다.
템플릿 마이그레이션 패턴
표준 템플릿으로 Scryber 바인딩 마이그레이션
Scryber.Core는 Handlebars 스타일의 {{ }} 바인딩 (이는 doc.Params를 통해 해결됨)과 반복 섹션을 위한 <template data-bind='...'> 구조를 가진 XHTML을 사용합니다. 마이그레이션하려면 이를 표준 .NET 템플릿으로 다시 표현하십시오:
Scryber Binding (XHTML + Handlebars):
<p>{{model.Name}}</p>
<p>Total: {{model.Total}}</p>
<template data-bind='{{model.Items}}'>
<p>{{.Name}}: {{.Price}}</p>
</template>
<p>{{model.Name}}</p>
<p>Total: {{model.Total}}</p>
<template data-bind='{{model.Items}}'>
<p>{{.Name}}: {{.Price}}</p>
</template>
IronPDF와 C# 문자열 인터폴레이션:
var items = model.Items.Select(i => $"<li>{i.Name}: {i.Price:C}</li>");
var html = $@"
<p>{model.Name}</p>
<p>Total: {model.Total:C}</p>
<ul>
{string.Join("", items)}
</ul>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
var items = model.Items.Select(i => $"<li>{i.Name}: {i.Price:C}</li>");
var html = $@"
<p>{model.Name}</p>
<p>Total: {model.Total:C}</p>
<ul>
{string.Join("", items)}
</ul>";
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf(html);
Dim items = model.Items.Select(Function(i) $"<li>{i.Name}: {i.Price:C}</li>")
Dim html = $"
<p>{model.Name}</p>
<p>Total: {model.Total:C}</p>
<ul>
{String.Join("", items)}
</ul>"
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf(html)
IronPDF는 일반 HTML을 수용하므로 .NET 템플릿 엔진(Razor, RazorLight, Handlebars.Net)을 Scryber의 {{ }} + <template> 구조 대신 사용할 수 있습니다.
헤더 및 푸터 마이그레이션
Scryber.Core (XHTML + @page 여백 상자):
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<style>
@page {
@top-center { content: 'Company Report'; }
@bottom-center { content: 'Page ' counter(page) ' of ' counter(pages); }
}
</style>
</head>
<body>
<h1>Content Here</h1>
</body>
</html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<style>
@page {
@top-center { content: 'Company Report'; }
@bottom-center { content: 'Page ' counter(page) ' of ' counter(pages); }
}
</style>
</head>
<body>
<h1>Content Here</h1>
</body>
</html>
IronPDF (HTML 헤더/푸터):
using IronPdf;
var renderer = new ChromePdfRenderer();
// HTML header with full CSS support
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='width: 100%; text-align: center; font-size: 12pt; border-bottom: 1px solid #ccc;'>
Company Report
</div>",
MaxHeight = 30
};
// HTML footer with page numbers
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='width: 100%; text-align: center; font-size: 10pt;'>
Page {page} of {total-pages}
</div>",
MaxHeight = 25
};
var pdf = renderer.RenderHtmlAsPdf("<h1>Content Here</h1>");
pdf.SaveAs("report.pdf");
using IronPdf;
var renderer = new ChromePdfRenderer();
// HTML header with full CSS support
renderer.RenderingOptions.HtmlHeader = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='width: 100%; text-align: center; font-size: 12pt; border-bottom: 1px solid #ccc;'>
Company Report
</div>",
MaxHeight = 30
};
// HTML footer with page numbers
renderer.RenderingOptions.HtmlFooter = new HtmlHeaderFooter
{
HtmlFragment = @"
<div style='width: 100%; text-align: center; font-size: 10pt;'>
Page {page} of {total-pages}
</div>",
MaxHeight = 25
};
var pdf = renderer.RenderHtmlAsPdf("<h1>Content Here</h1>");
pdf.SaveAs("report.pdf");
Imports IronPdf
Dim renderer As New ChromePdfRenderer()
' HTML header with full CSS support
renderer.RenderingOptions.HtmlHeader = New HtmlHeaderFooter With {
.HtmlFragment = "
<div style='width: 100%; text-align: center; font-size: 12pt; border-bottom: 1px solid #ccc;'>
Company Report
</div>",
.MaxHeight = 30
}
' HTML footer with page numbers
renderer.RenderingOptions.HtmlFooter = New HtmlHeaderFooter With {
.HtmlFragment = "
<div style='width: 100%; text-align: center; font-size: 10pt;'>
Page {page} of {total-pages}
</div>",
.MaxHeight = 25
}
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Content Here</h1>")
pdf.SaveAs("report.pdf")
Scryber.Core는 CSS의 @page 여백 상자를 통해 헤더 및 푸터를 정의하며, 페이지 번호에 대해 counter(page) 및 counter(pages)를 사용합니다. IronPDF는 헤더 및 푸터에 대해 전체 HTML/CSS와 함께 HtmlHeaderFooter를 사용하고, 자리 표시자로 {page} 및 {total-pages}를 사용합니다.
이동 후 새로운 기능
IronPDF로 마이그레이션한 후에는 Scryber.Core가 제공할 수 없는 기능을 얻을 수 있습니다:
PDF 병합
var pdf1 = PdfDocument.FromFile("chapter1.pdf");
var pdf2 = PdfDocument.FromFile("chapter2.pdf");
var pdf3 = PdfDocument.FromFile("chapter3.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
merged.SaveAs("complete_book.pdf");
var pdf1 = PdfDocument.FromFile("chapter1.pdf");
var pdf2 = PdfDocument.FromFile("chapter2.pdf");
var pdf3 = PdfDocument.FromFile("chapter3.pdf");
var merged = PdfDocument.Merge(pdf1, pdf2, pdf3);
merged.SaveAs("complete_book.pdf");
Dim pdf1 = PdfDocument.FromFile("chapter1.pdf")
Dim pdf2 = PdfDocument.FromFile("chapter2.pdf")
Dim pdf3 = PdfDocument.FromFile("chapter3.pdf")
Dim merged = PdfDocument.Merge(pdf1, pdf2, pdf3)
merged.SaveAs("complete_book.pdf")
보안 및 메타데이터
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Confidential</h1>");
// Metadata
pdf.MetaData.Title = "My Document";
pdf.MetaData.Author = "John Doe";
pdf.MetaData.Subject = "Annual Report";
pdf.MetaData.Keywords = "report, annual, confidential";
// Security
pdf.SecuritySettings.OwnerPassword = "owner123";
pdf.SecuritySettings.UserPassword = "user456";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.FullPrintRights;
pdf.SaveAs("protected.pdf");
var renderer = new ChromePdfRenderer();
var pdf = renderer.RenderHtmlAsPdf("<h1>Confidential</h1>");
// Metadata
pdf.MetaData.Title = "My Document";
pdf.MetaData.Author = "John Doe";
pdf.MetaData.Subject = "Annual Report";
pdf.MetaData.Keywords = "report, annual, confidential";
// Security
pdf.SecuritySettings.OwnerPassword = "owner123";
pdf.SecuritySettings.UserPassword = "user456";
pdf.SecuritySettings.AllowUserCopyPasteContent = false;
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.FullPrintRights;
pdf.SaveAs("protected.pdf");
Dim renderer = New ChromePdfRenderer()
Dim pdf = renderer.RenderHtmlAsPdf("<h1>Confidential</h1>")
' Metadata
pdf.MetaData.Title = "My Document"
pdf.MetaData.Author = "John Doe"
pdf.MetaData.Subject = "Annual Report"
pdf.MetaData.Keywords = "report, annual, confidential"
' Security
pdf.SecuritySettings.OwnerPassword = "owner123"
pdf.SecuritySettings.UserPassword = "user456"
pdf.SecuritySettings.AllowUserCopyPasteContent = False
pdf.SecuritySettings.AllowUserPrinting = PdfPrintSecurity.FullPrintRights
pdf.SaveAs("protected.pdf")
기능 비교 요약
| 기능 | Scryber.Core | IronPDF |
|---|---|---|
| HTML to PDF | XHTML+CSS를 사용하는 맞춤형 레이아웃 엔진 | 전체 Chromium |
| URL을 PDF로 변환 | 수동 페치만 | 네이티브 RenderUrlAsPdf |
| CSS 그리드 | 지원되지 않음 | 전체 지원 |
| 플렉스박스 | 부분적 | 전체 지원 |
| JavaScript | 실행되지 않음 | 전체 (V8) |
| 데이터 바인딩 | {{ }} Handlebars + doc.Params |
Razor / RazorLight / 보간 |
| 헤더/푸터 | @page 여백 상자 / 템플릿 섹션 |
{total-pages} HtmlHeaderFooter와 {page} 함께 |
| PDF 병합 | 지원되지 않음 | 내장 PdfDocument.Merge |
| PDF 분할 | 지원되지 않음 | 예 |
| 워터마크 | 템플릿에 오버레이 HTML을 통한 | 네이티브 ApplyStamp / ApplyWatermark |
| 디지털 서명 | 지원되지 않음 | 예 |
| PDF/A | 지원되지 않음 | 예 (PDF/A-1b, PDF/A-3) |
| 비밀번호 보호 | 지원되지 않음 | 전체 (사용자/소유자 + 권한) |
| 비동기 지원 | PDFAsync MVC 헬퍼; sync core |
전체 비동기 표면 |
| 크로스 플랫폼 | 예 (.NET Std 2.0/2.1, .NET 8/9/10) | 예 |
마이그레이션 체크리스트
사전 마이그레이션
- 모든 Scryber 템플릿을 XHTML/바인딩 패턴에 대해 검사
- 사용된 문서 데이터 바인딩 패턴 (
{{model.Property}}) - CSS 변환이 필요한 사용자 정의 스타일 식별
- ironpdf.com에서IronPDF라이선스 키 획득
코드 업데이트
Scryber.CoreNuGet 패키지 제거IronPdfNuGet Install-Package- 네임스페이스 가져오기 업데이트 (
using Scryber.Components;/Scryber.Drawing;/Scryber.PDF;→using IronPdf;) Document.ParseDocument(reader, "", ParseSourceType.DynamicContent)을(를)renderer.RenderHtmlAsPdf(html)으로(로) 대체doc.SaveAsPDF(stream)을(를)pdf.SaveAs(path)또는pdf.BinaryData으로(로) 대체- XHTML 템플릿을 일반 HTML5(네임스페이스 요구 없음)로 변환
{{ }}Handlebars 바인딩을 표준 템플릿(Razor / 문자열 보간)으로 대체@pageCSS를renderer.RenderingOptions로 이동 (PaperSize, MarginTop, 등)HtmlHeaderFooter와{page}및{total-pages}자리 표시자로@page여백 상자 헤더/푸터를 변환- 애플리케이션 시작 시 라이선스 초기화 추가
테스트
- 모든 문서 템플릿 테스트
- 스타일링 일치 여부 확인 (전체 CSS 지원 활용)
- 새로운 템플릿과 데이터 바인딩 테스트
- 페이지 나누기 확인
- 페이지 번호 플레이스홀더를 포함한 헤더/푸터 테스트
- 성능 비교

