이 페이지에는 자동 번역된 텍스트가 포함될 수 있습니다.
.NET PDF 생성기
Docotic.Pdf의 도움으로 페이지, 컨테이너, 텍스트 스팬, 이미지, 링크, 머리글, 바닥글, 표, 목록 등과 같은 구조적 요소를 조합하여 PDF 문서를 생성할 수 있습니다. 이러한 요소는 무료 Docotic.Pdf Layout 추가 기능이 제공하는 상위 수준의 Layout API를 통해 사용할 수 있습니다. 이 API는 재사용 가능한 사용자 지정 구성 요소도 지원합니다.

Layout API를 사용하면 플루언트 방식으로 C# 또는 VB.NET 코드만으로 문서를 완전히 정의할 수 있습니다. 이 설명을 기반으로, 추가 기능이 제공하는 PDF 생성기는 단순한 페이지부터 고도로 구조화된 PDF 보고서까지 임의로 복잡한 레이아웃의 문서를 생성할 수 있습니다.
PDF 생성 기본 사항
Layout API를 사용하여 PDF 문서를 생성하려면 무료 Layout 추가 기능이 필요합니다. 핵심 라이브러리와 추가 기능을 사용하려면 라이선스 키도 필요합니다. 무료 평가판 키 또는 구매한 키를 사용할 수 있습니다.
추가 기능 설치
권장 방법은 NuGet에서 추가 기능을 설치하는 것입니다.
Install-Package BitMiracle.Docotic.Pdf.Layout
패키지 관리자가 종속성을 자동으로 처리합니다.
추가 기능을 수동으로 설치하려면 먼저 Docotic.Pdf 바이너리가 들어 있는 ZIP 아카이브를 다운로드합니다. 아카이브를 압축 해제한 다음 다음 DLL에 대한 참조를 추가합니다:
BitMiracle.Docotic.Pdf.dllBitMiracle.Docotic.Pdf.Layout.dllfrom theLayout add-onsubfolder.
라이선스 키 얻기
라이브러리를 시험해 보려면 Docotic.Pdf 다운로드 페이지에서 양식을 작성하여 무료 기간 제한 라이선스 키를 요청하세요. 이미 라이선스를 구매한 경우 구매 후 제공된 코드를 사용하세요.
Layout 추가 기능은 무료이며 추가 라이선스가 필요하지 않습니다. 이미 보유한 Docotic.Pdf 라이선스로 Layout API를 사용할 수 있습니다.
Layout API로 Hello, world! 만들기
다음은 클래식한 "Hello, world!" 문구를 사용하여 PDF를 생성하는 API 샘플 코드입니다:
BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");
PdfDocumentBuilder.Create().Generate("hello.pdf", doc => doc.Pages(pages =>
{
pages.Content().Text("Hello, world!");
}));
이 코드는 왼쪽 위 모서리에 텍스트가 있는 단일 페이지 PDF를 생성합니다.
코드 샘플 이해하기
샘플은 먼저 라이선스 키를 추가하는 것으로 시작합니다. 라이선스가 없으면 Docotic.Pdf 라이브러리는 아무것도 생성하지 않습니다. PDF 생성 코드는 다음 줄에서 시작합니다.
코드는 정적 PdfDocumentBuilder.Create() 메서드를 호출하여 문서 빌더의 인스턴스를 만듭니다. Generate 메서드 호출이 PDF 생성 프로세스를 시작합니다. 이 메서드는 생성할 파일 이름과 Action<Document> 형식의 대리자 두 개의 매개 변수를 받습니다. 추가 기능은 Generate 호출의 결과로 hello.pdf를 생성합니다.
PDF에 어떤 레이아웃이 있어야 하는지 알기 위해, 문서 빌더는 Document 인스턴스로 대리자를 호출합니다. 대리자의 코드는 문서 내용을 조합합니다. 이 샘플에서 대리자는 Pages 메서드를 사용하여 빌더에 문서 페이지의 레이아웃을 정의하는 또 다른 대리자를 제공합니다.
빌더는 Pages 메서드에 제공된 대리자를 PageLayout 인스턴스로 호출합니다. 이 인스턴스는 문서의 하나 이상의 페이지를 나타냅니다. 정확한 페이지 수는 추가된 내용에 따라 달라집니다.
페이지 대리자는 Content 메서드를 호출하여 페이지의 기본 콘텐츠를 위한 레이아웃 컨테이너에 접근합니다. 컨테이너의 Text 메서드를 연쇄 호출하면 샘플 텍스트 스팬이 페이지에 추가됩니다. 자세한 동작 설명은 레이아웃 컨테이너 안내서를 참조하세요.
문서 빌더는 콘텐츠를 페이지 전체에 자동으로 분할하여, 기본 콘텐츠 레이아웃 컨테이너에 추가된 모든 데이터를 담는 데 필요한 만큼 정확히 페이지를 생성합니다. 이 샘플에서는 단일 페이지로 충분하므로 출력은 정확히 한 페이지를 포함합니다.
기본 샘플을 넘어서는 일반적인 작업
샘플 코드는 먼저 PdfDocumentBuilder 인스턴스를 만들고, 이어서 Generate 메서드를 호출하여 PDF를 생성합니다. PDF 생성이 시작되기 전에 빌더를 구성할 수 있습니다.
예를 들어 빌더에 암호화 처리기를 제공하여 암호화된 PDF를 생성할 수 있습니다. 생성된 문서에 포함할 메타데이터도 지정할 수 있습니다. 빌더를 사용자 지정하는 방법에 대한 자세한 내용은 별도 문서를 참조하세요.
샘플 코드는 기본 콘텐츠 슬롯의 레이아웃 컨테이너만 사용하지만, 다른 콘텐츠 슬롯도 사용할 수 있습니다. 콘텐츠 슬롯에 접근하기 위한 PageLayout 메서드 전체 목록은 다음과 같습니다:
Background()- 다른 콘텐츠에 의해 가려지는 배경 레이어를 반환합니다.Header()- 모든 페이지에 공통인 머리글을 반환합니다.Content()- 기본 페이지 콘텐츠 슬롯을 반환합니다.Footer()- 모든 페이지에 공통인 바닥글을 반환합니다.Foreground()- 다른 콘텐츠 위에 표시되는 전경 레이어를 반환합니다.
생성된 PDF의 페이지 수에 영향을 주는 것은 기본 콘텐츠 슬롯의 콘텐츠뿐입니다. 문서 빌더는 Content()가 제공한 슬롯을 제외한 모든 슬롯을 각 페이지에 반복합니다. 콘텐츠 슬롯에 대한 자세한 내용은 페이지 레이아웃 문서를 참조하세요.
많은 문서는 페이지마다 서로 다른 레이아웃을 사용합니다. 예를 들어 첫 페이지는 표지 스타일 디자인을 사용할 수 있고, 이후 페이지는 더 단순한 레이아웃을 사용할 수 있습니다. 일부 문서는 표 전용 페이지를 포함하거나 섹션에 따라 서로 다른 배경을 적용합니다. Docotic.Pdf와 Layout 추가 기능으로 이러한 문서를 생성하려면 Document.Pages 메서드를 여러 번 호출하면 됩니다. 샘플 저장소에서 작동 예제를 찾을 수 있습니다.
코드 구성하기
샘플처럼 짧은 코드에서는 호출을 연쇄하고 중첩 람다를 사용하는 것이 좋습니다. 더 큰 작업을 만들 때는 코드를 별도 메서드로 분리하는 편이 더 편할 수 있습니다. 이렇게 하면 코드를 읽고 유지하기가 쉬워집니다.
다음은 Hello, world! 샘플의 코드가 메서드로 분리되었을 때의 모습입니다.
public void GeneratePdf()
{
BitMiracle.Docotic.LicenseManager.AddLicenseData("PUT-LICENSE-HERE");
PdfDocumentBuilder.Create().Generate("hello.pdf", BuildDocument);
}
private void BuildDocument(Document doc)
{
doc.Pages(BuildPages);
}
private void BuildPages(PageLayout pages)
{
pages.Content().Text("Hello, world!");
}
Docotic.Pdf Layout API로 PDF를 생성하는 이유
Layout API는 PDF 형식 내부를 이해할 필요 없이 조합 가능한 빌딩 블록으로 PDF를 생성하는 개발자 친화적인 최신 방식입니다. 성능이 높고 결정적이며 예측 가능한 동작으로 PDF를 배치합니다. 이 API는 대량 문서 생성 시나리오에 사용할 수 있습니다.
이 API는 무료 Layout 추가 기능과 함께 Docotic.Pdf를 사용할 때 제공됩니다. Docotic.Pdf와 Layout 추가 기능은 모두 unsafe 코드 블록이 없는 100% 관리 코드 DLL입니다. Layout API는 브라우저나 Skia 바이너리와 같은 타사 외부 종속성 없이 구현되어, 배포와 유지 관리가 쉬운 경량 저오버헤드 솔루션을 제공합니다.
API 개요
Layout API는 사용하기 편한 플루언트 API입니다. 유연한 레이아웃 요소를 사용하여 문서의 레이아웃을 코드만으로 완전히 설명하면, 생성기가 콘텐츠를 흐르게 하고 자동으로 페이지를 나눈 뒤 결과를 PDF로 렌더링합니다.
Layout 추가 기능은 선언적이고 흐름 기반의 레이아웃 시스템을 사용합니다. 레이아웃 요소에는 목록, 열, 행, 표, 이미지, 텍스트 스팬, 머리글과 바닥글, 컨테이너 등이 포함됩니다. 요소를 정확한 좌표에 수동으로 배치하는 대신, 요소가 어떻게 동작해야 하는지를 설명합니다. 그러면 문서 빌더가 최종 레이아웃을 계산하고 PDF를 생성합니다.
흐름 기반 레이아웃 시스템은 레이아웃이 페이지 크기와 콘텐츠에 맞게 조정되도록 보장합니다. 이 시스템 덕분에 추가 기능은 복잡하고 구조화된 규칙 기반 레이아웃에 특히 강합니다. 서로 다른 유형의 컨테이너를 중첩하여 가독성을 해치지 않으면서 정교한 구조를 만들 수 있습니다.
Layout API를 사용할 때는 대부분의 호출을 연쇄할 수 있습니다. 그 결과 기존 API보다 더 간결하고 표현력이 풍부한 코드를 작성할 수 있습니다. 연쇄 내 호출 순서는 중요합니다. 모든 것이 강한 형식으로 되어 있어 컴파일 시 안전성을 제공하고 리팩터링 친화적입니다. Layout API를 사용하는 코드를 단위 테스트할 수도 있습니다.
레이아웃 구현을 더 간결하게 만들려면, 자신만의 메서드로 API를 확장하고 그 위에 깔끔하고 표현력 있는 DSL을 구축할 수 있습니다.
위치 지정과 DSL 생성에 대한 자세한 내용은 컨테이너의 크기, 위치, 정렬, 렌더링 동작을 제어하는 방법을 설명하는 문서를 참조하세요.
.NET 버전 및 플랫폼 지원
.NET Standard 2.1 및 그 이후 프레임워크를 대상으로 하는 프로젝트에서 Layout API를 사용할 수 있습니다. 즉, Layout 추가 기능은 .NET 5부터 .NET 10까지와 호환됩니다. 또한 .NET Core 3.0+도 지원됩니다.
ASP.NET Core, MAUI 앱, Unity, Xamarin 및 콘솔 애플리케이션에서 Layout API로 PDF를 생성할 수 있습니다. Layout 추가 기능이 포함된 Docotic.Pdf는 Windows, macOS 및 Linux에서 PDF를 생성할 수 있습니다.
클라우드 플랫폼 및 Docker 이미지
Layout 추가 기능이 포함된 Docotic.Pdf는 서버리스 구성을 포함한 Azure 및 AWS 클라우드 환경에서 실행할 수 있습니다. 라이브러리와 추가 기능은 동적 하드웨어 변경, 자동 확장 및 기타 클라우드 네이티브 런타임 기능을 완전히 지원합니다.
대부분의 클라우드 시나리오에서는 제한 없는 라이선스가 필요합니다. 라이선스 FAQ에서는 클라우드 애플리케이션에 적합한 라이선스를 선택하는 방법을 설명합니다.
Layout API는 Docker 컨테이너에서 그대로 동작합니다. 컨테이너 내부에서 라이브러리와 Layout 추가 기능을 실행하며 PDF를 생성할 때 특별한 구성은 필요하지 않습니다.
PDF 파일에 텍스트 추가하기
텍스트는 모든 PDF 문서의 기본 요소입니다. LayoutContainer 클래스의 LayoutContainer Text 메서드를 사용하여 콘텐츠 슬롯에 텍스트를 추가할 수 있습니다.

