让 CJK 和阿拉伯语 PDF 的复制粘贴结果正确
制作 PDF 文件,让其中的中文、日文、韩文(CJK)和阿拉伯语文本在复制粘贴时保留原始逻辑字符。引擎会通过 /ToUnicode CMap 把每个字形码映射到 Unicode,再按规范化形式兼容组合(NFKC)规范化结果,并把经过塑形或带字母间距的文本运行包裹在携带 /ActualText 的 /Span 中。注册字体并写入内容后,提取结果就会保持正确。请用 pdftotext/Poppler 验证提取,而非 PyMuPDF;veraPDF 验证的是 PDF/通用无障碍 2(PDF/UA-2)符合性,而不是文本提取结果。
composer require nextpdf/core注册一款 CJK 字体(例如 Noto Sans CJK),以及一款支持阿拉伯语、且字符映射表覆盖 Arabic Presentation Forms-B 区块的字体(例如 Noto Naskh Arabic)。只嵌入你拥有嵌入授权的字体。
概念总览
标题为“概念总览”的章节内容流中的字形码并不等同于 Unicode。/ToUnicode CMap 会把每个码映射回 Unicode,以便阅读器提取文本(ISO 32000-2 §9.10)。引擎会按规范化形式兼容组合(NFKC,由 Unicode UAX #15 定义)对这些值进行规范化。CJK 兼容表意文字和阿拉伯语呈现形式都会映射为各自的基础字符,因此搜索和复制得到的是规范文本,而不是兼容码位。
有两种情况仅靠 /ToUnicode 还不够:带字母间距的拉丁文,以及经过塑形的从右到左阿拉伯语。引擎会把它们绘制成带间距或经过重排序的字形,因此仅凭字形顺序无法还原逻辑字符串。引擎会把每个文本运行包裹在携带 /ActualText 的 /Span 标记内容序列中,/ActualText 是所包裹内容的精确替代(ISO 32000-2 §14.9)。遵循 /ActualText 的提取器会返回逻辑字符串。
API 一览
标题为“API 一览”的章节| 符号 | 位置 | 作用 |
|---|---|---|
FontRegistry::register(string $fontFile, string $alias = ''): FontInfo | NextPDF\Typography\FontRegistry | 注册 CJK 和阿拉伯语字体。 |
DocumentFactory::create(): Document | NextPDF\Core\DocumentFactory | 构建会使用你的注册表的文档。 |
Document::writeHtml(string $html): static | NextPDF\Core\Concerns\HasTextOutput | 渲染多语言内容。 |
代码示例 — 快速上手
标题为“代码示例 — 快速上手”的章节<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;use NextPDF\Typography\FontRegistry;
$fonts = new FontRegistry();$fonts->register(__DIR__ . '/NotoSansCJK-Regular.ttf', alias: 'CJK');$fonts->register(__DIR__ . '/NotoNaskhArabic-Regular.ttf', alias: 'Arabic');
$doc = (new DocumentFactory($fonts, new ImageRegistry(maxCacheBytes: 0)))->create();$doc->addPage();$doc->writeHtml( '<p style="font-family: \'CJK\';">PDF 2.0 引擎 — 量子</p>' . '<p style="direction: rtl; font-family: \'Arabic\';">فاتورة</p>');$doc->save(__DIR__ . '/multilingual.pdf');pdftotext multilingual.pdf - | head# Extracts the logical text: "PDF 2.0 引擎 — 量子" and the logical Arabic "فاتورة",# not compatibility code points or reversed presentation forms.代码示例 — 生产环境
标题为“代码示例 — 生产环境”的章节这个自包含示例会为文档添加标签,加入一个带字母间距的标题,并写入测试载体路径。
<?php
declare(strict_types=1);
require_once __DIR__ . '/vendor/autoload.php';
use NextPDF\Core\DocumentFactory;use NextPDF\Graphics\ImageRegistry;use NextPDF\Typography\FontRegistry;
$fonts = new FontRegistry();$fonts->register(__DIR__ . '/NotoSansCJK-Regular.ttf', alias: 'CJK');$fonts->register(__DIR__ . '/NotoNaskhArabic-Regular.ttf', alias: 'Arabic');
$doc = (new DocumentFactory($fonts, new ImageRegistry(maxCacheBytes: 0)))->create();$doc->setTitle('Multilingual extraction');$doc->enableTaggedPdf('en');$doc->addPage();
$html = <<<'HTML'<h1 style="font-family: 'CJK'; letter-spacing: 3px;">CODE WORD</h1><p style="font-family: 'CJK';">中文 · 日本語 · 한국어 · 量子 (compatibility ideograph)</p><p style="direction: rtl; font-family: 'Arabic';">المبلغ الإجمالي 380.00</p>HTML;
$doc->writeHtml($html);
$out = getenv('NEXTPDF_OUT');$doc->save($out !== false ? $out : __DIR__ . '/multilingual-copy-paste-extraction.pdf');
echo "Wrote the multilingual PDF\n";对输出文件运行 pdftotext。带字母间距的标题会提取为 CODE WORD,并且不会插入任何空格;CJK 行会提取为对应的基础字符;阿拉伯语行会提取为逻辑字符串。
边界情况与陷阱
标题为“边界情况与陷阱”的章节- 请用 pdftotext 验证提取,而非 PyMuPDF。 PyMuPDF 的原始文本模式会忽略行内
/ActualText,并返回视觉字形,因此可能低估结果的正确性。Poppler(pdftotext)会遵循/ActualText;veraPDF 验证的是 PDF/UA-2,而不是提取。 - 提取需要
/ToUnicode。 注册并嵌入字体,让写入器输出/ToUnicodeCMap。未嵌入的非标准字体无法保证 Unicode 映射。 /ActualText覆盖塑形后与带字母间距的运行。 对于普通、未塑形、无间距的文本,仅靠/ToUnicode就能正确提取;/Span包裹器则保留带间距或经过重排序的文本运行。- 已加标签的 HTML 表格能通过 PDF/UA-2 检查。 提取是正确的,而且已加标签的 HTML
<table>现在能通过veraPDF --flavour ua2且零失败;参见无障碍。
构建 /ToUnicode CMap 与 /Span 包裹器的开销随字形数量线性增长。本示例预算为 wall_ms: 1500, peak_mb: 96。
安全注意事项
标题为“安全注意事项”的章节请校验用户提供的多语言字符串长度,确保输出大小有界。/ToUnicode 构建器会拒绝代理半区和超出码空间的码,因此格式错误的映射无法生成损坏的提取资源。引擎不会运行任何脚本,也不会为本地字体抓取任何远程资源。
符合性
标题为“符合性”的章节| 陈述 | 规范 | 条款 |
|---|---|---|
/ToUnicode CMap 会将字符码映射到 Unicode,以供提取。 | ISO 32000-2 | §9.10 |
/ActualText 是所包裹内容的精确替代。 | ISO 32000-2 | §14.9 |
| NFKC 是先做兼容分解、再做规范组合。 | Unicode UAX #15 | §1.2 |
商业情境
标题为“商业情境”的章节不适用。
另请参阅
标题为“另请参阅”的章节- 生成可供下游工具提取的文本内容 — 已加标签文本提取的基础。
- 渲染从右到左的阿拉伯语 HTML — 阿拉伯语塑形和从右到左文本。
- 排版 —
/ToUnicode和 NFKC 规范化。 - 无障碍 —
/ActualText和已加标签表格的支持。