Перейти к содержимому

Устранение неполадок: шрифты, создание подмножеств и тегирование

В этих записях разобраны сбои при разрешении и разборе шрифтов, возникающие через NextPDF\Exception\FontNotFoundException и NextPDF\Exception\FontParsingException. Также здесь есть диагностика покрытия для китайского, японского и корейского языков (CJK) и проблемы дерева структуры, влияющие на тегированный вывод. В каждой записи указано точное исключение или тест, по которому вы можете проверить причину.

  • Симптом. FontNotFoundException с сообщением вида Font "<name>" not found. Searched: [<paths>].
  • Вероятная причина. Запрошенное семейство шрифтов или путь к файлу не существует, недоступно для чтения или находится в каталоге шрифтов, к которому среда выполнения не может получить доступ. Данные шрифта могут быть корректными, но движок всё равно не может получить к ним доступ.
  • Доказательства / диагностика. getContext() возвращает font_name, search_paths и fallback_attempted. Используйте search_paths, чтобы просмотреть все расположения, которые проверял движок. Используйте fallback_attempted, чтобы подтвердить, был ли уже задействован запасной вариант.
  • Решение.
    1. Сравните запрошенное font_name с файлом шрифта, который фактически присутствует.
    2. Добавьте каталог, содержащий шрифт, в список настроенных каталогов шрифтов или исправьте переданный вами путь.
    3. Убедитесь, что пользователь среды выполнения может прочитать файл.
    4. Выполните вызов повторно.
  • См. также. Справочник по исключениям.
  • Симптом. FontParsingException с сообщением вида Failed to parse font file "<file>": <reason>.
  • Вероятная причина. Движок нашёл файл шрифта, но не может использовать его содержимое: заголовок усечён, каталог таблиц недопустим или отсутствует обязательная таблица, такая как head, hhea или OS/2.
  • Доказательства / диагностика. getContext() возвращает font_file и parse_error. parse_error указывает структурную проблему.
  • Решение.
    1. Проверьте parse_error, чтобы определить структурный дефект.
    2. Замените файл шрифта заведомо исправной копией того же начертания.
    3. Выполните вызов повторно.
  • См. также. Справочник по исключениям.

Запись: создание подмножества завершается сбоем на некорректной таблице шрифта

Заголовок раздела «Запись: создание подмножества завершается сбоем на некорректной таблице шрифта»
  • Симптом. FontParsingException со значением font_file, равным font-subset, и значением parse_error, таким как Invalid head table: too short, Invalid hhea table: too short, Invalid maxp table: too short или Failed to unpack font data.
  • Вероятная причина. Шрифт прошёл первоначальную загрузку, но таблица, необходимая для создания подмножества, усечена или не может быть распакована. Модуль создания подмножеств отклоняет шрифт, вместо того чтобы создать неработающее подмножество.
  • Доказательства / диагностика. Когда таблица head, hhea или maxp слишком короткая или распаковка завершается сбоем, src/Typography/FontSubsetter.php вызывает FontParsingException с литеральным токеном font-subset в качестве имени файла. Этот токен указывает, что сбой произошёл во время создания подмножества, а не при первоначальной загрузке.
  • Решение.
    1. Замените исходный шрифт полной, неусечённой копией того же начертания.
    2. Если шрифт создаётся инструментом сборки, пересоздайте его и убедитесь, что таблицы head, hhea и maxp полные.
    3. Запустите сборку повторно.
  • См. также. Проверка PDF/A и PDF/UA.

Запись: текст CJK отображается с отсутствующими глифами

Заголовок раздела «Запись: текст CJK отображается с отсутствующими глифами»
  • Симптом. Китайский, японский или корейский текст отображается как пустые прямоугольники или отсутствующие символы, а покрытие CJK выбранным шрифтом вызывает сомнения.
  • Вероятная причина. Выбранный шрифт не охватывает блоки Unicode, нужные для письменности. Каждая письменность CJK требует определённых блоков в дополнение к общим блокам идеографов.
  • Доказательства / диагностика. src/Typography/CjkFontValidator.php предоставляет validateCoverage(FontInfo $font, CjkScript $script). Он возвращает CjkCoverageResult с процентом покрытия и блоками, которые не достигают 50% порога отчётности. Валидатор берёт выборку кодовых точек. Это диагностический инструмент, и он не влияет на загрузку шрифтов.
  • Решение.
    1. Запустите CjkFontValidator::validateCoverage() для шрифта и целевой письменности.
    2. Проверьте missingRanges, чтобы увидеть, какие блоки не покрыты, например, Bopomofo для традиционного китайского, Hiragana и Katakana для японского и Hangul Syllables для корейского.
    3. Выберите шрифт, который охватывает эти блоки, или добавьте запасной шрифт, который их охватывает.
    4. Снова запустите отрисовку и проверьте покрытие.
  • См. также. Справочник по исключениям.

