Гид по технологиям

Создание PDF в Node.js с помощью PDFKit

6 min read Development Обновлено 13 Dec 2025
PDFKit: создание PDF в Node.js
PDFKit: создание PDF в Node.js

Рука печатает на ноутбуке, на экране открыт документ

Введение

PDFKit — это библиотека для Node.js, предназначенная для создания и изменения PDF‑документов программно. Она предоставляет понятный API для добавления текста, изображений, векторной графики и управления страницами. Подходит для отчётов, счётов, чеков, билетов и любых документов, которые нужно сгенерировать на сервере.

Определение: PDF (Portable Document Format) — формат для представления документов, сохраняющий оформление и внешний вид на любых устройствах.

Быстрая проверка окружения

Перед началом убедитесь, что на машине установлены Node.js и npm. В терминале выполните:

node -v
npm -v

Если команды возвращают версии — можно продолжать.

Установка PDFKit

В каталоге проекта запустите:

npm install pdfkit

Это добавит pdfkit в зависимости проекта.

Важная заметка: если ваш проект требует встроенных шрифтов или поддержки шрифтовых файлов TrueType/OpenType, убедитесь, что эти файлы доступны в репозитории или в окружении выполнения.

Создание простого PDF — минимальный пример

Основные шаги:

  1. Подключить модуль pdfkit и fs.
  2. Создать экземпляр PDFDocument.
  3. Пропайпить поток в файл или ответ HTTP.
  4. Заполнить содержимым.
  5. Вызвать doc.end() для завершения потока.

Пример сохранения в файл:

const PDFDocument = require('pdfkit');
const fs = require('fs');

const doc = new PDFDocument();
doc.pipe(fs.createWriteStream('MyPDFDoc.pdf'));

doc.text('Coding is Easy!');

doc.end();

Запустите: node <имя_скрипта>. После выполнения в рабочем каталоге появится MyPDFDoc.pdf.

Потоковая отправка PDF в HTTP‑ответ

Часто PDF генерируют на сервере и сразу отправляют в браузер без сохранения на диск.

Пример Express.js:

const express = require('express');
const PDFDocument = require('pdfkit');

const app = express();
app.get('/invoice', (req, res) => {
  const doc = new PDFDocument();
  res.setHeader('Content-Type', 'application/pdf');
  res.setHeader('Content-Disposition', 'attachment; filename=invoice.pdf');

  doc.pipe(res);
  doc.text('Invoice #12345');
  doc.end();
});

app.listen(3000);

Важно: заголовки нужно установить до начала передачи данных.

Добавление текста и форматирование

Основное: метод text() добавляет текст и перемещает текущую позицию курсора на новую строку. По умолчанию PDFKit использует стандартные 14 шрифтов PDF, но можно подключать внешние.

Примеры: позиционирование и перемещение:

doc.text('Coding is Easy!');

// Позиционирование по координатам (x, y)
doc.text('Coding is Easy!', 100, 100);

// Переместиться вниз на 3 строки
doc.moveDown(3);

// Переместиться вверх на 1 строку
doc.moveUp();

Шрифты и размеры:

// Использование стандартного шрифта
doc.font('Times-Roman').text('Coding is Easy!');

// Цвет и размер
doc.fillColor('red').fontSize(8).text('Coding is Easy!');

Если нужно подключить свой файл шрифта:

// Регистрация и использование локального TTF/OTF
// (если шрифт лежит в ./fonts/Custom.ttf)
doc.registerFont('Custom', 'fonts/Custom.ttf');
doc.font('Custom').text('Текст с пользовательским шрифтом');

Добавление изображений

PDFKit поддерживает PNG и JPEG. Чтобы вставить изображение, передайте путь к файлу или Buffer.

// Вставить изображение в исходном размере
doc.image('path/to/image.jpeg');

// Указать ширину и/или высоту
doc.image('path/to/image.jpg', { width: 300 });

doc.image('path/to/image.jpg', { width: 300, height: 200 });

Также можно задавать выравнивание и положение (x, y). При работе с большими изображениями учитывайте потребление памяти.

Управление страницами и размерами

