Как встроить PDF.js на сайт и настроить интерфейс под свои задачи
PDF.js — это библиотека от Mozilla, позволяющая отображать PDF-документы прямо в браузере с помощью HTML5 Canvas. Чтобы быстро внедрить просмотрщик, подключите скрипты pdf.min.js и pdf.worker.min.js, создайте HTML-контейнер <canvas> и используйте метод pdfjsLib.getDocument() для загрузки файла. Для полноценного интерфейса с навигацией проще использовать готовый компонент PDFViewer из дистрибутива библиотеки, который затем можно стилизовать через CSS или модифицировать через JS API.
Почему выбирают PDF.js
В отличие от встроенных браузерных средств просмотра (которые часто открывают файл в новой вкладке или используют сторонние плагины), PDF.js дает полный контроль над отображением документа.
Ключевые преимущества:
- Безопасность: Документ обрабатывается на клиенте, нет необходимости отправлять файлы на сторонние серверы.
- Кроссбраузерность: Единое поведение в Chrome, Firefox, Safari и Edge.
- Гибкость UI: Вы можете скрыть ненужные кнопки, добавить свой логотип, изменить цвета или интегрировать просмотр в модальное окно.
- Производительность: Поддержка ленивой загрузки страниц и веб-воркеров для выноса тяжелых вычислений в отдельный поток.
Важно: PDF.js предназначен только для просмотра. Редактирование содержимого PDF (изменение текста, добавление полей) этой библиотекой не поддерживается.
Способы интеграции: от простого к сложному
Существует два основных подхода к внедрению библиотеки. Выбор зависит от того, насколько сильно вам нужно кастомизировать интерфейс.
1. Использование готового Viewer (Рекомендуемый способ)
Официальный дистрибутив PDF.js включает готовый интерфейс (viewer.html), который содержит панель инструментов, навигацию, поиск и боковую панель с миниатюрами.
Как подключить:
- Скачайте предсобранный пакет с официального сайта или установите через npm:
npm install pdfjs-dist. - Разместите файлы
build/иweb/на вашем сервере. - Встройте viewer через
<iframe>или перенесите его разметку в свой шаблон.
<iframe src="/path/to/web/viewer.html?file=/path/to/document.pdf" width="100%" height="600px"></iframe>
Этот метод идеален, если вам нужен стандартный функционал «как в Adobe Reader», но в рамках вашего дизайна.
2. Кастомная реализация через API (Core)
Если вам нужен минималистичный просмотрщик (например, только одна страница без лишних кнопок), используйте ядро библиотеки.
Базовая структура HTML:
<div id="pdf-container">
<canvas id="the-canvas"></canvas>
</div>
<div class="controls">
<button id="prev">Назад</button>
<button id="next">Вперед</button>
<span>Страница: <span id="page_num"></span> / <span id="page_count"></span></span>
</div>
Пример JavaScript кода:
import * as pdfjsLib from 'pdfjs-dist';
// Указываем путь к воркеру (обязательно!)
pdfjsLib.GlobalWorkerOptions.workerSrc = '/path/to/pdf.worker.min.mjs';
const url = 'document.pdf';
let pdfDoc = null,
pageNum = 1,
pageRendering = false,
pageNumPending = null,
scale = 1.5,
canvas = document.getElementById('the-canvas'),
ctx = canvas.getContext('2d');
/**
* Рендеринг страницы
*/
function renderPage(num) {
pageRendering = true;
// Получаем страницу
pdfDoc.getPage(num).then(function(page) {
const viewport = page.getViewport({scale: scale});
canvas.height = viewport.height;
canvas.width = viewport.width;
// Рендерим контекст страницы
const renderContext = {
canvasContext: ctx,
viewport: viewport
};
const renderTask = page.render(renderContext);
// Ожидаем завершения рендеринга
renderTask.promise.then(function() {
pageRendering = false;
if (pageNumPending !== null) {
renderPage(pageNumPending);
pageNumPending = null;
}
});
});
// Обновляем счетчики страниц
document.getElementById('page_num').textContent = num;
}
/**
* Если идет рендеринг другой страницы, ждем окончания
*/
function queueRenderPage(num) {
if (pageRendering) {
pageNumPending = num;
} else {
renderPage(num);
}
}
/**
* Предыдущая страница
*/
function onPrevPage() {
if (pageNum <= 1) return;
pageNum--;
queueRenderPage(pageNum);
}
/**
* Следующая страница
*/
function onNextPage() {
if (pageNum >= pdfDoc.numPages) return;
pageNum++;
queueRenderPage(pageNum);
}
document.getElementById('prev').addEventListener('click', onPrevPage);
document.getElementById('next').addEventListener('click', onNextPage);
// Загрузка документа
pdfjsLib.getDocument(url).promise.then(function(pdfDoc_) {
pdfDoc = pdfDoc_;
document.getElementById('page_count').textContent = pdfDoc.numPages;
renderPage(pageNum);
});
Настройка интерфейса и стилей
Даже используя готовый Viewer, вы можете адаптировать его под дизайн своего сайта.
Скрытие элементов панели инструментов
Если вам не нужны кнопки печати или скачивания, их можно скрыть через CSS. В стандартном viewer элементы имеют определенные классы или ID.
/* Скрыть кнопку печати */
#print { display: none !important; }
/* Скрыть кнопку скачивания */
#download { display: none !important; }
/* Скрыть боковую панель с миниатюрами */
#sidebarContainer { display: none !important; }
Осторожно с безопасностью: Скрытие кнопок через CSS не запрещает пользователю скачать файл. Файл все равно загружается в браузер. Для реальной защиты от скачивания необходимы серверные ограничения (DRM, водяные знаки, отдача файла потоком с запретом кэширования).
Темная тема и адаптивность
PDF.js использует CSS-переменные. Вы можете переопределить их для поддержки темной темы:
:root {
--body-bg-color: #1e1e1e;
--toolbar-bg-color: #2d2d2d;
--text-color: #ffffff;
}
/* Адаптация канваса под мобильные устройства */
#the-canvas {
max-width: 100%;
height: auto;
}
Для мобильных устройств убедитесь, что контейнер просмотрщика имеет правильные мета-теги viewport и поддерживает жесты масштабирования (pinch-to-zoom), если вы не реализовали свои кнопки зума.
Оптимизация производительности
Работа с большими PDF-файлами может замедлить работу браузера. Вот как этого избежать:
- Используйте Web Worker: Никогда не запускайте рендеринг в основном потоке. Всегда указывайте
workerSrc. Это предотвратит «зависание» интерфейса при обработке сложных документов. - Ленивая загрузка (Lazy Loading): Не рендерьте все страницы сразу. Загружайте и отрисовывайте только текущую страницу и, опционально, соседние (предзагрузка). В примере выше используется именно этот подход.
- Кэширование: Если пользователь часто обращается к одним и тем же документам, настройте HTTP-кэширование на сервере для
.pdfфайлов и скриптов библиотеки. - Сжатие PDF: Перед загрузкой на сервер оптимизируйте сами PDF-файлы (удалите встроенные шрифты, сожмите изображения). Это уменьшит время первоначальной загрузки.
Частые ошибки при интеграции
| Ошибка | Причина | Решение |
|---|---|---|
Setting up fake worker warning | Не указан путь к workerSrc или он недоступен | Явно укажите pdfjsLib.GlobalWorkerOptions.workerSrc на файл pdf.worker.min.mjs той же версии, что и основная библиотека. |
| Текст не копируется / не ищется | PDF состоит из сканов (картинок), а не текстового слоя | PDF.js не делает OCR автоматически. Используйте серверные инструменты (Tesseract, Adobe API) для распознавания текста перед отдачей файла. |
| Размытый текст при зуме | Неправильный расчет viewport | При изменении масштаба всегда пересчитывайте viewport через page.getViewport({scale: newScale}) и перерисовывайте канвас. |
| Ошибка CORS | Файл загружается с другого домена | Настройте заголовки Access-Control-Allow-Origin на сервере, где лежит PDF, или используйте прокси на своем бэкенде. |
FAQ
Можно ли использовать PDF.js с React/Vue/Angular?
Да. Для React популярны обертки вроде react-pdf, которые упрощают работу с хуками и состоянием. Однако они всё равно используют PDF.js под капотом. Для Vue есть vue-pdf-embed. Если нужна максимальная гибкость, лучше использовать нативный API PDF.js внутри useEffect (React) или onMounted (Vue).
Как защитить PDF от копирования? Технически, если файл открыт в браузере, пользователь может его сохранить. PDF.js позволяет отключить контекстное меню и кнопки интерфейса, но это не защита. Для серьезной защиты используйте водяные знаки с данными пользователя, динамическую генерацию PDF на лету или стриминг фрагментов файла.
Поддерживает ли библиотека формы и аннотации? Да, современные версии PDF.js поддерживают отображение интерактивных форм (AcroForms) и некоторых типов аннотаций. Однако редактирование форм может работать нестабильно в зависимости от сложности документа. Для сложных форм лучше тестировать конкретно ваш тип файлов.
Какой размер библиотеки?
Минифицированная версия pdf.min.js весит около 100–150 КБ, а воркер pdf.worker.min.mjs — около 1 МБ. Рекомендуется загружать их асинхронно или использовать code-splitting, чтобы не увеличивать время первичной загрузки страницы.