Статьи

Эффективная генерация PDF в Drupal

Несколько месяцев назад у меня было требование клиента для генерации PDF, в данном случае для создания сертификатов, которые можно было просматривать в Интернете или распечатывать. Я потратил некоторое время на поиск лучших доступных вариантов Drupal и получил несколько советов о том, как лучше всего достичь этих целей. После того, как я рассказал о своих результатах нескольким людям, казалось, что генерация PDF была обычным требованием, и теперь у меня снова возникла такая же потребность в личном проекте, поэтому показалось, что это хороший пример для ознакомления с тем, что я нашел.

Почему бы просто не распечатать?

Если ваши требования просты, может быть проще просто попросить пользователей вашего сайта распечатать, и ничто не мешает им делать это. Если нам нужен уровень контроля над тем, что печатается, или мы хотим распространять файлы для печати, то нам нужно рассмотреть другие варианты.

Веб против печати

Создание PDF требует небольшого изменения мышления. Как веб-разработчики, мы потратили много времени на то, чтобы убедить дизайнеров отказаться от создания идеальных по пикселям дизайнов, которые будет сложно воспроизвести в Интернете. Если вы хотите внедрить создание PDF-файлов или какую-либо форму высококачественного вывода на печать, то нам нужно заново изучить некоторые из наших старых навыков, которые мы оставили. Характер печати означает, что она точная и часто требует идеального дизайна в пикселях (или миллиметрах).

Чего я пытаюсь достичь?

В настоящее время я работаю над настольной игрой и хочу, чтобы игроки могли создавать свои собственные карты, которыми можно поделиться на веб-сайте и распечатать для использования в игре. У нас есть определенный размер и расположение, которым эти карты всегда будут и должны соответствовать, вот первоначальный дизайн, который мы частично воссоздадим:

Варианты PDF в Drupal

В Drupal есть два варианта создания PDF-файлов. Модуль печати и просмотра PDF . Представления PDF вначале казались лучшим вариантом, поскольку они позволили бы нам использовать мощь представлений и множество вариантов, которые он предлагает. Тем не менее, он имеет модуль PHP как зависимость и, насколько я знаю, зависит от функции eval() . Генерация PDF потенциально может потребовать значительных усилий на сервере, и этот метод показался мне неэффективным, за исключением моего нежелания когда-либо включать в Drupal какой-либо модуль оценки PHP.

Это заставило меня остановиться на модуле печати, который также лучше поддерживается и предлагает множество других вариантов вывода, которые могут оказаться полезными.

Далее нам нужно определиться с нашей библиотекой генерации PDF, я собираюсь предложить вам использовать wkhtmltopdf и объяснить, почему позже, так как сначала я хочу создать что-то для сравнения. Сделайте это, посетив веб-сайт wkhtmltopdf и следуя инструкциям по настройке. Помните, что его необходимо установить на локальных и производственных сайтах. После установки вам нужно создать псевдоним исполняемого файла wkhtmltopdf в папке библиотек Drupal, а именно:

 ln -s /usr/bin/wkhtmltopdf /var/www/sites/all/libraries/wkhtmltopdf 

Если вы устанавливаете под Ubuntu, у меня возникли некоторые проблемы с официальным архивом, я рекомендую установить вручную по ссылкам выше.

Настройка модуля печати

Давайте начнем с общих настроек в admin/config/user-interface/print/common :

  • Параметры логотипа, Параметры нижнего колонтитула : отключено для моего примера.
  • Сохранить текущую тему CSS : включите ее для согласованности темы и уменьшения трудозатрат.

Давайте установим, как и где мы хотим, чтобы ссылки отображались в наших версиях PDF / Print, admin/config/user-interface/print/ui .

Я устанавливаю мой для отображения в блоке, чтобы я мог иметь больше контроля над макетом.

Общие параметры конфигурации для вывода PDF находятся по адресу admin/config/user-interface/print/pdf

Я рекомендую эти настройки:

  • Открыть PDF в : Новое окно браузера
  • Размер бумаги и ориентация : все, что подходит для вас. Пока я использую A7 для своей карты, она не совсем такая же, но достаточно близкая для этой демонстрации.
  • Кеширование : я еще не определился, насколько это эффективно, но применяются обычные правила, не используйте его во время разработки и в процессе производства.
  • Имя файла : я буду использовать [site:name] - [node:title] , вы можете использовать токены здесь.