Добавление новой страницы:

doc.addPage();

Можно подписаться на событие добавления страницы:

doc.on('pageAdded', () => doc.text('Coding is Easy!'));

Размеры страниц и ориентация задаются при создании документа или при добавлении страницы. Примеры стандартных размеров:

// Установить размер по умолчанию при создании документа
const docA5 = new PDFDocument({ size: 'A5' });

// Поменять размер при добавлении страницы
doc.addPage({ size: 'A7' });

Установка полей (отступов) при добавлении страницы:

// Задаём разные отступы
doc.addPage({
  margins: {
    top: 72,
    bottom: 72,
    left: 50,
    right: 50
  }
});

// Один общий отступ для всех сторон
doc.addPage({ margin: 60 });

Примечание по локализации единиц: в PDFKit размеры задаются в пунктах (points). 72 пункта = 1 дюйм.

Векторная графика: линии, прямоугольники, кривые

PDFKit позволяет рисовать простые фигуры:

// Рисуем линию
doc.moveTo(100, 150).lineTo(100, 250).stroke();

// Прямоугольник
doc.rect(100, 300, 200, 100).fill('#FF0000');

Используйте save() и restore() для локального изменения состояния (цвет, ширина линии, трансформации).

Практические рекомендации и эвристики

  • Минимизируйте встраивание больших растровых изображений — используйте оптимизированные форматы и размеры.
  • Для таблиц используйте сторонние утилиты или прорисовывайте линии и текст вручную; PDFKit не содержит готовой реализации таблиц, но есть вспомогательные пакеты сообщества.
  • Тестируйте генерацию на объёмах, похожих на продакшен, чтобы выявить утечки памяти.
  • Всегда закрывайте поток вызовом doc.end(), иначе файл/ответ останутся неполными.
  • Для многостраничных шаблонов выносите повторяющиеся элементы (шапка/подвал) в функцию, вызываемую при событии pageAdded.

Когда PDFKit может не подойти (ограничения)

  • Если нужен точный рендер HTML/CSS в PDF (сложная верстка), лучше использовать движки, рендерящие HTML (Puppeteer, wkhtmltopdf).
  • При большом количестве таблиц со сложным переносом текста возможно удобнее использовать специализированные конструкторы PDF или готовые шаблоны.
  • Для массовой генерации миллионов документов обратите внимание на ресурсоёмкость и горизонтальное масштабирование сервиса генерации.

Альтернативы и сравнение (обзор)

  • Puppeteer — рендерит HTML/CSS в PDF (хорошо для сложной верстки, но тяжелее по ресурсам).
  • wkhtmltopdf — инструмент командной строки: преобразует HTML в PDF через WebKit.
  • PDFMake — удобен для декларативного описания контента в формате JSON; проще для таблиц и структуры, но другой подход к API.

Выбор зависит от того, хотите ли вы генерировать PDF из HTML (Puppeteer/wkhtmltopdf) или формировать документ программно (PDFKit/PDFMake).

Контроль качества и тесты

Критерии приёмки:

  • PDF откывается в основных ридерах (Adobe Reader, браузеры).
  • Шрифты отображаются корректно; нет замены шрифта на системный.
  • Все страницы содержат ожидаемый контент (шапка, тело, подвал).
  • Сгенерированные файлы соответствуют ожидаемым размерам и числу страниц.

Тестовые сценарии:

  • Генерация документа с разными шрифтами и языками (кириллица, латиница).
  • Вставка большого изображения и проверка, что файл не превышает допустимого размера.
  • Стресс‑тест: одновременные запросы генерации PDF и контроль потребления памяти.

Role‑based checklist (проверка ролям)

Разработчик:

  • Установил pdfkit и зависимости.
  • Написал модуль генерации с учётом ошибок и логированием.

DevOps:

  • Настроил лимиты памяти/пул воркеров для сервиса генерации.
  • Обеспечил хранение шрифтов в доступном и защищённом месте.

QA:

  • Проверил отображение на целевых ридерах.
  • Запустил регрессионные тесты формата и содержимого.