텍스트 스팬
Hello, world 샘플에서는 페이지의 기본 콘텐츠에 텍스트를 추가하기 위해 LayoutContainer.Text(string) 오버로드를 사용했습니다. 이제 Text 메서드의 다른 오버로드를 살펴보겠습니다.
public static void GenerateTextPdf()
{
PdfDocumentBuilder.Create().Generate("text-spans.pdf", doc => doc.Pages(pages =>
{
pages.Content().Text(AddTextSpans);
}));
}
private static void AddTextSpans(TextContainer text)
{
text.Line("About VB.NET")
.Style(t => t.Strong);
text.Span("VB.NET is a multi-paradigm, object-oriented language ");
text.Span("that runs on .NET, Mono, and the ");
text.Hyperlink(
".NET Framework",
new Uri("https://dotnet.microsoft.com/download/dotnet-framework"));
text.Line(".");
text.Span("Released by Microsoft in 2002, ");
text.Line("it continues the lineage of the original Visual Basic language.");
}
이 코드는 TextContainer 클래스의 Span 및 Line 메서드를 사용하여 현재 줄에 텍스트를 추가합니다. Line 메서드는 추가로 현재 줄을 완성합니다. 샘플 코드는 Hyperlink 메서드도 사용하여 특정 텍스트 스팬에 외부 리소스 링크를 연결합니다.
샘플 코드가 Style 메서드를 사용하여 첫 줄에 강한 서식을 적용하는 점에 주목하세요. 이제 텍스트 스타일 개념을 더 자세히 살펴보겠습니다.
텍스트 스타일
텍스트 스타일을 사용하면 텍스트 모양을 사용자 지정할 수 있습니다. TextStyle 클래스는 글꼴 크기, 자간, 색상 및 기타 텍스트 속성을 변경하는 메서드를 제공합니다. TextStyle 객체는 불변이므로 각 메서드 호출은 새 스타일 인스턴스를 생성합니다. 텍스트 스타일은 서로 다른 레이아웃 수준에 적용할 수 있습니다.
PdfDocumentBuilder.Create().Generate("text-styles.pdf", doc =>
{
doc.Pages(pages =>
{
pages.TextStyle(TextStyle.Parent.FontSize(30));
pages.Content()
.TextStyle(TextStyle.Parent.FontColor(new PdfRgbColor(0, 0, 255)))
.Text(text =>
{
text.Span("Hello,");
text.Span("World!")
.Style(TextStyle.Parent.Underline());
});
});
});
TextStyle.Parent 속성은 모든 텍스트 속성이 정의되지 않은 특수 스타일을 반환합니다. 위 샘플에서는 코드가 30포인트 글꼴 크기를 사용해 파란색으로 “Hello, World!”를 그리고, 두 번째 단어에 밑줄을 적용합니다.
이는 코드가 다음을 수행하기 때문입니다:
- 페이지 수준에서 글꼴 크기를 30포인트로 설정하고,
- 기본 콘텐츠 슬롯의 텍스트 색상을 파란색으로 설정한 뒤,
- 마지막 텍스트 스팬에 밑줄 스타일을 적용합니다.
각 후속 스타일은 TextStyle.Parent 속성을 통해 이전 스타일을 상속합니다.
TextStyle 클래스의 메서드를 사용하면, 다른 기능과 함께 텍스트 방향을 오른쪽에서 왼쪽으로 변경할 수도 있습니다. 샘플 저장소에서 텍스트 스타일 상속을 사용하는 다른 예제를 확인하세요.
타이포그래피
TextStyle 클래스는 연결된 글꼴을 제외한 모든 텍스트 속성을 사용자 지정할 수 있습니다. 기본 글꼴을 변경하려면 Document.TextStyleWithFont 메서드를 사용하여 특정 글꼴을 기반으로 한 텍스트 스타일을 만드세요. 운영 체제에 설치된 글꼴을 사용하거나 파일 또는 스트림에서 글꼴을 로드할 수 있습니다.
글꼴 기반 스타일을 만든 뒤에는 추가 선택적 속성을 적용하고, 그 결과 스타일을 텍스트 스팬에 사용할 수 있습니다. 이 C# 샘플은 시스템 글꼴을 사용하는 방법을 보여줍니다.
PdfDocumentBuilder.Create().Generate("text-style-with-font.pdf", doc =>
{
var font = SystemFont.Family("Calibri");
var style = doc.TextStyleWithFont(font).FontSize(30);
doc.Pages(pages =>
{
pages.Content().Text(text =>
{
text.Span("Hello,");
text.Span("World!")
.Style(style);
});
});
});
TextStyleWithFont 메서드에는 생성된 문서에 글꼴을 어떻게 포함할지 지정하는 선택적 매개 변수가 있습니다. 기본적으로 라이브러리는:
- TrueType/OpenType 글꼴에 대해 사용된 글리프만 포함합니다.
- Type1 및 CFF 글꼴에 대해 모든 글리프를 포함합니다.
- 내장 PDF 글꼴(Base14 글꼴)에 대해서는 글리프를 포함하지 않습니다.
이 기본 설정 덕분에 TrueType 및 OpenType 글꼴을 사용하는 문서는 큰 글꼴을 사용하더라도 크기가 작게 유지될 수 있습니다. 사용자 지정 글꼴 로더, 대체 글꼴, 누락된 글리프 처리기도 지정할 수 있습니다. PDF 문서에서 글꼴 관리를 하는 방법에 대한 자세한 내용은 예제 저장소의 샘플 코드를 참조하세요.
Layout API는 미리 정의된 스타일 모음을 제공하며, Typography 클래스를 통해 접근하고 수정할 수 있습니다.
PdfDocumentBuilder.Create().Generate("typography.pdf", doc =>
{
doc.Typography(t =>
{
var fontsPath = Environment.GetFolderPath(Environment.SpecialFolder.Fonts);
var arialFont = new FileInfo(Path.Combine(fontsPath, "arial.ttf"));
t.Document = doc.TextStyleWithFont(arialFont);
t.Header = t.Parent.FontSize(20).FontColor(new PdfGrayColor(20));
t.Footer = t.Footnote;
});
doc.Pages(pages =>
{
pages.Header().AlignCenter().Text("Header");
pages.Content().Text(t =>
{
t.Line("Title").Style(t => t.Title);
t.Line("Heading 1").Style(t => t.Heading1);
t.Line("Regular");
});
pages.Footer()
.Height(20)
.AlignCenter()
.Text(t => t.CurrentPageNumber());
});
});
문서 전체에 타이포그래피를 구성하여 미리 정의된 스타일을 재정의하는 것을 권장합니다. 그러나 이것이 필수는 아니며, 텍스트 스팬 수준에서 여전히 텍스트 스타일을 적용할 수 있습니다.
Typography 클래스를 사용하면 텍스트 스타일 참조를 변수에 저장할 필요가 없습니다. 대신 Document.Typography 메서드를 사용해 필요한 스타일을 등록한 다음, Typography 개체의 속성을 통해 이를 나중에 사용할 수 있습니다. PDF 문서를 생성할 때 미리 정의된 및 사용자 지정 텍스트 스타일을 사용하는 방법은 Typography 샘플을 참조하세요.
머리글 및 바닥글 작업
보고서나 송장과 같은 많은 실제 PDF 문서에는 머리글과 바닥글이 포함됩니다. 이 섹션에서는 둘 다 PDF에 추가하는 방법을 보여줍니다.
public static void GeneratePdfWithHeaderAndFooter()
{
PdfDocumentBuilder.Create()
.Generate("header-footer.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6).Margin(10);
BuildPagesHeader(pages.Header());
BuildPagesFooter(pages.Footer());
pages.Content().Text("Hello, world!");
}));
}
public static void BuildPagesHeader(LayoutContainer header)
{
header.TextStyle(TextStyle.Parent.FontSize(8))
.AlignRight()
.Text(t =>
{
t.Line($"Created by: {Environment.UserName}");
t.Line($"Date: {DateTime.Now}");
});
}
public static void BuildPagesFooter(LayoutContainer footer)
{
footer.AlignRight().Text(text =>
{
text.Style(t => t.Parent.FontColor(new PdfRgbColor(255, 0, 0)));
text.CurrentPageNumber();
text.Span(" / ");
text.PageCount();
});
}
BuildPagesHeader 메서드는 머리글 텍스트의 글꼴 크기를 더 작게 설정합니다. 머리글 콘텐츠는 현재 사용자의 이름과 현재 날짜라는 두 줄을 사용합니다. 텍스트는 오른쪽 정렬됩니다.
코드가 머리글의 명시적 크기를 지정하지 않는 점에 주목하세요. 머리글은 왼쪽 및 오른쪽 여백을 제외한 전체 페이지 너비를 차지하며, 높이는 텍스트 줄의 높이에 따라 달라집니다.
BuildPagesFooter 메서드는 PDF 바닥글에 현재 페이지 번호를 배치하는 방법을 보여줍니다. 라이브러리는 현재 페이지 번호와 전체 페이지 수를 자동으로 계산합니다. 이러한 값은 TextContainer 개체의 CurrentPageNumber 및 PageCount 메서드를 사용하여 접근할 수 있습니다.
Layout API는 페이지 번호 서식 지정 방법도 제공합니다. 예를 들어 다음과 같이 16진수 페이지 번호를 그릴 수 있습니다:
text.CurrentPageNumber().Format(p => "0x" + p?.ToString("x2"));
샘플 저장소에는 PDF에 머리글과 바닥글 추가를 하는 또 다른 예제가 있습니다. 해당 예제는 페이지 번호를 로마 숫자로 서식 지정합니다.
이미지 삽입
속담처럼, 한 장의 그림은 많은 단어를 대신할 수 있습니다. 견적서나 영수증에는 회사 로고나 다른 중요한 이미지를 자주 포함하게 됩니다. 이 예제에서는 단순하면서 보기 좋은 이미지를 사용하겠습니다.
이미지를 사용하려면 먼저 문서에 추가해야 합니다. 라이브러리는 파일 또는 스트림에서 이미지를 로드할 수 있습니다. 래스터 형식만 지원됩니다: PNG, JPEG, JPEG 2000, BMP, GIF 및 TIFF.
Image 개체를 얻은 후에는 컨테이너의 Image 메서드를 호출하여 하나 이상의 레이아웃 컨테이너의 콘텐츠로 설정할 수 있습니다. 다른 콘텐츠와 마찬가지로 이미지를 크기 조정, 회전, 패딩 추가, 배치할 수 있습니다.
PdfDocumentBuilder.Create().Generate("image-with-text.pdf", doc =>
{
var imageFile = new FileInfo("red-flowers-at-butterfly-world.jpg");
var image = doc.Image(imageFile);
doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(c =>
{
c.Spacing(20);
c.Item()
.AlignCenter()
.Text("Hello, world!")
.FontSize(20);
c.Item()
.AlignCenter()
.MaxWidth(200)
.Image(image);
});
});
});
샘플 코드는 기본 콘텐츠 슬롯에서 텍스트와 이미지를 함께 사용합니다. 그러나 레이아웃 컨테이너에는 텍스트만 또는 이미지만 포함할 수 있습니다. 페이지의 기본 콘텐츠 슬롯에 둘 다 포함하려면 복합 컨테이너가 필요합니다.
여기서는 Column 컨테이너를 사용하여 텍스트와 이미지를 세로로 하나씩 배치합니다. 열 컨테이너의 Item 메서드는 하위 컨테이너를 제공합니다. Item을 한 번 호출하면 텍스트용 컨테이너가 만들어지고, 다시 호출하면 이미지용 컨테이너가 만들어집니다. 모든 하위 컨테이너를 포함한 복합 컨테이너가 기본 콘텐츠가 됩니다.
샘플 코드를 실행하려면 샘플 저장소에서 꽃 이미지를 다운로드하여 앱의 작업 디렉터리에 배치하세요.
온라인 이미지
파일 대신 이미지 URL만 있는 경우, 이미지를 메모리 스트림에 다운로드한 다음 해당 스트림에서 Image를 생성할 수 있습니다. 다음 예제는 Layout API로 온라인 이미지를 사용하는 방법을 보여줍니다.
public static async Task AddImageWithTextFromUrl()
{
using var http = new HttpClient();
using var stream = await http.GetStreamAsync("url/to/image");
var memoryStream = new MemoryStream();
await stream.CopyToAsync(memoryStream);
memoryStream.Position = 0;
PdfDocumentBuilder.Create().Generate("online-image-with-text.pdf", doc =>
{
var image = doc.Image(memoryStream);
doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(c =>
{
c.Spacing(20);
c.Item()
.AlignCenter()
.Text("Hello, world!")
.FontSize(20);
c.Item()
.AlignCenter()
.MaxWidth(200)
.Image(image);
});
});
});
}
이 메서드는 비동기 작업(URL에서 이미지 다운로드)을 수행하므로 void 대신 async Task로 선언됩니다. 호출자는 PDF 생성이 올바르게 완료되도록 이를 await해야 합니다. 자신의 코드에서 유사한 메서드는 값을 반환할 수도 있으며, 이 경우 async Task<TResult>로 선언됩니다.
목록 만들기
목록이란 무엇일까요? 항목이 번호와 함께 한 줄씩 아래로 나열된 집합이라고 생각할 수 있습니다. Layout API는 목록 전용 컨테이너 유형을 제공하지 않지만, 다른 복합 컨테이너를 사용하여 쉽게 구현할 수 있습니다.
var dayNames = DateTimeFormatInfo.InvariantInfo.DayNames;
var dayNamesSpain = DateTimeFormatInfo.GetInstance(new CultureInfo("es-ES")).DayNames;
PdfDocumentBuilder.Create().Generate("list.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
pages.Content().Column(column =>
{
for (int i = 0; i < dayNames.Length; i++)
{
column.Item().Row(row =>
{
row.Spacing(5);
row.AutoItem().Text($"{i + 1}.");
row.RelativeItem().Text(t =>
{
t.Line(dayNames[i]);
t.Line($"In Spain they call it {dayNamesSpain[i]}");
});
});
}
});
}));
샘플 코드는 목록을 행들의 열로 생성합니다. 각 행에는 두 항목이 있습니다. 첫 번째 항목(왼쪽)은 항목 번호를 담고, 두 번째 항목(오른쪽)은 항목 텍스트를 담습니다. 코드는 각 행의 항목 사이 간격을 명시적으로 설정합니다.
항목을 배치하려면 Row 컨테이너는 각 항목의 크기를 명시적으로 지정하거나 직접 계산해야 합니다. 이 예제에서는 AutoItem 및 RelativeItem 메서드가 사용됩니다. 그 결과 행 컨테이너는 첫 번째 항목에 필요한 너비를 계산한 뒤 남은 사용 가능한 너비를 두 번째 항목에 사용합니다.
이러한 접근 방식을 사용하고 필요에 따라 행의 모양을 조정하면 문서의 레이아웃과 스타일에 가장 잘 맞는 목록을 만들 수 있습니다.
표 만들기
많은 PDF 문서에는 표가 포함됩니다. 표가 데이터의 명확성과 조직화를 향상시키기 때문에 이는 당연합니다. 이 섹션에서는 Layout API를 사용하여 PDF에 표를 만드는 방법을 보여줍니다.
public static void AddTable()
{
PdfDocumentBuilder.Create().Generate("table.pdf", doc => doc.Pages(pages =>
{
pages.Size(PdfPaperSize.A6);
var color = new PdfGrayColor(75);
pages.Content().Padding(20).Table(t =>
{
t.Columns(c =>
{
c.RelativeColumn(4);
c.RelativeColumn(1);
c.RelativeColumn(4);
});
t.Header(h =>
{
h.Cell().Background(color).Text("Month");
h.Cell().Background(color).Text("Days");
h.Cell().Background(color).Text("First Day");
});
var year = DateTime.Now.Year;
for (int yearDiff = 0; yearDiff < 4; yearDiff++)
{
for (int i = 11; i >= 0; i--)
{
var stats = GetMonthStats(year - yearDiff, i);
t.Cell().Text(stats.Item1);
t.Cell().Text(stats.Item2);
t.Cell().Text(stats.Item3);
}
}
});
}));
}
private static (string, string, string) GetMonthStats(int year, int monthIndex)
{
return (
$"{DateTimeFormatInfo.InvariantInfo.MonthNames[monthIndex]} {year}",
DateTime.DaysInMonth(year, monthIndex + 1).ToString(),
new DateTime(year, monthIndex + 1, 1).DayOfWeek.ToString()
);
}
샘플 코드는 현재 연도와 이전 3년의 월에 대한 기본 정보를 표시하는 간단한 표를 생성합니다. 코드는 상대적 너비를 가진 세 개의 열을 정의합니다. 가장 왼쪽과 가장 오른쪽 열은 가운데 열보다 네 배 더 넓습니다.
코드는 각 헤더 셀을 추가하고 셀마다 텍스트와 배경색을 지정하여 표 머리글도 정의합니다. 표가 한 페이지에 들어가지 않으면 머리글은 표가 차지하는 모든 페이지에서 반복됩니다. 샘플 코드로 생성된 PDF에서 이러한 동작을 볼 수 있습니다.
행을 만들기 위해 두 개의 단순한 루프를 사용합니다. 바깥쪽 루프는 연도를 순회하고, 안쪽 루프는 월을 역순으로 순회합니다. 안쪽 루프는 각 월에 대한 정보를 가져온 다음 세 개의 셀을 추가하여 행을 구성합니다.
자세한 내용은 Table 컨테이너의 기능을 깊이 있게 설명하는 문서를 참조하세요.
내부 PDF 링크 만들기
PDF 문서는 독자가 같은 파일 내의 다른 위치로 이동할 수 있는 내부 링크를 지원합니다. PDF 뷰어에서 이러한 링크는 클릭 가능한 텍스트 또는 이미지 요소로 나타납니다. 외부 웹사이트를 가리키는 대신 문서 내부로 이동한다는 점을 제외하면 하이퍼링크처럼 동작합니다.

