Skip to content

DocumentBuilder 流式 API

DocumentBuilder 是一套流式 API,用于逐页构建 PDF 文档,可全面控制文本布局、字体、注释、表单字段和内容元素。

绑定覆盖情况(v0.3.38)。 DocumentBuilder + FluentPageBuilder + EmbeddedFont 已在 Rust、Python、Node/TypeScript、C#、Go 和 WASM 中提供。所有绑定都暴露相同的能力:多页构建、通过嵌入字体支持 CJK/西里尔/希腊文本、15 种注释方法、5 种 AcroForm 控件类型、图形基本图元(rectfilled_rectline)、AES-256 加密以及 HTML+CSS 流水线。

快速示例

Rust

use pdf_oxide::writer::{DocumentBuilder, PageSize, DocumentMetadata};

let mut builder = DocumentBuilder::new()
    .metadata(DocumentMetadata::new().title("My Document"));

builder
    .page(PageSize::Letter)
        .at(72.0, 720.0)
        .heading(1, "Hello, World!")
        .paragraph("This is a PDF document created with DocumentBuilder.")
        .done();

let bytes = builder.build()?;
std::fs::write("output.pdf", bytes)?;

Python

from pdf_oxide import DocumentBuilder, EmbeddedFont

font = EmbeddedFont.from_file("DejaVuSans.ttf")
pdf = (DocumentBuilder()
    .register_embedded_font("DejaVu", font)
    .a4_page()
        .font("DejaVu", 12).at(72, 720).text("Hello, World!")
        .highlight((1.0, 1.0, 0.0))
    .done()
    .build())
open("output.pdf", "wb").write(pdf)

Node / TypeScript

import { DocumentBuilder, EmbeddedFont } from "pdf-oxide";

const font = await EmbeddedFont.fromFile("DejaVuSans.ttf");
const bytes = new DocumentBuilder()
  .registerEmbeddedFont("DejaVu", font)
  .a4Page()
    .font("DejaVu", 12).at(72, 720).text("Hello, World!")
    .highlight([1.0, 1.0, 0.0])
  .done()
  .build();

C#

using PdfOxide;

using var font = EmbeddedFont.FromFile("DejaVuSans.ttf");
var bytes = DocumentBuilder.Create()
    .RegisterEmbeddedFont("DejaVu", font)
    .A4Page()
        .Font("DejaVu", 12).At(72, 720).Text("Hello, World!")
        .Highlight(1.0, 1.0, 0.0)
    .Done()
    .Build();
File.WriteAllBytes("output.pdf", bytes);