Рассматривая особенности wkhtmltopdf, admin/config/user-interface/print/pdf/wkhtmltopdf .
Так как wkhtmltopdf — более продвинутый инструмент, это конфигурация на основе командной строки, более подробную информацию о которой вы можете найти здесь .

Вот некоторые дополнения, которые я добавил:

 --margin-bottom 0m --margin-left 0m --margin-top 0m --margin-right 0m --dpi 300 

Это гарантирует, что у нас нет полей, добавленных wkhtmltopdf, и мы можем положиться на наш вывод CSS. Мы также рендеринг на 300 точек на дюйм для печати.

Быстрая заметка на изображениях . Здесь есть варианты настройки рендеринга изображения с разрешением точек на дюйм, но, конечно, если кто-то загрузит изображение с разрешением 72 точки на дюйм и оно будет увеличено до 300 точек на дюйм, оно будет выглядеть плохо. Получение этого права является комбинацией конфигурации и обучения пользователей.

Создание HTML

Модуль печати работает путем воссоздания разметки HTML в качестве других форматов вывода. Мне проще создать разметку и CSS, которые в первую очередь приведут к такому выводу. В моем случае это влияет на вывод по умолчанию для моего типа контента, но это можно было бы разделить с помощью режимов просмотра или собственного вывода на печать модуля печати. Ниже приведен мой тип контента — я добавил несколько дополнительных полей, которые нужны моему типу контента, но не все из них:

Если вы хотите, модуль печати также предоставляет свой собственный режим просмотра, чтобы мы могли дублировать тот же дисплей или использовать в сочетании с методами, упомянутыми выше.

Создание стилей.

Модуль печати поставляется со своей собственной таблицей стилей ( print.css , которая находится в папке модуля), которую вы можете использовать для создания стилей, которые применяются только к визуализированным версиям узлов версией модуля печати. Вам нужно будет добавить копию вашей темы и добавить ее в файл .info вашей темы обычным способом.

Если вы отметили опцию Сохранить текущую тему CSS, как упомянуто выше, тогда модуль печати будет использовать ваши основные стили темы, а затем проверьте файл print.css наличие любых переопределений, которые вы хотите использовать только при выводе модуля печати. Это наиболее разумно для меня и похоже на самый аккуратный вариант. Если вы не используете эту опцию, то файл print.css будет единственной таблицей стилей, которая повлияет на ваш вывод. В остальной части этого примера предполагается, что он включен.

Вот упрощенная HTML-версия дизайна, который мы видели ранее:

Я использую подтему начальной загрузки, которая поставляется с собственной разметкой, которая может отличаться от вашей темы. У меня есть несколько пользовательских шрифтов, загруженных через font-your-face, и я создал собственный стиль изображения для изображения, эти имена полей также представляют мои поля, добавленные выше. Стили изображений не позволяют определять размеры в сантиметрах, чтобы получить правильный размер в пикселях. Я использовал этот инструмент .

У нас есть определенный размер печати, который мы пытаемся выполнить. Вы можете указать размеры в CSS в различных единицах, поэтому в нашем случае я использую сантиметры.

Вот мой CSS:

 //This is my main content area, will be different in other themes and in mine covers the regions that appear for logged in and anonymous users .node-type-event-card .main-container section.col-sm-9, .node-type-event-card .main-container section.col-sm-12 { border: solid 1px #000000; width: 6.8cm; height: 9.3cm; padding: 0.681cm; } //The card title .node-type-event-card .main-container h1.page-header { text-align: right; margin: 0; font-size: 14px; } //Sets card padding .node-type-event-card .main-container .content { padding: 20px; } //Formats the field contents .node-type-event-card .main-container .content .field { color: black; margin-top: 10px; margin-bottom: 10px; } .node-type-event-card .main-container .content .field-name-body { font-size: 12px; text-align: center; } .node-type-event-card .main-container .content .field-name-field-image img { width: 100%; } 

Вот как выглядит вывод PDF:

Не совсем верно.

Это потому, что модуль печати использует нашу тему, но другой файл tpl, print.tpl.php . Скопируйте его из модуля в свою тему, чтобы мы могли внести некоторые изменения. Вы можете добавить --format чтобы указать формат вывода, то есть print--pdf.tpl.php .

