Skip to content

Плинний API DocumentBuilder

DocumentBuilder — це плинний (fluent) 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")?;

Пов’язані сторінки