Skip to content

DocumentBuilder 플루언트 API

DocumentBuilder는 텍스트 배치, 폰트, 주석, 양식 필드, 콘텐츠 요소를 완전히 제어하면서 PDF 문서를 페이지 단위로 구성하는 플루언트 API입니다.

바인딩 지원 현황(v0.3.38). DocumentBuilder + FluentPageBuilder + EmbeddedFontRust, 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")?;

관련 페이지