该页面可以包含自动翻译的文本。

.NET PDF 生成器

借助 Docotic.Pdf,您可以利用页面、容器、文本跨区、图像、链接、页眉、页脚、表格、列表等结构元素生成 PDF 文档。这些元素可通过 Docotic.Pdf 的免费 Layout 插件提供的 Layout 高级 API 访问。该 API 还支持可重用的自定义组件。

Docotic.Pdf 如何生成 PDF 的示例:您排列图像、表格和文本等元素,库会根据该布局生成 PDF

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.dll
  • BitMiracle.Docotic.Pdf.Layout.dll(位于 Layout add-on 子文件夹中)。

获取许可证密钥

要试用该库,请填写 Docotic.Pdf 下载页面上的表格,申请一个免费的限时许可证密钥。如果您已经购买了许可证,请使用购买后收到的代码。

Layout 插件是免费的,无需额外许可证。您可以使用已有的 Docotic.Pdf 许可证来使用 Layout API。

Hello, world! 使用 Layout API

以下是使用 API 生成包含经典“Hello, world!”短语的 PDF 的示例代码:

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> 的委托。插件会生成 hello.pdf 作为 Generate 调用的结果。

为了确定 PDF 的布局,文档构建器会使用 Document 实例调用委托。委托的代码会生成文档内容。在本示例中,委托使用 Pages 方法向构建器提供另一个定义文档页面布局的委托。

构建器使用 PageLayout 实例调用传递给 Pages 方法的委托。此实例表示文档中的一个或多个页面。页面的具体数量取决于添加到其中的内容。

页面委托会调用 Content 方法来访问页面主要内容的布局容器。通过链式调用容器的 Text 方法,可以将示例文本 span 添加到页面中。有关布局容器工作原理的详细说明,请参阅布局容器指南。

文档构建器会自动将内容拆分到多个页面中,创建与添加到主要内容布局容器的所有数据所需的页面数量完全相同的页面。在本示例中,单页就足够了,因此输出结果恰好包含一个页面。

基本示例之外的常见任务

示例代码首先创建一个 PdfDocumentBuilder 实例,然后调用 Generate 方法生成 PDF 文件。您可以在生成器开始生成 PDF 之前对其进行配置。

例如,您可以通过向生成器提供加密处理程序来生成加密的 PDF 文件。您还可以指定生成器要包含在生成的文档中的元数据。有关如何自定义生成器的更多详细信息,请参阅单独的文章。

示例代码仅使用主内容槽的布局容器,但其他内容槽也可用。以下是用于访问内容槽的 PageLayout 方法的完整列表:

  • Background() - 返回背景层,该层会被其他内容覆盖。
  • Header() - 返回所有页面的公共页眉。
  • Content() - 返回主页面内容槽。
  • Footer() - 返回所有页面的公共页脚。
  • Foreground() - 返回前景层,该层会显示在其他内容之上。

只有主内容槽中的内容才会影响生成的 PDF 的页数。文档生成器会在每一页上重复使用除 Content() 提供的槽之外的所有槽。有关内容槽的更多信息,请参阅关于页面布局的文章。

许多文档会在不同的页面上使用不同的布局。例如,第一页可能采用封面式设计,而后续页面则使用更简洁的布局。有些文档包含用于表格的专用页面,或者根据不同的章节应用不同的背景。要使用 Docotic.Pdf 和 Layout 插件生成此类文档,请多次调用 Document.Pages 方法。您可以在我们的示例库中找到工作示例

代码整理

对于像示例中那样的短代码,链式调用和嵌套 lambda 表达式是可以接受的。但当构建更复杂的程序时,将代码拆分成多个方法会更方便。这样可以使代码更易于阅读和维护。

以下是将 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。

当 Docotic.Pdf 与免费的 Layout 插件一起使用时,即可使用此 API。Docotic.Pdf 和 Layout 插件均为 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 及更高版本。

您可以使用 Layout API 在 ASP.NET Core、MAUI 应用、Unity、Xamarin 和控制台应用程序中生成 PDF。Docotic.Pdf 配合 Layout 插件可以在 Windows、macOS 和 Linux 系统上生成 PDF。

云平台和 Docker 镜像

