При разработке подсистем предварительного просмотра документов на платформе 1С:Предприятие часто используется специализированный объект ДокументPDF совместно с элементом формы ПолеPDFДокумента. Однако на практике разработчики регулярно сталкиваются с ситуацией, когда большинство файлов открывается корректно, но отдельные PDF-документы вызывают исключение «Неправильный заголовок PDF файла» либо приводят к аварийному завершению работы платформы. При этом внешние программы просмотра (например, Adobe Acrobat Reader или веб-браузеры) открывают те же самые файлы без каких-либо нареканий.
Проанализируем типовой фрагмент клиентского кода, приводящий к ошибке:
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(ТекущиеДанные.АдресФайла);
Поток = ДвоичныеДанныеФайла.ОткрытьПотокДляЧтения();
ПросмотрPDF.Прочитать(Поток);
Выясним причину такого поведения встроенного механизма платформы и рассмотрим по шагам, как обойти эту проблему или устранить её корень.
Разберем, почему один и тот же файл успешно открывается во внешней программе, но выдает ошибку в 1С. Основные факторы заключаются в следующем:
%PDF- (шестнадцатеричные байты 25 50 44 46 2D). Внешние ридеры обладают высокой отказоустойчивостью: они могут просканировать первые сотни байт файла, пропуская пустые строки, пробелы, метку порядка байтов UTF-8 BOM (EF BB BF) или служебный мусор, оставленный веб-серверами и сканерами. Встроенный парсер платформы 1С требует, чтобы сигнатура находилась строго со смещения 0. Любой байт перед ней воспринимается как повреждение заголовка.ObjStm), специфические линейные структуры (Fast Web View) или нестандартное шифрование часто не могут быть обработаны подмножеством стандарта, реализованным в объекте ДокументPDF.1cv8c.exe.Рассмотрим самое простое и прямое решение проблемы. Ошибки разбора бинарных данных и нестандартных заголовков регулярно исправляются разработчиками платформы. Если в используемой версии (например, 8.3.25.1445) парсер завершает работу аварийно или не распознает документ, рекомендуется обновить платформу на актуальный релиз ветки 8.3.26 или 8.3.27, где механизмы работы с объектом ДокументPDF были существенно доработаны.
Посмотрим на практическую особенность реализации методов Прочитать(). В ряде релизов поведение платформы различается в зависимости от того, передается ли в метод интерфейс ПотокВПамяти или путь к файлу на диске. Чтение из физического файла на клиенте отрабатывает более стабильно.
Перепишем исходный код с сохранением двоичных данных во временный каталог:
ДвоичныеДанныеФайла = ПолучитьИзВременногоХранилища(ТекущиеДанные.АдресФайла);
ИмяВременногоФайла = ПолучитьИмяВременногоФайла("pdf");
ДвоичныеДанныеФайла.Записать(ИмяВременногоФайла);
Попытка
ПросмотрPDF.Прочитать(ИмяВременногоФайла);
Исключение
ВызватьИсключение;
Финально
УдалитьФайлы(ИмяВременногоФайла);
КонецПопытки;
Проанализируем ситуацию, когда сторонний источник (веб-сервер или МФУ) добавил перед заголовком документа лишние символы или байты BOM. В этом случае мы можем нормализовать двоичные данные перед открытием: найти позицию сигнатуры %PDF- и отсечь всё, что находится перед ней.
Разберем алгоритм исправления двоичных данных:
%PDF-.ПросмотрPDF.Прочитать().Если входящие PDF-файлы формируются внешними системами с систематическими ошибками в структуре (например, поврежденными таблицами перекрестных ссылок xref), целесообразно выполнять их предварительную нормализацию на стороне сервера при загрузке. Для этого подходят консольные утилиты вроде qpdf, Ghostscript или pdfcpu. Вызов утилиты с ключом линейной пересборки файла перезаписывает заголовок со смещения 0 и исправляет смещения всех внутренних объектов, делая файл абсолютно валидным для 1С.
Если специфика документов не позволяет отобразить их через встроенный ДокументPDF, а обновить платформу нет возможности, рассмотрим альтернативные механизмы просмотра внутри формы:
ПолеHTMLДокумента, куда внедряется библиотека PDF.js. Этот движок рендеринга полностью независим от багов платформы 1С и справляется практически с любыми поврежденными или нестандартными PDF-файлами.КаталогВременныхФайлов(), после чего вызывается команда ЗапуститьПриложение() или ЗапуститьПриложениеАсинх(). Документ откроется в установленном у пользователя Acrobat Reader или браузере без каких-либо ошибок.