Создание из HTML
Доступно две точки входа:
Pdf::from_html(content)— базовый структурный HTML (заголовки, абзацы, списки, код, жирный/курсив). Без стилей. Во всех биндингах.Pdf::from_html_css(html, css, font_bytes)— полноценный pure-Rust конвейер HTML+CSS, появившийся в v0.3.37. Самописный CSS-движок (подмножество селекторов L3 + L4, каскад,calc()/var(),@page/@media print), раскладка block / flex / grid на базе Taffy, переносы UAX #14, RTL-шейпинг через rustybuzz,::before/::after,page-break-*,<a href>→ link-аннотация,<img>data-URI →/XObject, каскад из нескольких шрифтов. Ноль MPL-зависимостей. Во всех биндингах.
Быстрый пример
Python
from pdf_oxide import Pdf
pdf = Pdf.from_html("<h1>Hello</h1><p>World</p>")
pdf.save("out.pdf")
WASM
import { WasmPdf } from "pdf-oxide-wasm";
import { writeFileSync } from "fs";
const pdf = WasmPdf.fromHtml("<h1>Hello</h1><p>World</p>");
writeFileSync("out.pdf", pdf.toBytes());
Rust
use pdf_oxide::api::Pdf;
let pdf = Pdf::from_html("<h1>Hello</h1><p>World</p>")?;
pdf.save("out.pdf")?;
Go
package main
import (
"log"
pdfoxide "github.com/yfedoseev/pdf_oxide/go"
)
func main() {
pdf, err := pdfoxide.FromHtml("<h1>Hello</h1><p>World</p>")
if err != nil { log.Fatal(err) }
defer pdf.Close()
if err := pdf.Save("out.pdf"); err != nil { log.Fatal(err) }
}
C#
using PdfOxide;
using var pdf = Pdf.FromHtml("<h1>Hello</h1><p>World</p>");
pdf.Save("out.pdf");
Конвейер HTML + CSS (v0.3.37)
Pdf::from_html_css(html, css, font_bytes) принимает HTML, CSS-стили и байты TTF/OTF-шрифта. Возвращает постраничный PDF. extract_text round-trip’ит байт в байт — сгенерированные PDF участвуют в существующей тестовой инфраструктуре.
Rust:
use pdf_oxide::api::Pdf;
let font = std::fs::read("DejaVuSans.ttf")?;
let pdf = Pdf::from_html_css(
"<h1>Hello</h1><p>World</p>",
"h1 { color: blue; font-size: 24pt } p { line-height: 1.5 }",
font,
)?;
pdf.save("out.pdf")?;
Python:
from pdf_oxide import Pdf
with open("DejaVuSans.ttf", "rb") as f:
font = f.read()
pdf = Pdf.from_html_css(
"<h1>Hello</h1><p>World</p>",
"h1 { color: blue; font-size: 24pt }",
font,
)
pdf.save("out.pdf")
Node / TypeScript:
import { Pdf } from "pdf-oxide";
import { readFileSync } from "fs";
const font = readFileSync("DejaVuSans.ttf");
const pdf = Pdf.fromHtmlCss(
"<h1>Hello</h1><p>World</p>",
"h1 { color: blue; font-size: 24pt }",
font,
);
pdf.save("out.pdf");
Go:
font, _ := os.ReadFile("DejaVuSans.ttf")
pdf, err := pdfoxide.FromHtmlCss(
"<h1>Hello</h1><p>World</p>",
"h1 { color: blue; font-size: 24pt }",
font,
)
if err != nil { log.Fatal(err) }
defer pdf.Close()
_ = pdf.Save("out.pdf")
C#:
var font = File.ReadAllBytes("DejaVuSans.ttf");
using var pdf = Pdf.FromHtmlCss(
"<h1>Hello</h1><p>World</p>",
"h1 { color: blue; font-size: 24pt }",
font);
pdf.Save("out.pdf");
Каскад из нескольких шрифтов
Если документ смешивает несколько гарнитур, используйте Pdf::from_html_css_with_fonts(html, css, fonts). CSS font-family на любом элементе резолвится по зарегистрированным семействам (без учёта регистра, с кавычками и без, многословные имена без кавычек). Неизвестные семейства откатываются на первый зарегистрированный шрифт.
from pdf_oxide import Pdf
fonts = [
("DejaVu Sans", open("DejaVuSans.ttf", "rb").read()),
("Noto Sans CJK", open("NotoSansCJKtc-Regular.otf", "rb").read()),
]
pdf = Pdf.from_html_css_with_fonts(
'<h1 style="font-family: DejaVu Sans">English</h1>'
'<p style="font-family: \'Noto Sans CJK\'">中文段落</p>',
"h1 { font-size: 24pt }",
fonts,
)
pdf.save("multilang.pdf")
CJK-содержимое автоматически субсетится на выходе (v0.3.38 #385) — PDF с 5 символами из CJK-шрифта размером ~17 МБ обычно помещается в 100 КБ.
Поддерживаемое подмножество CSS
- Селекторы — подмножество L3 + L4:
:is/:where/:not/:has, структурные псевдоклассы, матчинг атрибутов с флагамиi/s. - Каскад — сортировка по origin / specificity / порядку, наследование, мерж inline-стилей, пользовательские свойства (
var()с детекцией циклов). - Функции —
calc(),min(),max(),clamp(). - At-правила —
@media print(всегда true),(min/max-width),@page :first / :left / :right / :blankс margin-боксами,@font-face,@import,@supports. - Типизированные значения — цвета (~150 именованных, hex, rgb/rgba, hsl), длины (все единицы CSS Values L4),
display,font-size/weight/style/family, шорткатыmargin/padding,line-height. - Счётчики —
counter/counters,counter-reset/-increment/-set, нумерация римскими / греческими / алфавитом. - Псевдоэлементы —
::before/::afterс литеральными строками,attr(name),open-quote/close-quote. - Раскладка — block, flex, grid (всё через Taffy), схлопывание margin, многоколоночность (
column-count/column-width/column-gap), таблицы (алгоритмы auto и fixed). - Inline — переносы UAX #14,
text-align, режимыwhite-space, жёсткие переносы, атомарные inline-боксы. - Эффекты —
opacity,transform: translate*(),page-break-before: always,page-break-after: always. - HTML — токенизатор HTML5, извлечение
<style>/<link rel="stylesheet">/ inlinestyle="", декод<img>data-URI (/XObject),<a href>→ аннотация/Linkс/URI, маркеры списков<ul>/<ol>.
Вне области покрытия
CSS-фильтры, 3D-трансформы, анимации, SVG-в-HTML (все пригодные Rust-крейты для SVG — под MPL), MathML, hyphens: auto, shape-outside, выполнение JavaScript, полноматричный transform (scale / rotate), градиенты, box-shadow.
Лицензия
cargo deny check licenses проходит без ни одной транзитивной зависимости под MPL. Mozilla-стек для CSS (cssparser, selectors, html5ever, lightningcss, stylo) целиком под MPL-2.0; в v0.3.37 эти части переписаны вручную, чтобы pdf_oxide оставался полностью под MIT/Apache.
Поддерживаемые HTML-элементы
| Element | Description |
|---|---|
<h1> through <h6> |
Заголовки (сопоставлены размерам заголовков PDF) |
<p> |
Абзацы с автоматическими отступами |
<b>, <strong> |
Жирный текст |
<i>, <em> |
Курсивный текст |
<ul>, <ol>, <li> |
Маркированные и нумерованные списки |
<pre>, <code> |
Форматированный и встроенный код |
<blockquote> |
Блочные цитаты |
<br> |
Переносы строк |
<hr> |
Горизонтальные линии |
Полный справочник API
Pdf::from_html(content) (Static Method)
Создаёт PDF из HTML-содержимого с настройками по умолчанию (страница Letter, поля 72pt, шрифт Helvetica 12pt).
Rust:
use pdf_oxide::api::Pdf;
let html = r#"
<h1>Product Specification</h1>
<p>This document describes the <strong>technical requirements</strong>
for the new product line.</p>
<h2>Requirements</h2>
<ul>
<li>Operating temperature: -20C to 60C</li>
<li>Power consumption: <5W</li>
<li>Weight: <200g</li>
</ul>
"#;
let pdf = Pdf::from_html(html)?;
pdf.save("spec.pdf")?;
JavaScript:
import { WasmPdf } from "pdf-oxide-wasm";
import { writeFileSync } from "fs";
const html = `
<h1>Product Specification</h1>
<p>This document describes the <strong>technical requirements</strong>
for the new product line.</p>
`;
const pdf = WasmPdf.fromHtml(html);
writeFileSync("spec.pdf", pdf.toBytes());
Python:
from pdf_oxide import Pdf
html = """
<h1>Product Specification</h1>
<p>This document describes the <strong>technical requirements</strong>
for the new product line.</p>
"""
pdf = Pdf.from_html(html)
pdf.save("spec.pdf")
Python Signature:
Pdf.from_html(
content: str,
title: str | None = None,
author: str | None = None
) -> Pdf
PdfBuilder::new().from_html(content) (Builder Pattern)
Используйте PdfBuilder для управления размером страницы, полями, размером шрифта и метаданными документа.
Rust:
use pdf_oxide::api::PdfBuilder;
use pdf_oxide::writer::PageSize;
let pdf = PdfBuilder::new()
.title("Technical Specification")
.author("Engineering")
.page_size(PageSize::A4)
.margin(54.0)
.font_size(11.0)
.from_html("<h1>Spec</h1><p>Version 2.0</p>")?;
pdf.save("spec_a4.pdf")?;
Продвинутые примеры
Структурированный отчёт
use pdf_oxide::api::Pdf;
let html = r#"
<h1>Incident Report</h1>
<h2>Summary</h2>
<p>On <em>2025-11-15</em>, a service disruption was detected in the
<strong>payment processing</strong> pipeline.</p>
<h2>Timeline</h2>
<ol>
<li>14:32 UTC - Alert triggered for elevated error rates</li>
<li>14:35 UTC - On-call engineer acknowledged</li>
<li>14:48 UTC - Root cause identified: database connection pool exhaustion</li>
<li>15:02 UTC - Fix deployed, services recovering</li>
<li>15:15 UTC - Full recovery confirmed</li>
</ol>
<h2>Root Cause</h2>
<p>A configuration change deployed at 14:00 UTC reduced the maximum
connection pool size from 100 to 10.</p>
<h2>Code Reference</h2>
<pre><code>max_connections: 10 # Should be 100
timeout_seconds: 30
</code></pre>
<h2>Action Items</h2>
<ul>
<li>Add validation for connection pool configuration</li>
<li>Implement canary deployment for config changes</li>
<li>Add alerting for connection pool utilization</li>
</ul>
"#;
let pdf = Pdf::from_html(html)?;
pdf.save("incident_report.pdf")?;
Python с динамическим HTML
from pdf_oxide import Pdf
rows = [
("Widget A", "$12.99", 150),
("Widget B", "$24.50", 89),
("Widget C", "$7.25", 312),
]
html = "<h1>Inventory Report</h1>"
html += "<p>Generated on 2025-11-20</p>"
html += "<h2>Current Stock</h2><ul>"
for name, price, qty in rows:
html += f"<li><strong>{name}</strong> - {price} ({qty} units)</li>"
html += "</ul>"
pdf = Pdf.from_html(html, title="Inventory Report")
pdf.save("inventory.pdf")
Чтение HTML из файла
from pdf_oxide import Pdf
with open("report.html") as f:
html = f.read()
pdf = Pdf.from_html(html, title="Report")
pdf.save("report.pdf")
import { WasmPdf } from "pdf-oxide-wasm";
import { readFileSync, writeFileSync } from "fs";
const html = readFileSync("report.html", "utf-8");
const pdf = WasmPdf.fromHtml(html);
writeFileSync("report.pdf", pdf.toBytes());
use pdf_oxide::api::Pdf;
let html = std::fs::read_to_string("report.html")?;
let pdf = Pdf::from_html(&html)?;
pdf.save("report.pdf")?;
Связанные страницы
- Создание из Markdown — конвертация Markdown в PDF
- Fluent API PdfBuilder — полные параметры конфигурации
- Низкоуровневый API DocumentBuilder — программное конструирование страниц