Создание PDF-файлов с CJK и арабским текстом для корректного копирования и вставки
Краткий обзор
Заголовок раздела «Краткий обзор»Создайте файл Portable Document Format (PDF) с китайским, японским, корейским (CJK) и арабским текстом, который при копировании и вставке сохраняет исходные логические символы. Движок сопоставляет каждый глиф с Unicode через CMap /ToUnicode, канонизирует результат в форме нормализации совместимости с композицией (NFKC) и оборачивает сформированные прогоны или прогоны с разрядкой в /Span, который несёт /ActualText. Зарегистрируйте шрифты и выведите содержимое — извлечение останется корректным. Проверяйте извлечение через pdftotext/Poppler, а не PyMuPDF; veraPDF валидирует соответствие PDF/Universal Accessibility 2 (PDF/UA-2), а не извлечение.
Установка
Заголовок раздела «Установка»composer require nextpdf/coreЗарегистрируйте CJK-шрифт, например Noto Sans CJK, и шрифт с поддержкой арабского, например Noto Naskh Arabic, с таблицей символов, покрывающей блок Arabic Presentation Forms-B. Встраивайте только шрифты, на встраивание которых у вас есть права.
Концептуальный обзор
Заголовок раздела «Концептуальный обзор»Коды глифов в потоке содержимого — это не Unicode. CMap /ToUnicode сопоставляет каждый код обратно с Unicode, чтобы средство чтения могло извлечь текст (ISO 32000-2 §9.10). Движок канонизирует эти значения в форме нормализации совместимости с композицией (NFKC), как определено в Unicode UAX #15. Идеографы совместимости CJK и арабские формы представления сопоставляются со своими базовыми символами, поэтому поиск и копирование возвращают канонический текст вместо символов совместимости или форм представления.
В двух случаях одного /ToUnicode недостаточно: для латиницы с разрядкой и сформированного арабского с направлением справа налево. Движок отрисовывает их как разнесённые или переупорядоченные глифы, поэтому по одному порядку глифов нельзя восстановить логическую строку. Движок оборачивает каждый прогон в последовательность размеченного содержимого /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. Регистрируйте и встраивайте шрифты, чтобы компонент записи выводил CMap/ToUnicode. Для невстроенного нестандартного шрифта нельзя гарантировать сопоставление с Unicode. /ActualTextохватывает сформированные прогоны и прогоны с разрядкой. Для обычного несформированного текста без разрядки одного/ToUnicodeдостаточно для корректного извлечения; обёртка/Spanсохраняет прогоны с разрядкой или переупорядочением.- Тегированные HTML-таблицы проходят проверки PDF/UA-2. Извлечение корректно, и тегированная HTML-
<table>теперь проходитveraPDF --flavour ua2без единой ошибки — см. Доступность.
Производительность
Заголовок раздела «Производительность»Построение CMap /ToUnicode и обёрток /Span линейно зависит от числа глифов. Бюджет этого рецепта — wall_ms: 1500, peak_mb: 96.
Замечания по безопасности
Заголовок раздела «Замечания по безопасности»Проверяйте длину многоязычных строк от пользователя, чтобы ограничивать размер вывода. Построитель /ToUnicode отклоняет половины суррогатных пар и коды вне кодового пространства, поэтому некорректное сопоставление не может создать повреждённый ресурс извлечения. Движок не выполняет сценарии и не загружает удалённые ресурсы при работе с локальными шрифтами.
Соответствие
Заголовок раздела «Соответствие»| Утверждение | Спецификация | Пункт |
|---|---|---|
CMap /ToUnicode сопоставляет коды символов с Unicode для извлечения. | ISO 32000-2 | §9.10 |
/ActualText — точная замена вложенного содержимого. | ISO 32000-2 | §14.9 |
| NFKC — это декомпозиция совместимости с последующей канонической композицией. | Unicode UAX #15 | §1.2 |
Коммерческий контекст
Заголовок раздела «Коммерческий контекст»Не применимо.
См. также
Заголовок раздела «См. также»- Извлечение текстового содержимого — основа для тегированного извлечения.
- Отрисовка арабского HTML с направлением справа налево — формирование арабского текста и письмо справа налево.
- Типографика —
/ToUnicodeи канонизация NFKC. - Доступность —
/ActualTextи поддержка тегированных таблиц.