Основная причина, по которой мы хотим отредактировать это, заключается в том, что модуль печати по умолчанию печатает кучу ссылок в верхней части страницы и некоторые теги hr которые мы не хотим и не можем удалить в пользовательском интерфейсе, поэтому давайте исправим это. , Вот мой последний HTML:

 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML+RDFa 1.0//EN" "http://www.w3.org/MarkUp/DTD/xhtml-rdfa-1.dtd"> <html xmlns="http://www.w3.org/1999/xhtml" xml:lang="<?php print $language->language; ?>" version="XHTML+RDFa 1.0" dir="<?php print $language->dir; ?>"> <head> <?php print $head; ?> <base href='<?php print $url ?>' /> <title><?php print $print_title; ?></title> <?php print $scripts; ?> <?php if (isset($sendtoprinter)) print $sendtoprinter; ?> <?php print $robots_meta; ?> <?php if (theme_get_setting('toggle_favicon')): ?> <link rel='shortcut icon' href='<?php print theme_get_setting('favicon') ?>' type='image/x-icon' /> <?php endif; ?> <?php print $css; ?> </head> <body> <?php if (!empty($message)): ?> <div class="print-message"><?php print $message; ?></div><p /> <?php endif; ?> <?php if ($print_logo): ?> <div class="print-logo"><?php print $print_logo; ?></div> <?php endif; ?> <?php if (!isset($node->type)): ?> <h2 class="print-title"><?php print $print_title; ?></h2> <?php endif; ?> <div class="print-content"><?php print $content; ?></div> <div class="print-footer"><?php print theme('print_footer'); ?></div> <?php if ($sourceurl_enabled): ?> <div class="print-source_url"> <?php print theme('print_sourceurl', array('url' => $source_url, 'node' => $node, 'cid' => $cid)); ?> </div> <?php endif; ?> <?php print $footer_scripts; ?> </body> </html> 

И мой CSS ( print.css ) очень print.css на предыдущий CSS, но отражает структуру страницы:

 // I have found that clearing the margins helps with the PDF generation body { margin: 0; padding: 0; } html { margin: 0; } .print-content .node { border: solid 1px #000000; width: 6.8cm; height: 9.3cm; padding: 0.681cm; font-family: 'VT323'; font-size: 20px; } .print-content h2 { text-align: right; margin: 0; font-size: 14px; } .print-content .content { padding: 20px; } .print-content .content .field { color: black; margin-top: 10px; margin-bottom: 10px; } .print-content .content .field-name-body { font-size: 12px; text-align: center; } .print-content .content .field-name-field-image img { width: 100%; } 

Теперь, что не так со шрифтами? К сожалению, мы не можем использовать пользовательские шрифты, которые находятся на удаленном сервере (в данном случае Google Fonts). Я не уверен, если это проблема с модулем печати (глядя на print.tpl.php , он загружает стили по-другому), или это проблема wkhtmltopdf. Я нашел несколько других возможных путей, по которым вы можете пойти, если не сможете загрузить свой шрифт, но я предполагаю, что вы можете и покажете надежный метод.

Загрузите ваши шрифты и добавьте их локально, я помещаю их в theme/fonts и добавляю следующий CSS в верхней части вашего файла print.css.

 @font-face { font-family: 'VT323'; src: url('../fonts/VT323-Regular.ttf'); font-style: regular; font-weight: 400; } 

Вуаля!

Ну, у нас все еще есть запас, но это потому, что мы не используем правильный размер бумаги. Так что, кроме этого, это очень здорово!

Почему wkhtmltopdf?

Многие из вас могут быть знакомы с TCPDF и dompdf — они обычные и достаточно легкие. Я попробовал TCPDF и вот результаты:

Не так точно, как wkhtmltopdf из коробки, поэтому я попробовал dompdf:

Хм. Это потому, что я использую пользовательские шрифты и в документации упоминается, что с изменениями я могу заставить это работать. Тем не менее, wkhtmltopdf сработал для меня сразу, без каких-либо настроек или просеивания документации. Он нацелен на создание полной копии HTML, поэтому обычно он на 99% точнее. В моем последнем проекте (который был гораздо более сложным) я обнаружил несколько проблем при использовании нескольких техник CSS, которые более подходили для экрана, но даже они были исправимы.

Хотя wkhtmltopdf предлагает лучший выходной файл PDF, установка включает установку исполняемого файла, и это может сделать его непригодным для многих из вас. Тем не менее, я сделаю предположение, что если вы работаете с Drupal и вам необходимо достичь такого уровня сложности макета, то у вас есть доступ к вашему собственному серверу или VPS.

Вы пробовали какую-либо форму генерации PDF (или других форматов) с помощью Drupal? Я хотел бы услышать советы и хитрости, которые вы нашли.