이 페이지에는 자동 번역된 텍스트가 포함될 수 있습니다.

복합용기

복잡한 컨테이너는 콘텐츠를 구조화하고 구성하는 데 중요한 역할을 합니다. 적절한 컨테이너를 사용하면 텍스트와 이미지를 사용자 친화적인 방식으로 쉽게 표현할 수 있습니다.

간단한 텍스트와 이미지 컨테이너만 사용하여 문서를 구성하는 것은 확실히 가능합니다. 하지만 단순한 컨테이너만으로는 구현하기 어렵거나 불가능한 요구사항이 있습니다. 이러한 경우에는 복합 용기가 도움이 됩니다. 또한 복잡한 컨테이너는 더 적은 코드로 목표를 달성하는 데 도움이 됩니다.

복합용기

문서 페이지에 RowColumn 과 같은 복잡한 컨테이너를 추가하려면 LayoutContainer 클래스의 메서드를 사용하세요. 이러한 컨테이너를 사용하면 그리드 및 목록과 같은 다른 컨테이너를 구현할 수 있습니다. 덜 일반적이지만 여전히 중요한 경우를 위한 InlinedLayers 메서드도 있습니다.

이 기사는 PDF 생성을 위한 Layout API에 관한 시리즈의 일부입니다. API를 처음 사용하는 경우 Layout API 시작하기 부분을 먼저 읽어보세요.

Docotic.Pdf 라이브러리 9.5.17573-dev 레이아웃 애드온 9.5.17573-dev
회귀 테스트 14,726건의 테스트 통과 총 NuGet 다운로드 4,765,230

Row

Row 컨테이너는 한 줄에 수평으로 배열된 항목을 위한 공간을 제공합니다. 행의 각 항목은 컨테이너입니다. 즉, 다양한 유형의 콘텐츠를 한 행에 넣을 수 있습니다. Spacing 방법을 사용하여 항목 사이의 간격을 지정할 수 있습니다.

연속된 모든 항목의 높이는 동일합니다. 라이브러리는 가장 높은 항목의 높이를 행 높이로 사용합니다. 항목의 너비를 지정하는 세 가지 방법이 있습니다. 항목을 생성할 때 하나를 선택해야 합니다. 행에는 다양한 방법으로 생성된 항목이 포함될 수 있습니다.

Row.AutoItem 메서드는 명시적으로 지정된 너비 없이 항목을 생성합니다. 이러한 항목의 경우 라이브러리는 해당 콘텐츠의 고유 크기를 계산합니다. 계산된 콘텐츠 너비는 항목의 너비입니다. AutoItem 으로 생성된 항목은 긴 줄을 줄바꿈하지 않습니다.

정확한 포인트 수와 동일한 너비를 가진 항목을 생성하려면 ConstantItem 메서드를 사용하세요.

RelativeItem 은 행에 있는 항목의 정확한 너비를 모르고 고유 크기를 사용하고 싶지 않을 때 유용합니다. 대신 행 항목의 상대적 너비를 지정할 수 있습니다. 이 메서드는 항목이 차지해야 하는 부품 수를 허용합니다. 총 부품 수는 이 행의 모든 ​​RelativeItem 호출에 있는 모든 숫자의 합계입니다.

예를 들어 RelativeItem 호출이 하나 있는 경우 숫자는 중요하지 않습니다. 항목은 사용 가능한 모든 너비를 차지합니다. 두 개 이상의 항목에 대해 숫자는 비율을 정의합니다.

row.RelativeItem(2)
row.RelativeItem(3)
row.RelativeItem(1)

위 코드로 생성된 모든 항목은 6개 부분(2 + 3 + 1 = 6)으로 구성됩니다. 개별 항목은 각각 6개 중 2개, 6개 중 3개, 6개 부품 중 1개를 차지합니다.

Layout API는 다음 공식을 사용하여 한 부분의 너비를 계산합니다.

PartWidth = (RowWidth - AutoWidth - ConstantWidth) / TotalParts

어디:
RowWidth = 행 컨테이너의 너비
AutoWidth = AutoItem 메서드로 생성된 모든 항목의 너비
ConstantWidth = ConstantItem 메서드로 생성된 모든 항목의 너비

다음은 세 가지 종류의 항목이 모두 포함된 행을 생성하는 예입니다.

var monthNames = DateTimeFormatInfo.InvariantInfo.MonthNames;
var groups = new[]
{
    string.Join(", ", monthNames.Take(4)),
    string.Join(", ", monthNames.Skip(4).Take(4)),
    string.Join(", ", monthNames.Skip(8).Take(4)),
};