많은 PDF 문서는 북마크나 목차에 내부 링크를 사용하여 독자가 섹션 사이를 빠르게 이동하도록 돕습니다. Layout API를 사용하여 문서 섹션에 링크를 추가하는 방법은 다음과 같습니다:
PdfDocumentBuilder.Create().Generate("link.pdf", doc =>
{
doc.Pages(pages =>
{
pages.Content().Column(c =>
{
const string SectionName = "Chapter 1";
c.Item().SectionLink(SectionName).Text("Link");
c.Item().PageBreak();
c.Item().Section(SectionName).Text("Target");
});
});
});
샘플 코드는 첫 번째 페이지의 텍스트를 지정한 이름의 섹션으로 연결되는 링크로 만듭니다. 이는 텍스트가 들어 있는 레이아웃 컨테이너에서 SectionLink 메서드를 호출함으로써 수행됩니다. 이 시점에서 해당 섹션이 아직 존재하지 않아도 됩니다. 텍스트는 PDF 뷰어에서 클릭 가능해집니다.
그런 다음 코드는 두 번째 페이지의 텍스트를 같은 이름의 섹션 시작 지점으로 표시합니다. 외형과 동작은 변하지 않지만, 첫 번째 페이지 링크의 대상이 됩니다. 이는 해당 레이아웃 컨테이너에서 Section 메서드를 호출하여 수행됩니다.
이 예제에서는 링크와 대상 모두 텍스트 스팬이지만, 어떤 레이아웃 컨테이너에도 섹션과 링크를 만들 수 있습니다. 이미지 컨테이너, 표 컨테이너 또는 직접 구성한 컨테이너일 수도 있습니다.
샘플 저장소에서 PDF 목차 만들기의 예제를 참조하세요.
복잡한 PDF 레이아웃 설계
Layout API는 임의로 복잡한 PDF 문서를 만들기 위해 조합할 수 있는 다양한 레이아웃 컨테이너를 제공합니다. 자신만의 사용자 지정 구성 요소로 API를 확장할 수도 있습니다.
이 페이지의 예제는 의도적으로 단순하게 구성되어 있습니다. 핵심 아이디어에 집중할 수 있도록 직관적인 문서를 만드는 데 초점을 맞췄기 때문입니다. 서로 다른 컨테이너를 조합하여 더 복잡한 PDF를 생성하는 방법을 보고 싶다면 GitHub의 샘플 저장소에 있는 해당 예제를 살펴보세요.
내장 컨테이너를 사용하는 것 외에도 사용자 지정 레이아웃 구성 요소를 정의하고 사용할 수 있습니다. 이러한 구성 요소는 데이터와 레이아웃 논리를 하나의 클래스에 함께 캡슐화하고 싶을 때 특히 유용합니다. 모든 것을 한곳에 두면 구성 요소를 이해하고 수정하고 재사용하기가 쉬워지며, 복잡한 레이아웃을 처리하는 유연한 방법도 제공합니다.
사용자 지정 레이아웃 구성 요소를 만들려면 클래스에서 ILayoutComponent 인터페이스를 구현하세요. PDF를 생성할 때 라이브러리는 인터페이스의 Compose 메서드를 호출하고 LayoutContext 개체를 제공합니다. 코드는 이 개체를 사용하여 레이아웃 요소를 만들고 생성 중인 문서에 대한 정보를 액세스할 수 있습니다.
사용자 지정 레이아웃 구성 요소를 레이아웃에 추가하려면 LayoutContainer 클래스의 Component 메서드를 호출하세요. 크기 조정과 위치 지정 측면에서 사용자 지정 구성 요소는 텍스트나 이미지와 똑같이 동작합니다.
ILayoutComponent 인터페이스로 사용자 지정 구성 요소를 구현하는 예제는 레이아웃 구성 요소 샘플을 참조하세요.
PDF를 만드는 다른 방법
Docotic.Pdf는 다양한 시나리오에 적합한 여러 PDF 생성 방식을 제공합니다. 이 섹션에서는 언제 Layout API에 의존해야 하는지, 그리고 언제 다른 접근 방식이 더 적합한지 설명합니다.
Layout API를 선호해야 하는 경우
Docotic.Pdf Layout API는 구조화된 레이아웃에서 PDF를 생성하는 강력한 방법입니다. 텍스트, 이미지, 컨테이너, 표를 조합하여 임의로 복잡한 중첩 구조의 문서를 만들 수 있습니다. 생성 과정은 빠르고 메모리 사용량이 적당하며 예측 가능하게 동작합니다.
Docotic.Pdf와 Layout 추가 기능은 가볍고 완전히 독립적인 세트를 구성합니다. 이 API는 PDF 생성에 외부 라이브러리나 브라우저를 필요로 하지 않습니다. 따라서 .NET 마이크로서비스, 클라우드 애플리케이션(특히 서버리스 애플리케이션), 그리고 풋프린트 크기가 중요한 다른 환경에 적합합니다.
문서 레이아웃이 코드로 정의되므로 어떤 부분이든 단위 테스트할 수 있습니다. 레이아웃 논리는 다른 코드처럼 재사용할 수 있으며, 사용자 지정 구성 요소에 데이터와 레이아웃 동작을 모두 캡슐화할 수 있습니다.
Layout API의 대안
전용 문서에서는 Docotic.Pdf로 PDF를 만드는 모든 방법을 자세히 비교합니다. 아래는 가장 자주 사용되는 대안 몇 가지입니다.
-
HTML을 PDF로 변환
기존 HTML/CSS 템플릿을 재사용합니다. 팀이 이미 HTML/CSS로 문서를 만들고 있고 해당 문서의 PDF 버전이 필요할 때 HTML-to-PDF 접근 방식을 선택하세요. -
저수준 PDF 생성
라이브러리에서 PDF 구조와 콘텐츠에 대해 가능한 최대 제어를 제공합니다. 픽셀 수준 위치 지정이나 복잡한 벡터 그래픽이 필요할 때 이 접근 방식을 선택하세요. 성능이 중요한 시나리오나 가능한 가장 작은 풋프린트가 필요한 경우에 권장됩니다. -
템플릿 기반 PDF 생성
요소를 설계하거나 배치하지 않고 문서를 빠르고 예측 가능하게 채울 수 있습니다. 승인되었거나 규정 통제되는 템플릿처럼 미리 정의된 PDF 구조가 있고, 텍스트 필드 변경, 자리 표시자 교체, 관련 문서 첨부, 유사 작업만 필요할 때 선택하세요. -
PDF 병합 및 구성
처음부터 만드는 대신 기존 조각으로 PDF를 생성할 수 있습니다. 이미지, 스캔한 페이지 또는 다른 PDF를 하나의 파일로 결합해야 할 때 선택하세요.
다른 PDF 생성 솔루션과의 비교
이 섹션에는 두 개의 비교 표가 있습니다. 하나는 핵심 요약이고, 다른 하나는 Layout 추가 기능이 포함된 Docotic.Pdf가 다른 인기 있는 PDF 생성 솔루션과 어떻게 비교되는지에 대한 자세하고 구조화된 정보입니다.
비교의 핵심 요점
서명, 암호화, 문서 병합 같은 기능이 다르기 때문에, 무료 솔루션을 포함한 강력한 선택지가 있습니다. 그러나 실제로 요구 사항에 맞는 도구는 제한될 수 있습니다.
| 솔루션 | 사용 시점 | 가장 적합한 용도 |
|---|---|---|
| Layout 추가 기능이 포함된 Docotic.Pdf | 플랫폼 전반에서 서명, 암호화, PDF 편집을 고급으로 지원하면서 최적화된 PDF를 생성할 수 있는 고품질 고성능 레이아웃 엔진이 필요할 때 | 뛰어난 개발자 경험과 함께 송장, 보고서, 명세서 및 유사 문서의 고품질 생성. 엔터프라이즈급 PDF 처리와 전문 지원이 필요할 때 이상적 |
| PDFsharp + MigraDoc | 기본 PDF 생성을 위한 무료 MIT 라이선스 라이브러리가 필요하고 디지털 서명이나 최신 암호화 알고리즘이 필요하지 않을 때 | 오픈 소스 또는 예산이 제한된 프로젝트에서의 단순한 문서 생성 |
| QuestPDF | PDF 생성 전용의 최신 레이아웃 엔진이 필요하고 편집, 서명 또는 암호화가 필요하지 않을 때 | 생성 외 기능은 다른 곳에서 처리된다는 전제하에 MIT 또는 저비용 상용 라이선스로 고품질 PDF 생성 |
| iText | PDF 생성과 처리 모두에 대해 성숙하고 기능이 풍부한 PDF 툴킷이 필요하며, 솔루션을 AGPL/GPLv3 라이선스 아래 오픈 소스로 공개하거나 비싼 상용 라이선스를 구매할 준비가 되어 있을 때 | iText API에 이미 익숙하여 가파른 학습 곡선의 영향을 받지 않는 팀 |
상세 비교
표를 검토하여 더 넓은 맥락을 이해하고 스스로 결론을 내려 보세요.
| Layout이 포함된 Docotic.Pdf | PDFsharp + MigraDoc | QuestPDF | iText | |
|---|---|---|---|---|
| PDF 기능 | 모든 기능을 갖춘 PDF 라이브러리 | PDF 생성 및 제한된 편집 | PDF 생성 전용 | 광범위한 PDF 기능 |
| 렌더링 모델 | 최신 선언형 보존 모드 레이아웃 엔진 | 박스 기반 레이아웃 엔진 | 최신 선언형 보존 모드 레이아웃 엔진 | 박스 기반 레이아웃 엔진 + 렌더러 트리 |
| API 유형 | 플루언트 API | 명령형 API | 플루언트 API | 명령형 API |
| 개발자 경험 | 뛰어남. API가 깔끔하고 현대적이며 직관적임 | 좋음. API 설계가 전통적임 | 뛰어남. API가 깔끔하고 현대적이며 직관적임 | 보통. API가 장황하고 지나치게 복잡함 |
| 글꼴 부분 집합화 | 지원됨; 기본적으로 사용된 글리프만 포함됨 | 지원되지 않음; 불필요하게 큰 PDF가 될 수 있음 | 지원됨; 기본적으로 사용된 글리프만 포함됨 | 지원됨; 기본적으로 사용된 글리프만 포함됨 |
| 오른쪽에서 왼쪽(RTL) 콘텐츠 방향 | 지원됨 | 지원되지 않음 | 지원됨 | 지원됨 |
| 디지털 서명 | LTV 및 외부 서명을 포함해 지원됨 | 지원되지 않음 | 지원되지 않음 | LTV 및 외부 서명을 포함해 지원됨 |
| 암호화 / 권한 | 완전히 지원됨 | RC4 암호화만 지원, AES 또는 인증서 지원 없음 | 지원되지 않음 | 완전히 지원됨 |
| 외부 종속성 | 없음 | 없음 | SkiaSharp / Skia 기반 구성 요소 | 없음 |
| 지원 | 잠재 고객과 고객을 위한 전문 지원; 최상위 라이선스는 우선 지원 제공 | 커뮤니티 지원; 전문 지원은 별도 구매 가능 | GitHub를 통한 커뮤니티 지원 | AGPL 버전은 커뮤니티 지원; 상용 라이선스 보유자는 전문 지원 |
| 라이선스 | 상용, 자격이 있는 사용 사례에는 무료 라이선스 제공 | MIT | 개인 및 소규모 회사는 MIT; 대규모 기업에는 상용 라이선스 필요 | 오픈 소스 사용에는 AGPL, 독점 프로젝트에는 비싼 상용 라이선스 |
| 개발자 라이선스 | 모든 라이선스에서 개발자 수 무제한 | 모든 라이선스에서 개발자 수 무제한 | MIT는 개발자 수 무제한; Professional은 10명; Enterprise는 무제한 | AGPL 버전은 개발자 수 무제한; 상용 라이선스는 개발자별 과금 |
결론
Layout 추가 기능이 포함된 Docotic.Pdf는 C# 및 VB.NET에서 PDF를 생성하는 현대적이고 고성능이며 고품질의 방법을 제공합니다. 이 라이브러리는 보고서, 명세서, 송장 및 유사 문서를 생성합니다. 잘 설계된 플루언트 API는 뛰어난 개발자 경험을 제공합니다. Bit Miracle이 Docotic.Pdf와 그 추가 기능에 대해 제공하는 전문 지원에 의지할 수 있습니다.
다른 일부 PDF 생성 솔루션과 달리 Docotic.Pdf는 모든 기능을 갖춘 PDF API입니다. 이 라이브러리는 LTV 지원 서명을 포함한 디지털 서명으로 생성된 PDF에 서명할 수 있습니다. Docotic.Pdf는 USB 토큰과 스마트 카드 같은 보안 하드웨어에 저장된 인증서 사용이 가능합니다. Microsoft Azure Key Vault 및 AWS Key Management Service(KMS) 같은 클라우드 기반 하드웨어 보안 모듈(HSM)도 지원됩니다.
Docotic.Pdf를 사용하면 스프레드시트나 음성 메모와 같은 보조 문서를 첨부하여 생성된 PDF에 포함할 수 있습니다. 웹 페이지나 유사한 인터페이스에서 문서를 표시하려면 하나 이상의 페이지에서 썸네일 이미지 생성을 할 수 있습니다.
다음 단계: