Как создать PDF-файл из вашего веб-приложения
Опубликовано: 2022-03-10Многие веб-приложения требуют предоставления пользователю возможности загружать что-либо в формате PDF. В случае приложений (таких как магазины электронной коммерции) эти PDF-файлы должны создаваться с использованием динамических данных и быть немедленно доступными для пользователя.
В этой статье я рассмотрю способы создания PDF-файла непосредственно из веб-приложения на лету. Это не исчерпывающий список инструментов, вместо этого я постараюсь продемонстрировать различные подходы. Если у вас есть любимый инструмент или собственный опыт, которым вы хотите поделиться, добавьте его в комментарии ниже.
Начиная с HTML и CSS
Наше веб-приложение, скорее всего, уже создает HTML-документ, используя информацию, которая будет добавлена в наш PDF-файл. В случае счета-фактуры пользователь может просмотреть информацию в Интернете, а затем щелкнуть, чтобы загрузить PDF-файл для своих записей. Возможно, вы создаете упаковочные листы; еще раз, информация уже хранится в системе. Вы хотите отформатировать это в удобном для загрузки и печати виде. Поэтому для начала было бы неплохо подумать, можно ли использовать эти HTML и CSS для создания PDF-версии.
У CSS есть спецификация, касающаяся CSS для печати, и это модуль Paged Media. У меня есть обзор этой спецификации в моей статье «Проектирование для печати с помощью CSS», и многие издатели книг используют CSS для всей своей печатной продукции. Следовательно, поскольку сам CSS имеет спецификации для печатных материалов, мы, конечно же, должны иметь возможность его использовать?
Самый простой способ, которым пользователь может создать PDF-файл, — через браузер. Если выбрать печать в PDF, а не на принтер, будет создан PDF-файл. К сожалению, этот PDF обычно не совсем удовлетворительный! Для начала у него будут верхние и нижние колонтитулы, которые автоматически добавляются при печати чего-либо с веб-страницы. Он также будет отформатирован в соответствии с вашей таблицей стилей печати — при условии, что она у вас есть.
Проблема, с которой мы здесь сталкиваемся, заключается в плохой поддержке спецификации фрагментации в браузерах; это может означать, что содержимое ваших страниц прерывается необычным образом. Поддержка фрагментации неоднородна, как я обнаружил, изучая свою статью «Разрушение блоков с помощью фрагментации CSS». Это означает, что вы, возможно, не сможете предотвратить неоптимальное прерывание содержимого, когда заголовки остаются последним элементом на странице и т. д.
Кроме того, у нас нет возможности управлять содержимым полей на полях страницы, например, добавлять выбранный нами заголовок к каждой странице или нумерацию страниц, чтобы показать, сколько страниц содержит сложный счет. Эти вещи являются частью спецификации Paged Media, но не реализованы ни в одном браузере.
Моя статья «Руководство по состоянию таблиц стилей печати в 2018 году» по-прежнему точна с точки зрения типа поддержки, которую браузеры имеют для печати непосредственно из браузера с использованием таблицы стилей печати.
Печать с использованием механизмов браузерного рендеринга
Существуют способы печати в PDF с помощью механизмов рендеринга браузера, не заходя в меню печати в браузере и заканчивая верхними и нижними колонтитулами, как если бы вы распечатали документ. Самыми популярными вариантами в ответ на мой твит были wkhtmltopdf и печать с использованием безголового Chrome и Puppeteer.
wkhtmltopdf
Решение, которое несколько раз упоминалось в Твиттере, — это инструмент командной строки под названием wkhtmltopdf. Этот инструмент берет файл HTML или несколько файлов вместе с таблицей стилей и превращает их в PDF. Это делается с помощью механизма рендеринга WebKit.
Мы используем wkhtmltopdf. Это не идеально, хотя, вероятно, это была ошибка пользователя, но вполне достаточно для производственного приложения.
— Пол Кардно (@pcardno) 15 февраля 2019 г.
Таким образом, по сути, этот инструмент делает то же самое, что и печать из браузера, однако вы не получите автоматически добавленных верхних и нижних колонтитулов. С этой положительной стороны, если у вас есть рабочая таблица стилей печати для вашего контента, она также должна хорошо выводиться в PDF с помощью этого инструмента, и поэтому простой макет вполне может печатать очень хорошо.
Однако, к сожалению, вы по-прежнему будете сталкиваться с теми же проблемами, что и при печати непосредственно из веб-браузера, с точки зрения отсутствия поддержки спецификации Paged Media и свойств фрагментации, поскольку вы все еще печатаете с использованием механизма рендеринга браузера. Есть несколько флагов, которые вы можете передать в wkhtmltopdf, чтобы добавить обратно некоторые недостающие функции, которые были бы у вас по умолчанию при использовании спецификации Paged Media. Однако это требует дополнительной работы помимо написания хороших HTML и CSS.
Безголовый хром
Еще одна интересная возможность — использование Headless Chrome и Puppeteer для печати в PDF.
Кукольник. Это удивительно для этого.
— Алекс Рассел (@slightlylate) 15 февраля 2019 г.
Однако в очередной раз вы ограничены поддержкой браузером Paged Media и фрагментацией. Есть несколько параметров, которые можно передать в page.pdf()
. Как и в случае с wkhtmltopdf, они добавляют некоторые функциональные возможности, которые были бы возможны из CSS, если бы была поддержка браузера.
Вполне может быть, что одно из этих решений сделает все, что вам нужно, однако, если вы обнаружите, что ведете что-то вроде битвы, вероятно, вы достигаете пределов того, что возможно с текущими механизмами рендеринга браузера, и придется искать лучшее решение.
Полифиллы JavaScript для постраничных медиа
Есть несколько попыток по существу воспроизвести спецификацию Paged Media в браузере с помощью JavaScript — по сути, создать Polyfill Paged Media. Это может дать вам поддержку Paged Media при использовании Puppeteer. Взгляните на paged.js и Vivliostyle.
да. Для простых документов, таких как сертификаты курсов, мы можем использовать Chrome, который имеет минимальную поддержку @page. Для всего остального мы используем PrinceXML или полифил paged.js в Chrome. Вот подтверждение концепции WIP с использованием paged.js для книг: https://t.co/AZ9fO94PT2.
— Electric Book Works (@electricbook) 15 февраля 2019 г.
Использование агента пользователя для печати
Если вы хотите остаться с решением HTML и CSS, вам нужно обратиться к пользовательскому агенту (UA), предназначенному для печати из HTML и CSS, который имеет API для создания PDF из ваших файлов. Эти пользовательские агенты реализуют спецификацию Paged Media и гораздо лучше поддерживают свойства CSS Fragmentation; это даст вам больший контроль над выводом. Ведущие варианты включают в себя:
- принц
- Антенный дом
- PDFРеактор
UA для печати будет форматировать документы с помощью CSS — так же, как это делает веб-браузер. Как и в случае с браузерной поддержкой CSS, вам нужно проверить документацию этих UA, чтобы узнать, что они поддерживают. Например, Prince (с которым я лучше всего знаком) на момент написания статьи поддерживает Flexbox, но не поддерживает CSS Grid Layout. При отправке ваших страниц в инструмент, который вы используете, обычно это будет с определенной таблицей стилей для печати. Как и в случае с обычной таблицей стилей для печати, не все CSS, которые вы используете на своем сайте, подходят для версии в формате PDF.
Создание таблицы стилей для этих инструментов очень похоже на создание обычной таблицы стилей печати, принимая решения о том, что отображать или скрывать, возможно, используя другой размер шрифта или цвета. После этого вы сможете воспользоваться преимуществами спецификации Paged Media, добавляя сноски, номера страниц и т. д.
Что касается использования этих инструментов из вашего веб-приложения, вам нужно будет установить их на свой сервер (конечно, купив для этого лицензию). Основная проблема с этими инструментами заключается в том, что они дороги. Тем не менее, учитывая легкость, с которой вы затем можете создавать с их помощью печатные документы, они вполне могут окупить себя за сэкономленное время разработчиков.
Можно использовать Prince через API с оплатой за каждый документ через службу под названием DocRaptor. Это, безусловно, было бы хорошим местом для запуска многих приложений, поскольку казалось бы, что размещение собственных приложений станет более рентабельным, стоимость разработки переключения будет минимальной.
Бесплатная альтернатива, которая не так универсальна, как вышеупомянутые инструменты, но вполне может дать нужные вам результаты, — это WeasyPrint. Он не полностью реализует весь Paged Media, однако реализует больше, чем движок браузера. Однозначно, стоит попробовать!
Другие инструменты, которые утверждают, что поддерживают преобразование из HTML и CSS, включают PDFCrowd, который смело заявляет о поддержке HTML5, CSS3 и JavaScript. Однако я не смог найти никаких подробностей о том, что именно поддерживалось, и поддерживалась ли какая-либо спецификация Paged Media. Также в ответах на мой твит упоминается mPDF.
Отказ от HTML и CSS
Существует ряд других решений, которые отходят от использования HTML и CSS и требуют от вас создания определенного вывода для инструмента. Вот несколько претендентов на JavaScript:
- jsPDF
- pdfmake
Безголовый браузер + сохранение в PDF когда-то были моим первым выбором, но всегда давали некачественные результаты для всего, кроме одностраничного документа. Мы перешли на https://t.co/3o8Ce23F1t для многостраничных отчетов, что потребовало гораздо больше усилий, но в итоге оно того стоило!
— ДжиммиДжой (@jimle_uk) 15 февраля 2019 г.
Рекомендации
Помимо подходов на основе JavaScript, которые требуют от вас создания совершенно другого представления вашего контента для печати, красота многих из этих решений заключается в том, что они взаимозаменяемы. Если ваше решение основано на вызове инструмента командной строки и передаче этому инструменту вашего HTML, CSS и, возможно, некоторого JavaScript, переключаться между инструментами довольно просто.
В ходе написания этой статьи я также обнаружил оболочку Python, которая может запускать ряд различных инструментов. (Обратите внимание, что сами инструменты должны быть уже установлены, однако это может быть хорошим способом протестировать различные инструменты на образце документа.)
В плане поддержки Paged Media и фрагментации на первое место выходят Prince, Antenna House и PDFReactor. Как коммерческие продукты, они также поставляются с поддержкой. Если у вас есть бюджет, сложные страницы для печати в PDF и ваше ограничение — время разработчика, то вы, скорее всего, обнаружите, что это самый быстрый путь к тому, чтобы ваше создание PDF работало хорошо.
Однако во многих случаях вам подойдут бесплатные инструменты. Если ваши требования очень просты, то wkhtmltopdf или базовое безголовое решение для Chrome и Puppeteer может помочь. Это определенно сработало для многих людей, которые ответили на мой первоначальный твит.
Однако, если вы обнаружите, что изо всех сил пытаетесь получить желаемый результат, имейте в виду, что это может быть ограничение печати браузера, а не то, что вы делаете неправильно. В случае, если вам нужна дополнительная поддержка Paged Media, но вы не в состоянии перейти на коммерческий продукт, возможно, обратите внимание на WeasyPrint.
Я надеюсь, что это полезный обзор инструментов, доступных для создания PDF-файлов из вашего веб-приложения. По крайней мере, это демонстрирует, что существует широкий выбор вариантов, если ваш первоначальный выбор не работает.
Пожалуйста, поделитесь своим собственным опытом и предложениями в комментариях, это одна из тех вещей, с которыми многие из нас в конечном итоге сталкиваются, и обмен личным опытом может быть невероятно полезным.
Дальнейшее чтение
Обзор различных ресурсов и инструментов, упомянутых в этой статье, а также некоторых других полезных ресурсов для работы с PDF-файлами из веб-приложений.
Характеристики
- Постраничный медиа-модуль
- Фрагментация
Статьи и ресурсы
- Проектирование для печати с помощью CSS
- Разрушение блоков с помощью фрагментации CSS
- Руководство по состоянию таблиц стилей печати в 2018 году
- Начало работы с Headless Chrome и Puppeteer
- печать-css.rocks
Инструменты
- wkhtmltopdf
- paged.js
- Вивлиостиль
- принц
- Антенный дом
- PDFРеактор
- ДокРаптор
- WeasyPrint
- PDFCrowd
- mPDF
- jsPDF
- pdfmake
- Создать и опубликовать сервер