PdfDocumentBuilder.Create().Generate("compounds-row.pdf", doc => doc.Pages(page =>
{
    page.Content()
        .Padding(20)
        .MinimalBox()
        .Row(row =>
        {
            row.ConstantItem(100)
                .Background(new PdfRgbColor(187, 237, 237))
                .Text("100 points wide");

            for (int i = 0; i < groups.Length; i++)
            {
                row.AutoItem().LineVertical(0.1);

                var numberOfParts = groups.Length - i + 1;
                row.RelativeItem(numberOfParts)
                    .PaddingHorizontal(5)
                    .Text(t =>
                    {
                        t.Line($"{numberOfParts} parts wide");
                        t.Line();
                        t.Line(groups[i]);
                    });
            }
        });
}));

compounds-row.pdf에서 코드 결과를 확인할 수 있습니다.

Column

항목을 수직으로 하나씩 정렬하려면 Column 컨테이너를 사용하세요. 열의 각 항목은 컨테이너입니다. 이로 인해 하나의 열에 다양한 유형의 콘텐츠를 넣을 수 있습니다.

각 항목의 너비는 열 너비와 같습니다. 각 항목의 높이는 항목의 내용과 속성에 따라 다릅니다. Column 컨테이너는 페이징을 지원하므로 Layout 추가 기능은 둘 이상의 페이지에 있는 열 항목을 렌더링할 수 있습니다.

기본적으로 Column 컨테이너에는 머리글이나 바닥글 콘텐츠가 없습니다. 해당 컨테이너에 액세스하고 설정하려면 HeaderFooter 메소드를 사용하세요. 열 항목이 두 페이지 이상을 차지하는 경우 라이브러리는 각 페이지에서 머리글과 바닥글을 모두 반복합니다.

열 항목 사이에 수직 공간을 추가하려면 Spacing 방법을 사용하세요. 라이브러리는 헤더와 첫 번째 항목 사이에 공백을 적용하지 않습니다. 라이브러리는 또한 바닥글 앞에 공간을 추가하지 않습니다.

PdfDocumentBuilder.Create().Generate("compounds-column.pdf", doc => doc.Pages(page =>
{
    page.Size(PdfPaperSize.A6);

    page.Content()
        .Padding(20)
        .Column(column =>
        {
            column.Header()
                .Background(new PdfRgbColor(187, 237, 237))
                .Padding(5)
                .Text("Month names");

            for (int i = 0; i < 12; i++)
            {
                column.Item().Background(
                    new PdfGrayColor(i % 2 == 0 ? 90 : 100))
                    .Padding(5)
                    .Text(DateTimeFormatInfo.InvariantInfo.MonthNames[i]);
            }

            column.Footer().LineHorizontal(1);
        });
}));

compounds-column.pdf에서 코드 결과를 확인할 수 있습니다.

그리드

그리드 레이아웃은 항목을 열과 행으로 구성합니다. 그리드는 이러한 측면에서 테이블과 유사합니다. Layout API 는 그리드에 대한 특수 컨테이너 유형을 제공하지 않습니다. ColumnRow 컨테이너를 사용하여 그리드 레이아웃을 구현할 수 있습니다.

그리드를 열로 생각하면 도움이 됩니다. 각 항목은 행입니다. ColumnRow 컨테이너 모두 항목 사이의 간격을 설정하는 기능을 제공합니다. 원하는 경우 머리글과 바닥글을 가질 수 있습니다.

각 행은 독립적인 레이아웃을 가질 수 있습니다. 각 행에는 항목 수가 다를 수 있습니다. 항목의 너비와 높이가 다를 수 있습니다. 행의 항목 앞, 뒤 또는 사이에 추가 공간을 추가할 수 있습니다. 이를 위해 내용과 장식이 없는 항목을 사용하십시오.

var blue = new PdfRgbColor(187, 237, 237);
var darkerBlue = blue.Darken(50);
PdfDocumentBuilder.Create().Generate("compounds-grid.pdf", doc => doc.Pages(page =>
{
    page.Size(300, 200);

    page.Content().Padding(15).Column(column =>
    {
        column.Spacing(10);

        column.Item().Row(row =>
        {
            row.Spacing(10);

            row.ConstantItem(100).Background(darkerBlue).Height(40);
            row.RelativeItem(4).Background(blue);
        });

        column.Item().Row(row =>
        {
            row.Spacing(10);

            row.RelativeItem(2).Background(blue).Height(60);
            row.RelativeItem(1);
            row.RelativeItem(2).Background(blue);
        });

        column.Item().Row(row =>
        {
            row.Spacing(10);

            row.RelativeItem(1).Background(blue).Height(50);
            row.RelativeItem(3).Background(blue);
            row.ConstantItem(50).Background(darkerBlue);
        });
    });
}));

