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 控件类型、图形基本图元(rect、filled_rect、line)、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")?;

相关页面