Docotic.Pdf 及其 Layout 插件可在 Azure 和 AWS 云环境(包括无服务器架构)中运行。该库和插件完全支持动态硬件变更、自动缩放和其他云原生运行时特性。

在大多数云场景中,需要使用 Unbound 许可证。许可证常见问题解答解释了如何选择适用于云应用程序的许可证

Layout API 可以直接在 Docker 容器中运行。在容器内运行库和 Layout 插件时,无需任何特殊配置即可生成 PDF 文件。

向 PDF 文件添加文本

文本是任何 PDF 文档的基本组成部分。您可以使用 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 类的 SpanLine 方法向当前行添加文本。Line 方法还会补全当前行。示例代码还使用 Hyperlink 方法将外部资源链接附加到特定的文本 span 元素。

请注意示例代码如何使用 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 文档中字体的详细信息,请参阅我们示例存储库中的示例代码。

布局 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 文档时使用预定义和自定义文本样式

许多实际应用中的 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 对象的 CurrentPageNumberPageCount 方法访问这些值。

Layout API 还提供了一种格式化页码的方法。例如,您可以像这样绘制十六进制页码:

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 容器将文本和图像垂直排列,彼此相邻。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 下载图像),因此声明为 async Task 而不是 void。调用者必须使用 await 来确保 PDF 生成正确完成。在您自己的代码中,类似的方法也可能返回一个值,在这种情况下,它应该声明为 async Task<TResult>

创建列表

什么是列表?您可以将其理解为一组按顺序排列的带编号的项目。布局 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 容器必须显式指定每个项目的大小,或者自动计算其大小。在本例中,使用了 AutoItemRelativeItem 方法。因此,行容器会计算第一个项目所需的宽度,然后将剩余的可用宽度用于第二个项目。

通过使用这种方法并根据需要调整行的外观,您可以创建最适合文档布局和样式的列表。

搭建桌子

许多 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()
    );
}

示例代码创建了一个简单的表格,显示当前年份和前三年各月的基本信息。代码定义了三列,每列的宽度各不相同。最左侧和最右侧的列的宽度是中间列的四倍。

代码还定义了表格标题,添加了标题单元格,并为每个单元格指定了文本和背景颜色。当表格无法完整显示在一页上时,标题会在表格所在的每一页上重复显示。您可以在示例代码生成的 PDF 文件中看到这种行为。

代码使用两个简单的循环来构建表格的行。外层循环遍历年份,内层循环按相反的顺序遍历月份。内层循环获取每个月份的信息,然后将三个单元格添加到表格中形成一行。

更多详情,您可以阅读详细介绍表格容器功能的文章。

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 方法实现的。

在本例中,链接及其目标均为文本 span 元素,但您可以在任何布局容器上创建章节和链接。它可以是包含图像的容器、表格容器,或者您自己创建的容器。

请参阅我们的示例库,了解如何创建 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 转 PDF 方法

  • 底层 PDF 生成
    提供库中对 PDF 结构和内容的最大控制权。当您需要像素级定位或复杂的矢量图形时,请选择此选项。此方法推荐用于对性能要求极高的场景或需要尽可能小的资源占用时。

  • 基于模板的 PDF 生成
    提供了一种快速、可预测的方式来填写文档,无需设计或排列文档元素。如果您已有预定义的 PDF 结构(例如已批准或符合规范的模板),并且只需要更改文本字段、替换占位符、附加相关文档以及执行类似任务,请选择此功能。

  • PDF合并和合成
    允许您从现有文件创建 PDF,而不是从头开始创建。当您需要将图像、扫描页面或其他 PDF 文件合并到一个文件中时,请选择此功能。

与其他 PDF 生成解决方案的比较

本节包含两个比较表:一个包含关键要点,另一个包含详细的结构化信息,说明带有 Layout 插件的 Docotic.Pdf 与其他流行的 PDF 生成解决方案的比较情况。

主要对比要点

生成 PDF 文件有很多不错的选择,其中也包括免费工具。但是,诸如签名、加密或合并文档等功能各不相同,这可能会限制哪些工具真正符合您的需求。

