該頁面可以包含自動翻譯的文字。

複合容器

複雜容器在建構和組織內容方面發揮著至關重要的作用。透過使用適當的容器,您可以輕鬆地以使用者友好的方 式呈現文字和圖像。

僅使用簡單的文字和圖像容器來建立文件絕對是可能的。不過,有些要求只使用簡單的容器很難或不可能實現。 複合容器在這種情況下會有所幫助。此外,複雜的容器有助於以更少的程式碼實現您的目標。

複合容器

使用 LayoutContainer 類別的方法將 RowColumn 等複雜 容器新增至文件頁面。使用這些容器,您可以實作其他容器,例如網格和清單。還有 InlinedLayers 方 法,用於不太常見但仍然重要的情況。

本文是用於 PDF 產生的 La​​yout API 的系列文章的一部分。 如果您是 API 新手,請先閱讀 Layout API 入 門 部分。

Docotic.Pdf 函式庫 9.4.17467-dev 佈局附加元件 9.4.17467-dev
回歸測試 14,760 已通過 NuGet 總下載量 4,415,970

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 沒有為清單提供特殊的容 器類型。

檢查按季節建立月份清單的範例程式碼。請注意,該清單有一個標題。如果項目包含可以換行到下一行的文本, 請對項目的文本部分使用 RelativeItemConstantItem 方法。

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/Horizo​​ntalSpacing/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 中看到程式 碼的結果。

範例程式碼

我們有一些範例應用程序,更詳細地涵蓋了上述功能。請花一些時間檢查一下。