Запись: предопределённая CMap не соответствует письменности CJK

Заголовок раздела «Запись: предопределённая CMap не соответствует письменности CJK»
  • Симптом. Текст CJK сопоставляется с неправильными глифами, или документ использует предопределённую CMap, которая не соответствует его языку.
  • Вероятная причина. По обнаруженной письменности выбирается имя предопределённой CMap от Adobe. Если шрифт охватывает только общий блок идеографов и не содержит блока, специфичного для письменности, он по умолчанию определяется как упрощённый китайский.
  • Доказательства / диагностика. CjkFontValidator::detectScript() возвращает обнаруженную письменность, а resolvePredefinedCMapName() сопоставляет её: упрощённый китайский с UniGB-UTF16-H, традиционный китайский с UniCNS-UTF16-H, японский с UniJIS-UTF16-H и корейский с UniKS-UTF16-H. Если блок, специфичный для письменности, отсутствует, результат обнаружения откатывается к упрощённому китайскому.
  • Решение.
    1. Убедитесь, что шрифт содержит блок, специфичный для письменности: Bopomofo для традиционного китайского, Hiragana или Katakana для японского и Hangul для корейского.
    2. Если документ на традиционном китайском, но в шрифте нет блока Bopomofo, выберите шрифт, который его включает, чтобы обнаружение вернуло нужную письменность.
    3. Запустите отрисовку повторно.
  • См. также. Справочник по исключениям.

Запись: тегированное содержимое не создаёт пригодное дерево структуры

Заголовок раздела «Запись: тегированное содержимое не создаёт пригодное дерево структуры»
  • Симптом. Сборка с тегированием не создаёт структуру, либо последующая проверка доступности сообщает о пустом или отсутствующем дереве структуры.
  • Вероятная причина. Сборка вывела содержимое вне пути тегирования, поэтому элементы структуры не были созданы. Дерево структуры остаётся пустым.
  • Доказательства / диагностика. src/Accessibility/StructureTree.php и src/Accessibility/TaggedContentEmitter.php строят дерево структуры из тегированного содержимого. Тест tests/Integration/Accessibility/EmptyTaggedPdfDoesNotAdvertisePdfUa2Test.php подтверждает, что пустое дерево структуры не заявляет о PDF/UA-2.
  • Решение.
    1. Убедитесь, что содержимое выводится через путь тегирования, чтобы создавались элементы структуры.
    2. Убедитесь, что каждая последовательность маркированного содержимого сопоставляется с элементом структуры.
    3. Повторно запустите сборку и проверьте дерево структуры.
  • См. также. Проверка PDF/A и PDF/UA.

Запись: языковой тег элемента структуры отклонён

Заголовок раздела «Запись: языковой тег элемента структуры отклонён»
  • Симптом. Сборка завершается сбоем, потому что значение языка в элементе структуры или документе не является допустимым тегом.
  • Вероятная причина. Указанное значение языка не является допустимым тегом BCP-47. Валидатор отклоняет некорректные теги и не пропускает их в вывод.
  • Доказательства / диагностика. src/Accessibility/Bcp47Validator.php проверяет тег языка. Недопустимый тег вызывает src/Accessibility/InvalidBcp47TagException.php. tests/Unit/Conformance/PdfUa2Section844LangStrictTest.php проверяет строгое требование к языку PDF/UA-2.
  • Решение.
    1. Замените значение языка допустимым тегом BCP-47, таким как en-US, de-DE или zh-Hant-TW.
    2. Установите язык на конкретном элементе структуры, если язык фрагмента отличается от языка документа.
    3. Запустите сборку повторно.
  • См. также. Проверка PDF/A и PDF/UA.
  • FontNotFoundException и FontParsingException сообщают о разных сбоях. Not-found означает, что файл недоступен. Parsing означает, что файл доступен, но его байты непригодны для использования. Проверьте класс исключения, чтобы определить, какой сбой произошёл.
  • font-subset в font_file — это намеренный маркер этапа создания подмножества, а не фактический путь. Не ищите файл с именем font-subset.
  • CjkFontValidator берёт выборку кодовых точек вместо проверки каждой из них, поэтому его показатель покрытия является оценкой для выбора шрифта, а не побайтовым аудитом.
  • Пустое дерево структуры по замыслу помечается как не соответствующее PDF/UA-2. Это задокументированное поведение движка, а не дефект.

Глоссарий: создание подмножеств шрифтов · покрытие CJK · дерево структуры