compounds-grid.pdf에서 코드 결과를 확인할 수 있습니다.

기울기

목록은 정보를 간결한 항목으로 나누어 가독성을 높입니다. 목록 항목의 텍스트 옆에는 숫자, 글머리 기호 및 기타 기호가 있을 수 있습니다. ColumnRow 컨테이너를 사용하여 목록 레이아웃을 쉽게 구현할 수 있습니다. Layout API는 목록에 대한 특별한 컨테이너 유형을 제공하지 않습니다.

계절별 월 목록을 생성하는 예제 코드를 확인해보세요. 목록에는 헤더가 있습니다. 항목에 다음 줄로 넘어갈 수 있는 텍스트가 포함되어 있는 경우 항목의 텍스트 부분에 RelativeItem 또는 ConstantItem 메서드를 사용하세요.

var monthNames = DateTimeFormatInfo.InvariantInfo.MonthNames.ToList();
monthNames.Insert(0, monthNames[11]);

PdfDocumentBuilder.Create().Generate("compounds-list.pdf", doc => doc.Pages(page =>
{
    page.Size(150, 200);

    page.Content().Padding(5).Column(column =>
    {
        column.Header()
            .Text("Months by seasons:")
            .Style(TextStyle.Parent.Underline());

        for (int i = 0; i < 4; i++)
        {
            var season = string.Join(", ", monthNames.Skip(i * 3).Take(3));
            column.Item().Row(row =>
            {
                row.Spacing(2);

                row.AutoItem().Text("•");
                row.RelativeItem().Text(season);
            });
        }
    });
}));

compounds-list.pdf에서 코드 결과를 확인할 수 있습니다.

Table

테이블 레이아웃은 항목을 열과 행으로 구성합니다. Table 컨테이너 유형은 광범위한 기능 세트를 제공하며 가장 정교한 사례에 도움이 될 수 있습니다. Table 컨테이너 문서에서 모든 기능에 대해 읽어보세요.

InlineContainer

컨테이너를 다른 컨테이너 컬렉션으로 채울 수 있습니다. LayoutContainer.Inlined 메서드를 호출하여 시작하세요. 그런 다음 제공된 InlineContainerItem 메서드를 호출하여 하위 컨테이너를 추가합니다.

Layout 추가 기능은 컨테이너를 차례로 한 줄로 배치합니다. 항목을 넣을 공간이 없으면 라이브러리는 새 행을 시작합니다. 항목 사이에 공간을 추가하려면 Spacing/HorizontalSpacing/VerticalSpacing 메서드를 사용하세요.

정렬 방법을 사용하여 컨테이너의 항목 위치에 영향을 줄 수 있습니다. AlignTop/AlignMiddle/AlignBottom 메서드는 항목을 수직으로 정렬합니다. 가로 방향의 경우 AlignLeft/AlignCenter/AlignRight/AlignJustify 메서드를 사용하세요.

특별한 경우가 있습니다. 항목을 수평으로 정렬하는 AlignSpaceAround 메서드. 또한 첫 번째 항목 앞과 마지막 항목 뒤에 추가 간격을 추가합니다.

var orange = new PdfRgbColor(250, 123, 5);
var brown = orange.Darken(50);
var itemProps = new (int Width, PdfColor Color)[] {
    (20, orange), (30, orange), (50, brown), (50, orange), (50, orange),
    (30, orange), (20, brown), (30, orange), (50, brown), (10, brown)
};

PdfDocumentBuilder.Create().Generate("compounds-inlined.pdf", doc => doc.Pages(page =>
{
    page.Size(150, 120);

    page.Content().Inlined(c =>
    {
        c.Spacing(5);

        foreach (var (Width, Color) in itemProps)
            c.Item().Height(30).Width(Width).Background(Color);
    });
}));

compounds-inlined.pdf에서 코드 결과를 확인할 수 있습니다.

LayerContainer

기본 페이지 콘텐츠 아래 및/또는 위에 일부 콘텐츠를 배치해야 할 수도 있습니다. 확실한 사용 사례는 PDF 페이지 위에 워터마크를 추가하는 것입니다.

먼저 LayoutContainer.Layers 메서드를 호출하여 LayerContainer 개체를 가져옵니다. 객체가 주어지면 레이어 추가를 시작할 수 있습니다. Layer 메서드를 호출하면 보조 레이어가 추가됩니다. 기본 콘텐츠 레이어를 추가하려면 PrimaryLayer 메서드를 호출하세요. 정확히 하나의 기본 레이어를 추가해야 합니다.

