Эта страница может содержать автоматически переведенный текст.

Контейнеры и их содержимое

Документ представляет собой набор страниц. Каждая страница, в свою очередь, представляет собой набор фрагментов контента. Как вы, возможно, уже знаете, PageLayout предоставляет контейнеры для основного и дополнительного контента. Но что делать с этими контейнерами?

Контейнеры для содержимого страницы

Контейнеры помогают организовать контент на страницах. Все, что вы помещаете на страницу, должно попасть в контейнер. Если содержимое достаточно велико, контейнер может занимать место более чем на одной странице.

Вы можете поместить в контейнер текст или изображение. В целях выравнивания и позиционирования вы можете поместить контейнер внутрь другого контейнера. Существуют контейнеры, в которых можно разместить более одного фрагмента контента.

Контейнеры на странице представлены объектами класса LayoutContainer. Используйте этот класс для настройки размера, положения, содержимого и процесса рендеринга ваших контейнеров.

Эта статья - часть серии статей про Layout API для генерации PDF-файлов. Если вы новичок в работе с API, то сначала прочитайте часть Начало работы с Layout API.

Библиотека Docotic.Pdf 9.3.17105-dev Дополнение Layout 9.3.17105-dev
Регрессионные тесты 14,681 прошло Всего загрузок NuGet 4,234,061

Принцип работы контейнеров

Вы начинаете с получения контейнера. Например, вызвав метод PageLayout.Content. Этот метод вернет контейнер, который не занимает места и не имеет содержимого или свойств. Используйте методы класса LayoutContainer для настройки контейнера.

Очень важно понимать, что все методы LayoutContainer помещают контент в контейнер. Когда вы добавляете в контейнер текст, это ожидаемо. Но что становится содержимым, когда вы устанавливаете отступ или ширину?

Когда вы устанавливаете свойство контейнера, библиотека создает новый контейнер с указанным свойством. Новый контейнер становится содержимым исходного контейнера. Библиотека возвращает вложенный контейнер как результат метода.

Свойства вложенных контейнеров влияют на родительские контейнеры и наоборот. Например, ширина вложенного контейнера влияет на размер родительского контейнера. Стиль текста родительского контейнера по умолчанию влияет на текст во вложенных контейнерах. Дополнение Layout использует иерархию контейнеров и их свойств для создания результирующего макета.

Результат следующего кода может вас удивить, но, пожалуйста, потратьте некоторое время на его анализ. Код иллюстрирует, как работают вложенные контейнеры.

PdfDocumentBuilder.Create().Generate("containers-how.pdf", doc => doc.Pages(page =>
{
    page.Size(150, 150);
    page.Content()
        .Background(new PdfRgbColor(235, 64, 52)) // красный

        .PaddingTop(50)
        .Background(new PdfRgbColor(187, 237, 237)) // голубой

        .PaddingRight(50)
        .Background(new PdfRgbColor(15, 130, 9)) // зеленый

        .PaddingBottom(50)
        .Background(new PdfRgbColor(250, 123, 5)) // оранжевый

        .PaddingLeft(50)
        .Background(new PdfRgbColor(204, 204, 204)); // серый
}));

Украшение

Дизайн документа включает в себя больше, чем просто организацию текста и изображений. Правильно разработанный документ создает не только эффективную, но и визуально привлекательную коммуникацию.

С помощью Layout API вы можете применить цвет фона к любому контейнеру. Это помогает установить иерархию внутри вашего контента. Вы также можете определить границы, применяя рамки. Используйте вертикальные и горизонтальные линии для разделения элементов контента.

PdfDocumentBuilder.Create().Generate("containers-decor.pdf", doc => doc.Pages(page =>
{
    page.Size(150, 150);
    page.Content()
        .Background(new PdfRgbColor(250, 123, 5))
        .Border(b =>
        {
            b.Color(new PdfGrayColor(0), 50);
            b.Thickness(15);
        })
        .PaddingTop(74)
        .LineHorizontal(2)
            .Color(new PdfCmykColor(73, 45, 0, 4))
            .DashPattern(new PdfDashPattern(new double[] { 8, 2 }));
}));

API поддерживает непрозрачные и полупрозрачные цвета в цветовых пространствах Gray, RGB и CMYK. Помимо сплошных линий, Layout API поддерживает линии, в которых используются пунктирные узоры.

Результат работы приведенного выше кода находится в файле containers-decor.pdf.

Содержимое

Давайте посмотрим, что класс LayoutContainer предоставляет для организации содержимого.

Text

Чтобы добавить текст в контейнер, используйте один из методов Text.

Если весь текст использует один и тот же стиль, используйте простую сокращенную версию метода. Эта версия принимает строку и возвращает объект TextSpan. Вы можете использовать результат для настройки стиля текста.