解决方案 何时使用 最适合
使用 Layout 插件的 Docotic.Pdf 当您需要一款高质量、高性能的布局引擎,能够生成优化的 PDF 文件,并提供跨平台的高级签名、加密和 PDF 编辑支持时,这款引擎是您的理想之选 高质量生成发票、报告、报表及类似文档,并提供卓越的开发体验。是您需要企业级 PDF 处理和专业支持时的理想之选
PDFsharp + MigraDoc 当您需要一个免费的、MIT 许可的 PDF 生成库,且不需要数字签名或现代加密算法时,可以使用此库 在开源或预算受限的项目中创建简单文档
QuestPDF 当您需要一个专用于生成 PDF 的现代化排版引擎,而不需要编辑、签名或加密功能时 提供高质量的 PDF 生成服务,采用 MIT 许可或低成本商业许可,前提是所有非生成功能均由其他方处理
iText 当您需要一款成熟、功能丰富的 PDF 工具包来生成和处理 PDF 文件,并且您准备好以 AGPL/GPLv3 许可证开源您的解决方案,或者购买昂贵的商业许可证时,那么这款产品或许适合您 已经熟悉 iText API 的团队,因此不会受到其陡峭学习曲线的影响

详细比较

请查看表格以了解更广泛的背景,并形成您自己的结论。

  Docotic.Pdf 与 Layout PDFsharp + MigraDoc QuestPDF iText
PDF功能 功能齐全的PDF库 PDF 生成和有限编辑 仅生成 PDF 强大的PDF功能
渲染模型 现代的、声明式的、保留模式的布局引擎 基于盒的布局引擎 现代的、声明式的、保留模式的布局引擎 基于盒的布局引擎 + 渲染器树
API 类型 Fluent API 命令式 API Fluent API 命令式 API
开发者体验 非常棒。API简洁、现代且直观 很好。API 设计符合传统规范 非常棒。API简洁、现代且直观 尚可。API 冗长且过于复杂
字体子集 支持;默认情况下仅嵌入使用的字形 不支持;可能会导致生成的PDF文件过大 支持;默认情况下仅嵌入使用的字形 支持;默认情况下仅嵌入使用的字形
从右到左(RTL)的内容方向 支持 不支持 支持 支持
数字签名 支持的,包括 LTV 签名和外部签名 不支持 不支持 支持包括 LTV 和外部签名
加密/权限 完全支持 仅支持RC4加密,不支持AES或证书 不支持 完全支持
外部依赖项 没有任何 没有任何 SkiaSharp / 基于 Skia 的组件 没有任何
支持 为潜在客户和现有客户提供专业支持;为持有顶级许可证的客户提供优先支持 社区支持;专业支持可单独购买 通过 GitHub 提供社区支持 AGPL 版本获得社区支持;商业许可持有者获得专业支持
执照 商业用途,符合条件的用例可获得免费许可 MIT MIT适用于个人和小公司;大型企业需要商业许可证 AGPL 适用于开源项目,而专有项目则使用昂贵的商业许可
开发者许可 拥有所有许可证的无限开发者 拥有所有许可证的无限开发者 MIT 许可下开发者人数不限;专业版许可下开发者人数为 10 人;企业版许可下开发者人数不限 AGPL 版本允许无限数量的开发者;商业许可则按开发者数量授权

结论

Docotic.Pdf 及其 Layout 插件提供了一种现代化、高性能、高质量的 C# 和 VB.NET PDF 生成方式。该库可生成报告、报表、发票及类似文档。其精心设计、流畅易用的 API 为开发者提供了卓越的体验。您可以信赖 Bit Miracle 为 Docotic.Pdf 及其插件提供的专业支持。

与其他一些 PDF 生成解决方案不同,Docotic.Pdf 是一个功能齐全的 PDF API。该库可以使用数字签名(包括 LTV 签名)对生成的 PDF 进行签名。Docotic.Pdf 能够使用存储在 USB 令牌和智能卡等安全硬件上的证书。此外,它还支持基于云的硬件安全模块 (HSM),例如 Microsoft Azure Key Vault 和 AWS Key Management Service (KMS)。

使用 Docotic.Pdf,您可以将电子表格或语音备注等辅助文档附加到生成的 PDF 中。要在网页或类似界面上显示文档,您可以从文档的一个或多个页面创建缩略图

后续步骤: