主题
PDF ↔ OFD 双向转换
两个方向均为 async 自由函数(首次调用自动懒加载转换模块):
js
import { convertPdfToOfd, convertPdfDetailed, convertOfdToPdf, pdfPageCount } from "rust-ofd";
// PDF → OFD:只要字节
const ofdBytes = await convertPdfToOfd(pdfBytes, "auto");
// PDF → OFD:要报告
const { ofd, report } = await convertPdfDetailed(pdfBytes, "embed", "1-3,5", "password?");
// OFD → PDF:矢量 + 真实可检索文本
const pdfBytes = await convertOfdToPdf(ofdBytes, "real");
// 转换前探测 PDF 页数
const pages = await pdfPageCount(pdfBytes);参数
| 参数 | 类型 | 说明 |
|---|---|---|
pdf / ofd | Uint8Array | 源文件字节 |
textMode | PDF→OFD:"auto" | "embed" | "outline";OFD→PDF:"real" | "outline" | 文本策略(下表) |
pages | string?("1-3,5") | 页码范围;省略转全部 |
password | string?(仅 PDF→OFD) | 加密 PDF 口令 |
PDF → OFD 文本双模式
| 模式 | 行为 | 适用 |
|---|---|---|
auto | 先尝试嵌入字体子集(Tier 1),无法保真时退化为文字轮廓(Tier 2) | 默认推荐 |
embed | 只做字体嵌入;字体无法解析时报警告 | 需要可检索文本 |
outline | 文字一律转矢量轮廓 | 目标环境无字体渲染能力 |
GB/T 42133-2022(档案指南)要求字体保真——auto 模式在国标原文 PDF(138 个裸 CFF 字体)上达成零退化嵌入。旋转/非均匀缩放文本走轮廓退化时会并行输出不可见 TextCode,保检索。
OFD → PDF
textMode: "real"(默认)输出真实可检索文本(内嵌字体按原字节透传,非嵌入字体按回退字体输出);"outline" 输出矢量轮廓。报告含嵌入/回退字体数、大纲与附件迁移统计:
ts
interface OfdToPdfReport {
pages: number; // 转换页数
fonts_embedded: number; // 原字节透传的嵌入字体数
fonts_fallback: number; // 走回退字体的字体数
images: number; // 转换图像数
outline_items: number; // 迁移的书签数
attachments: number; // 迁移的附件数
warnings: string[];
}ConvertReport(PDF → OFD)
ts
interface ConvertReport {
pages: number; // 转换页数
fonts_embedded: number; // 嵌入字体数(Tier 1)
fonts_outlined: number; // 退化为轮廓的字体数(Tier 2)
images: number; // 转换图像数
warnings: { kind: string; page?: number; message: string }[];
}warnings 记录每一处降级(如 JPX 图像占位、字体无法嵌入),上线前务必展示给用户,不要静默吞掉。
转换质量评测(0.6.0)
内核以 1018 份公开 PDF 语料(corpus/,覆盖中文正文/嵌入子集字体/扫描件/表单/注释/加密/JPX 图像等矩阵)做自动化评测(scripts/pdf2ofd-eval.py,指标为转换成功率 / SSIM 视觉还原 / 文本层保留),全量口径转换成功率 98.1%(19 份加密/损坏语料为预期失败)、panic 0——达标线见 docs/business/pdf2ofd-商业化达标线.md。另以 scripts/pdf2ofd-page-verify.py 做单文件全页逐页严格对拍(1018 份/2036 页,2026-10-08 口径:bad 476 份、panic 0),两套口径互补定位"整页分数不敏感但逐页可辨"的渲染不一致。
回退字体
无嵌入字体的 PDF(扫描件、小众字体)转换后需要回退字体才能显示文字:
js
// init 完成后注入;用 TTF(CFF/OTF 会使 OFD→PDF 真实文本退化为轮廓)
setFallbackFont(new Uint8Array(await (await fetch("/fallback-font.ttf")).arrayBuffer()));渲染与转换共用同一份注入字体。
实测数据
| 样本 | 页数 | 耗时 | 产物 | 字体 |
|---|---|---|---|---|
| GB/T 42133-2022 国标原文 PDF | 14 | 0.47s | 1533.9 KB | 138 嵌入 / 0 退化 |
| w3.org 示例 PDF | — | <0.3s | — | 保真嵌入 |
(单机实测值,尚未做系统基准测试;浏览器 WASM 端耗时约为原生的 1.5–3 倍。)