Существует еще одна версия метода Text, которая принимает делегат типа Action<TextContainer>. Используйте эту версию, чтобы иметь фразменты с разными стилями в одном блоке текста. TextContainer предоставляет методы для вставки изображений и других элементов между текстовыми фрагментами. Есть и другие расширенные функции, такие как возможность устанавливать расстояние между абзацами.

PdfDocumentBuilder.Create().Generate("containers-text.pdf", doc => doc.Pages(page =>
{
    page.Header().Text("This is a simple text span");

    page.Content().Text(t =>
    {
        t.Span("This line contains ");
        t.Span("some underlined text").Style(TextStyle.Parent.Underline());
    });
}));

Вы можете увидеть результат выполнения кода в containers-text.pdf.

Image

API Layout предоставляет методы для создания объектов Image из изображений в файле или потоке. Любой объект Image может служить содержимым контейнера. Вы можете использовать один и тот же объект Image в нескольких контейнерах. Существуют различные режимы содержимого, которые влияют на то, как изображение будет выглядеть внутри контейнера.

Библиотека может загружать изображения только в растровых форматах: PNG, JPEG, JPEG 2000, BMP, GIF и TIFF.

PdfDocumentBuilder.Create().Generate("containers-image.pdf", doc =>
{
    var imageFile = new FileInfo(@"path-to-image.jpg");
    var image = doc.Image(imageFile);

    doc.Pages(pages =>
    {
        pages.Size(image.Width, image.Height);
        pages.Content().Image(image, ImageContentMode.FitArea);
    });
});

Column

Столбцы предоставляют место для неограниченного количества элементов, расположенных друг над другом. Внутри столбца можно использовать элементы любого типа. Например, столбец может содержать изображения и текстовые элементы. Ширина каждого элемента равна ширине столбца. Высота каждого элемента зависит от его содержимого и свойств.

PdfDocumentBuilder.Create().Generate("containers-column.pdf", doc => doc.Pages(page =>
{
    page.Content().Column(c =>
    {
        for (int i = 0; i < 10; i++)
        {
            PdfColor color = i % 2 == 0
                ? new PdfRgbColor(187, 237, 237)
                : new PdfGrayColor(66);

            c.Item().Background(color).Height(10 + i * 3);
        }
    });
}));

Вы можете увидеть результат выполнения кода в containers-column.pdf.

Row

Контейнеры Row помогают организовать неограниченное количество элементов в ряд. Каждый элемент в ряду является контейнером. Благодаря этому вы можете размещать контент разных типов в ряд.

PdfDocumentBuilder.Create().Generate("containers-row.pdf", doc => doc.Pages(page =>
{
    var rowItems = new[] { "three", "two", "one" };

    page.Content().Row(row =>
    {
        for (int index = 0; index < rowItems.Length; index++)
        {
            row.AutoItem().Text(rowItems[index]);

            if (index != rowItems.Length - 1)
                row.AutoItem().PaddingHorizontal(10).LineVertical(0.5);
        }
    });
}));

Вы можете увидеть результат выполнения кода в containers-row.pdf.

Table

Используйте контейнеры Table для размещения самых сложных данных. Начните с определения хотя бы одного столбца, а затем заполните столбцы и строки, вызвав метод Cell несколько раз.

Таблицы могут иметь верхний и нижний колонтитулы. Ячейки в таблице могут охватывать более одного столбца и/или строки. Вот код, который добавляет простую таблицу.

PdfDocumentBuilder.Create().Generate("containers-table.pdf", doc => doc.Pages(page =>
{
    page.Content().Table(t =>
    {
        t.Columns(c =>
        {
            for (int i = 0; i < 4; ++i)
                c.ConstantColumn(50);
        });

        for (int i = 0; i < 16; i++)
        {
            t.Cell()
                .Border(b => b.Thickness(0.5))
                .PaddingHorizontal(10)
                .Text($"{i + 1}");
        }
    });
}));

Результат выполнения кода находится в containers-table.pdf.

Inlined

Контейнер Inlined позволяет удобно заполнить область элементами из коллекции контейнеров. Вы просто добавляете элементы один за другим, а библиотека ставит их в ряд один за другим. Когда места для размещения нового элемента нет, библиотека начинает новую строку.

Layers

Бывают случаи, когда лучше размещать контент на нескольких слоях. Контейнер Layers служит именно этой цели. Вы должны определить ровно один основной слой и любое количество неосновных. Layout API будет компоновать слои в том же порядке, в котором вы их создаете.

Element

Это особый вид контента. Вы можете создать элемент динамически и поместить результат в контейнер.

Динамически создаваемые элементы могут иметь макет, который зависит от номера страницы, размера и других свойств.