Layout API는 레이어를 생성할 때와 동일한 순서로 레이어를 구성합니다. 기본 레이어 앞에 추가된 레이어는 배경으로 이동됩니다. 기본 레이어 뒤에 추가된 모든 레이어는 기본 콘텐츠 위로 이동합니다. 컨테이너는 주요 콘텐츠가 차지하는 모든 페이지에서 보조 레이어를 반복합니다.

PDF 페이지에 워터마크를 추가하는 방법에 대한 샘플 코드는 다음과 같습니다.

PdfDocumentBuilder.Create().Generate("compounds-layers.pdf", doc => doc.Pages(page =>
{
    var largeRedText = TextStyle.Parent.FontSize(48)
        .FontColor(new PdfRgbColor(235, 64, 52));

    page.Size(400, 250);

    page.Content()
        .Padding(25)
        .Layers(layers =>
        {
            layers.Layer()
                .AlignCenter()
                .Text(text => text.CurrentPageNumber().Style(largeRedText));

            layers.PrimaryLayer()
                .Background(new PdfGrayColor(85), 65)
                .Padding(25)
                .Text(new string('_', 790));

            layers.Layer()
                .AlignCenter()
                .AlignMiddle()
                .Text("Watermark")
                .Style(largeRedText);
        });
}));

compounds-layers.pdf에서 코드 결과를 확인할 수 있습니다.

워터마크

일반적인 요구 사항 중 하나는 PDF에 워터마크를 추가하는 것입니다. 요구사항은 다양한 이유로 존재할 수 있습니다. PDF에 워터마크를 추가하여 소유권을 식별하거나 PDF에 있는 정보의 기밀성 또는 민감성을 지적할 수 있습니다.

PDF에 워터마킹을 적용하는 한 가지 접근 방식은 레이어를 사용하는 것입니다. 이전 섹션의 예를 참조하세요. 또 다른 접근법을 보여드리겠습니다.

페이지 배경 및 전경 컨테이너를 사용하여 PDF에 워터마크를 표시하겠습니다. Layout 추가 기능은 다음 페이지에서 이러한 컨테이너를 반복합니다. 기본 문서 콘텐츠가 있는 모든 페이지에는 배경 및 전경 컨테이너도 포함됩니다. 이는 작업에 적합하게 만듭니다.

먼저 배경 컨테이너에 이미지를 추가합니다. 같은 방법으로 PDF에 로고를 추가할 수 있습니다. 이미지는 페이지 콘텐츠 뒤에 표시됩니다. 문서에서 배경 이미지를 사용하는 페이지 수는 중요하지 않습니다. API는 생성된 PDF에 이미지 바이트 사본 하나만 추가합니다.

주요 문서 내용은 무엇이든 될 수 있습니다. 이 샘플 코드에서는 유명한 Lorem Ipsum 텍스트를 사용합니다.

텍스트 워터마크는 전경 컨테이너에 들어갑니다. 텍스트 자체는 무엇이든 될 수 있으며 어떤 색상이나 글꼴도 사용할 수 있습니다. 더 큰 크기의 반투명 빨간색 글자로 그려진 회전된 텍스트를 사용했습니다.

샘플 코드는 샘플 코드 저장소에서 이미지와 텍스트를 모두 비동기적으로 다운로드합니다. 물론 로컬 이미지를 사용하거나 파일에서 텍스트를 읽을 수 있습니다.

var urlPrefix =
    "https://raw.githubusercontent.com/BitMiracle/Docotic.Pdf.Samples/master/Samples/Sample%20Data/";

using var client = new HttpClient();
using var imageResponse = await client.GetAsync(urlPrefix + "watermark-background.png");
using var imageStream = await imageResponse.Content.ReadAsStreamAsync().ConfigureAwait(false);

var loremIpsum = string.Empty;
using (var textResponse = await client.GetAsync(urlPrefix + "lorem-ipsum.txt"))
     loremIpsum = await textResponse.Content.ReadAsStringAsync().ConfigureAwait(false);

PdfDocumentBuilder.Create().Generate("compounds-watermarks.pdf", doc =>
{
    var image = doc.Image(imageStream);

    doc.Pages(page =>
    {
        page.Size(400, 250);

        page.Background()
            .AlignMiddle()
            .Image(image);

        page.Content()
            .Padding(25)
            .Text(loremIpsum);

        var largeRedText = TextStyle.Parent.FontSize(48)
            .FontColor(new PdfRgbColor(235, 64, 52), 50);
        page.Foreground()
            .Rotate(-30)
            .Translate(-50, 180)
            .Text("DO NOT COPY")
            .Style(largeRedText);
    });
});

compounds-watermarks.pdf에서 코드 결과를 확인할 수 있습니다.

샘플 코드

앞서 언급한 기능을 더 자세히 다루는 몇 가지 샘플 앱이 있습니다. 시간을 내어 확인해 보세요.