Go(CGo 方式;需要 CGO_ENABLED=1

import pdfoxide "github.com/yfedoseev/pdf_oxide/go"

font, _ := pdfoxide.EmbeddedFontFromFile("DejaVuSans.ttf")
defer font.Close()

builder := pdfoxide.NewDocumentBuilder()
builder.RegisterEmbeddedFont("DejaVu", font)
builder.A4Page().
    Font("DejaVu", 12).At(72, 720).Text("Hello, World!").
    Highlight(1.0, 1.0, 0.0).
    Done()
bytes, _ := builder.Build()

WASM(浏览器/Node/打包器 — API 相同)

import init, { DocumentBuilder, EmbeddedFont } from "pdf-oxide-wasm/web";
await init();

const font = await fetch("/DejaVuSans.ttf").then(r => r.arrayBuffer());
const bytes = new DocumentBuilder()
  .registerEmbeddedFont("DejaVu", EmbeddedFont.fromBytes(new Uint8Array(font), "DejaVu"))
  .a4Page()
    .font("DejaVu", 12).at(72, 720).text("Hello, World!")
  .done()
  .build();

C++

#include <pdf_oxide/pdf_oxide.hpp>

auto font = pdf_oxide::EmbeddedFont::from_file("DejaVuSans.ttf");
auto builder = pdf_oxide::DocumentBuilder::create();
builder.register_embedded_font("DejaVu", font);
builder.a4_page()
    .font("DejaVu", 12).at(72, 720).text("Hello, World!")
    .highlight(1.0, 1.0, 0.0)
    .done();
std::vector<std::uint8_t> bytes = builder.build();

Swift

import PdfOxide

let font = try EmbeddedFont.fromFile("DejaVuSans.ttf")
let builder = try DocumentBuilder.create()
try builder.registerEmbeddedFont("DejaVu", font)
let page = try builder.a4Page()
try page.font("DejaVu", 12).at(72, 720).text("Hello, World!")
    .highlight(1.0, 1.0, 0.0)
    .done()
let bytes = try builder.build()

Dart

import 'package:pdf_oxide/pdf_oxide.dart';

final font = EmbeddedFont.fromFile('DejaVuSans.ttf');
final builder = DocumentBuilder.create();
builder.registerEmbeddedFont('DejaVu', font);
builder.a4Page()
    .font('DejaVu', 12.0).at(72.0, 720.0).text('Hello, World!')
    .highlight(1.0, 1.0, 0.0)
    .done();
final bytes = builder.build();

R

library(pdfoxide)

font <- pdf_embedded_font_from_file("DejaVuSans.ttf")
b    <- pdf_builder_create()
pdf_builder_register_embedded_font(b, "DejaVu", font)
pg <- pdf_builder_a4_page(b)
pdf_page_font(pg, "DejaVu", 12)
pdf_page_at(pg, 72, 720)
pdf_page_builder_text(pg, "Hello, World!")
pdf_page_highlight(pg, 1.0, 1.0, 0.0)
pdf_page_done(pg)
bytes <- pdf_builder_build(b)

Julia

using PdfOxide

emb = embedded_font_from_file("DejaVuSans.ttf")
b   = DocumentBuilder()
register_embedded_font(b, "DejaVu", emb)
pg = a4_page(b)
font(pg, "DejaVu", 12)
at(pg, 72, 720)
text(pg, "Hello, World!")
highlight(pg, 1.0, 1.0, 0.0)
done(pg)
bytes = build(b)

Zig

const pdf_oxide = @import("pdf_oxide");
const a = std.heap.page_allocator;

var font = try pdf_oxide.EmbeddedFont.fromFile("DejaVuSans.ttf");
var builder = try pdf_oxide.DocumentBuilder.create();
try builder.registerEmbeddedFont("DejaVu", &font);
var page = try builder.a4Page();
try page.font("DejaVu", 12);
try page.at(72, 720);
try page.text("Hello, World!");
try page.highlight(1.0, 1.0, 0.0);
try page.done();
const bytes = try builder.build(a);

Objective-C

#import "POXPdfOxide.h"
NSError *err = nil;

POXEmbeddedFont *font = [POXEmbeddedFont fromPath:@"DejaVuSans.ttf" error:&err];
POXDocumentBuilder *builder = [POXDocumentBuilder createWithError:&err];
[builder registerEmbeddedFont:@"DejaVu" font:font error:&err];
POXPageBuilder *page = [builder a4PageWithError:&err];
[page font:@"DejaVu" size:12 error:&err];
[page at:72 y:720 error:&err];
[page text:@"Hello, World!" error:&err];
[page highlightR:1.0 g:1.0 b:0.0 error:&err];
[page done:&err];
NSData *bytes = [builder buildWithError:&err];

Elixir

{:ok, font} = PdfOxide.font_from_file("DejaVuSans.ttf")
{:ok, db}   = PdfOxide.builder()
:ok = PdfOxide.builder_register_embedded_font(db, "DejaVu", font)
{:ok, page} = PdfOxide.builder_a4_page(db)
:ok = PdfOxide.page_font(page, "DejaVu", 12)
:ok = PdfOxide.page_at(page, 72, 720)
:ok = PdfOxide.page_text(page, "Hello, World!")
:ok = PdfOxide.page_highlight(page, 1.0, 1.0, 0.0)
:ok = PdfOxide.page_done(page)
{:ok, bytes} = PdfOxide.builder_build(db)

完整 API 参考

DocumentBuilder

DocumentBuilder::new() – 创建构建器

let mut builder = DocumentBuilder::new();

.metadata(metadata) – 设置文档元数据

use pdf_oxide::writer::DocumentMetadata;

let mut builder = DocumentBuilder::new()
    .metadata(
        DocumentMetadata::new()
            .title("Report")
            .author("Jane Smith")
            .subject("Q4 Analysis")
            .keywords("finance, quarterly")
            .creator("MyApp")
    );

.page(size) – 添加页面

返回一个 FluentPageBuilder,用于向页面添加内容。完成后调用 .done()

use pdf_oxide::writer::PageSize;

builder.page(PageSize::A4)
    .at(72.0, 770.0)
    .text("Hello")
    .done();

.letter_page() / .a4_page() – 便捷页面方法

builder.letter_page().text("US Letter page").done();
builder.a4_page().text("A4 page").done();

.build() – 生成 PDF 字节

let bytes: Vec<u8> = builder.build()?;

.save(path) – 构建并保存到文件

builder.save("output.pdf")?;

.save_encrypted(path, user_pw, owner_pw) – AES-256 加密

在 v0.3.38 中加入。所有绑定均可用。

DocumentBuilder::new()
    .a4_page().text("secret").done()
    .save_encrypted("out.pdf", "user-pw", "owner-pw")?;
(DocumentBuilder()
    .a4_page().text("secret").done()
    .save_encrypted("out.pdf", "user-pw", "owner-pw"))
DocumentBuilder.Create()
    .A4Page().Text("secret").Done()
    .SaveEncrypted("out.pdf", "user-pw", "owner-pw");

此外还提供:.to_bytes_encrypted(user_pw, owner_pw) 用于内存中输出;.save_with_encryption(path, algorithm, permissions, user_pw, owner_pw)(Rust)用于自定义算法和按权限设置标志。

DocumentMetadata

文档级元数据的构建器。

方法 说明
.title(s) 设置文档标题
.author(s) 设置文档作者
.subject(s) 设置文档主题
.keywords(s) 设置文档关键词
.creator(s) 设置创建者应用程序

FluentPageBuilder

builder.page(size) 返回。所有方法都返回 self 以便链式调用(.done() 除外)。

文本与定位

方法 说明
.at(x, y) 设置光标位置(从左下角起算的点数)
.text(s) 在当前光标位置添加文本
.heading(level, s) 添加标题(1–6 级,使用相应字体)
.paragraph(s) 添加段落,自动换行
.font(name, size) 为后续文本设置字体
.text_config(config) 设置完整的文本配置
.space(points) 添加垂直间距
.horizontal_rule() 添加水平分隔线
.element(elem) 添加原始 ContentElement
.elements(vec) 添加多个原始内容元素

注释

方法 说明
.link_url(url) 将最后一个文本元素链接到 URL
.link_page(page_index) 将最后一段文本链接到内部页面
.link_named(destination) 链接到命名目标
.highlight(color) 高亮最后一段文本(RGB 元组)
.underline(color) 为最后一段文本添加下划线
.strikeout(color) 为最后一段文本添加删除线
.squiggly(color) 为最后一段文本添加波浪下划线
.sticky_note(text) 在光标位置添加便签
.sticky_note_with_icon(text, icon) 使用指定图标添加便签
.sticky_note_at(x, y, text) 在指定位置添加便签
.stamp(stamp_type) 在光标位置添加印章
.stamp_at(rect, stamp_type) 在指定矩形内添加印章
.freetext(rect, text) 添加自由文本注释
.freetext_styled(rect, text, font, size) 添加带样式的自由文本注释
.watermark(text) 在整页添加对角水印
.watermark_confidential() 添加预设的 “CONFIDENTIAL” 水印
.watermark_draft() 添加预设的 “DRAFT” 水印
.watermark_custom(watermark) 添加自定义水印注释
.add_annotation(annotation) 添加任意类型的注释

AcroForm 控件

在 v0.3.38 中加入所有绑定。所有位置均以页面左下角原点起算的 PDF 点为单位。

方法 说明
.text_field(name, x, y, w, h, default_value=None) 单行文本输入
.checkbox(name, x, y, w, h, checked) 复选框控件
.combo_box(name, x, y, w, h, options, selected=None) 下拉选择器
.radio_group(name, buttons, selected=None) 单选组;buttons(export_value, x, y, w, h) 的列表
.push_button(name, x, y, w, h, caption) 带标签的可点击按钮
(DocumentBuilder()
    .a4_page()
        .text_field("name", 150, 680, 200, 20, "Jane Doe")
        .checkbox("subscribe", 72, 650, 15, 15, True)
        .combo_box("country", 150, 620, 200, 20, ["US", "UK", "DE"], "US")
        .radio_group("tier", [("free", 72, 590, 15, 15), ("pro", 120, 590, 15, 15)], "pro")
        .push_button("submit", 72, 540, 80, 25, "Submit")
    .done()
    .save("form.pdf"))

图形基本图元

在 v0.3.38 中加入所有绑定:rect(x, y, w, h)(仅描边)、filled_rect(x, y, w, h, color)(用 RGB 元组填充)以及 line(x1, y1, x2, y2)。它们都经由同一条 FluentPageBuilder 链,足以满足表单背景、分隔线和简单的表格边框需求。

如需完整的路径/图案/渐变/ExtGState 控制,请使用 ContentStreamBuilder(仅 Rust — 参见图形、图案与底纹)。

.done() – 完成页面

将控制权交还给 DocumentBuilder

builder.page(PageSize::Letter)
    .at(72.0, 720.0)
    .text("Content")
    .done();  // Back to builder

TextConfig

文本渲染的配置。

use pdf_oxide::writer::TextConfig;

let config = TextConfig {
    font: "Times-Roman".to_string(),
    size: 14.0,
    align: TextAlign::Center,
    line_height: 1.5,
};
字段 类型 默认值
font String "Helvetica"
size f32 12.0
align TextAlign Left
line_height f32 1.2

PageSize

变体 宽 x 高(点)
Letter 612 x 792
A4 595 x 842
Legal 612 x 1008
A3 842 x 1190
Custom(w, h) 自定义尺寸

进阶示例

带注释的多页文档

use pdf_oxide::writer::{
    DocumentBuilder, DocumentMetadata, PageSize, StampType
};

let mut builder = DocumentBuilder::new()
    .metadata(
        DocumentMetadata::new()
            .title("Annotated Report")
            .author("Review Team")
    );

// Cover page
builder.page(PageSize::Letter)
    .at(72.0, 600.0)
    .font("Helvetica-Bold", 28.0)
    .text("Annual Review 2025")
    .font("Helvetica", 14.0)
    .space(20.0)
    .text("Prepared by the Review Team")
    .watermark_draft()
    .done();

// Content page with annotations
builder.page(PageSize::Letter)
    .at(72.0, 720.0)
    .heading(1, "Executive Summary")
    .paragraph(
        "Revenue increased 18% year-over-year, driven by expansion \
         into new markets and strong retention rates."
    )
    .text("See full financial details")
    .link_page(2)  // Link to page 3 (0-indexed)
    .space(12.0)
    .heading(2, "Key Findings")
    .text("Customer satisfaction reached an all-time high.")
    .highlight((1.0, 1.0, 0.0))  // Yellow highlight
    .sticky_note("Verify this claim with latest survey data")
    .paragraph(
        "Operating costs were reduced through automation initiatives, \
         achieving a 15% improvement in operational efficiency."
    )
    .stamp(StampType::ForComment)
    .done();

// Data page
builder.page(PageSize::Letter)
    .at(72.0, 720.0)
    .heading(1, "Financial Details")
    .paragraph("Detailed breakdown of revenue by segment...")
    .horizontal_rule()
    .paragraph("North America: $82M (+12%)")
    .paragraph("Europe: $41M (+28%)")
    .paragraph("Asia-Pacific: $19M (+35%)")
    .done();

builder.save("annotated_report.pdf")?;

精确文本定位

use pdf_oxide::writer::{DocumentBuilder, PageSize};

let mut builder = DocumentBuilder::new();

builder.page(PageSize::Letter)
    // Title at top center area
    .at(200.0, 740.0)
    .font("Helvetica-Bold", 20.0)
    .text("Certificate of Completion")

    // Recipient name
    .at(200.0, 620.0)
    .font("Times-Roman", 16.0)
    .text("Awarded to: Jane Smith")

    // Details at specific positions
    .at(72.0, 500.0)
    .font("Helvetica", 12.0)
    .text("For successfully completing the Advanced Rust Programming course.")

    .at(72.0, 450.0)
    .text("Date: November 15, 2025")

    .at(350.0, 450.0)
    .text("Instructor: Dr. Alan Turing")

    .horizontal_rule()

    .at(72.0, 380.0)
    .font("Helvetica", 9.0)
    .text("Certificate ID: CERT-2025-00042")

    .done();

builder.save("certificate.pdf")?;

相关页面