Мини‑методология: как организовать генерацию PDF в проекте

  1. Выделите отдельный модуль/сервис для генерации PDF.
  2. Создайте шаблоны и функции для повторяющихся блоков (шапка, подвал).
  3. Поддерживайте централизованное хранилище шрифтов и ресурсов (изображения).
  4. Логируйте ошибки и время генерации; добавьте метрики (latency, success/failure).
  5. Тестируйте с эталонными примерами и добавляйте их в CI.

Пример расширенного шаблона счёта (invoice)

Короткий пример структуры исходного кода для счета:

function renderHeader(doc, invoice) {
  doc.fontSize(20).text('Company Name', 50, 50);
  doc.fontSize(10).text(`Invoice #${invoice.number}`, 50, 80);
}

function renderFooter(doc) {
  doc.fontSize(10).text('Thank you for your business.', 50, doc.page.height - 50);
}

function renderTable(doc, items) {
  // простая прорисовка строк таблицы через text() и линии
}

function createInvoice(invoice, path) {
  const PDFDocument = require('pdfkit');
  const fs = require('fs');
  const doc = new PDFDocument({ margin: 50 });
  doc.pipe(fs.createWriteStream(path));

  renderHeader(doc, invoice);
  renderTable(doc, invoice.items);
  renderFooter(doc);

  doc.end();
}

Отладка и распространённые ошибки

  • «PDF не открывается» — скорее всего, забыли doc.end() или в поток уже записаны данные до установки заголовков.
  • «Шрифт не отображается» — путь к файлу шрифта неверен или шрифт не поддерживает нужные глифы.
  • «Память растёт» — проверьте, не храните в памяти большие картинки как строки; используйте потоки и оптимизацию изображений.

Важно: логируйте стек ошибок и сохраняйте образцы неудачных входных данных для воспроизведения.

Безопасность и приватность

  • Если вы генерируете PDF с персональными данными, храните и передавайте их в зашифрованном виде и соблюдайте правила GDPR/локального законодательства.
  • Минимизируйте права файлов и доступ к шрифтам/ресурсам.

Ментальные модели при выборе инструмента

  • Если нужно «программно» рисовать документ — PDFKit.
  • Если нужно «верстать» через HTML/CSS — Puppeteer или wkhtmltopdf.
  • Если нужен декларативный JSON‑подход — PDFMake.

Короткий глоссарий

  • doc.pipe — метод для передачи данных из PDFKit в поток (файл/HTTP‑ответ).
  • doc.end — завершает генерацию документа и закрывает поток.
  • points/пункты — единица измерения в PDF (72 пункта = 1 дюйм).

Итог и рекомендации

PDFKit — стабильный выбор, если вы хотите гибко управлять содержимым PDF программно. Для сложной HTML‑верстки рассмотрите рендеринг через браузерный движок. Всегда тестируйте генерацию на реальных данных и предусмотрите обработку ошибок и ограничение ресурсов.

Important: всегда вызываетe doc.end(), тестируйте вывод в целевых PDF‑ридерах и следите за использованием памяти в нагрузочных сценариях.

Краткое резюме:

  • PDFKit удобен для программной генерации PDF из Node.js.
  • Поддерживает текст, изображения, векторную графику и управление страницами.
  • При необходимости комбинируйте с другими инструментами (Puppeteer, PDFMake) в зависимости от задач.
Поделиться: X/Twitter Facebook LinkedIn Telegram
Автор
Редакция

Похожие материалы

Как проверить звонок 911 на телефоне
Мобильные телефоны

Как проверить звонок 911 на телефоне

Рождественская открытка в Photoshop — пошагово
Дизайн

Рождественская открытка в Photoshop — пошагово

Как выгнать воду из Apple Watch
Гаджеты

Как выгнать воду из Apple Watch

Как играть в игры Nintendo Switch офлайн
Gaming

Как играть в игры Nintendo Switch офлайн

Сортировка фото по лицам в Windows — руководство
Windows

Сортировка фото по лицам в Windows — руководство

Расширение Wi‑Fi с Tomato‑роутерами
Сети

Расширение Wi‑Fi с Tomato‑роутерами