Статьи

Как создать JavaScript PDF Viewer

Формат Portable Document Format, или сокращенно PDF, идеально подходит для публикации документов, содержащих много точно отформатированного текста и изображений, особенно если они могут быть напечатаны или прочитаны в автономном режиме. Хотя большинство современных браузеров могут отображать файлы PDF, они делают это с помощью средства просмотра PDF, которое запускается на независимой вкладке или в окне, заставляя пользователей покидать ваш веб-сайт.

PDF.js — это библиотека JavaScript с открытым исходным кодом, которая позволяет вам анализировать и отображать файлы PDF прямо на ваших веб-страницах. В этом уроке я покажу вам, как использовать его для создания полноценного пользовательского JavaScript PDF viewer с нуля.

Давайте начнем с создания новой веб-страницы и добавления к ней обычного шаблонного кода HTML5.

01
02
03
04
05
06
07
08
09
10
11
12
<!doctype html>
 
<html lang=»en»>
<head>
  <meta charset=»utf-8″>
  <meta name=»viewport» content=»width=device-width, initial-scale=1″>
  <title>My PDF Viewer</title>
</head>
<body>
     
</body>
</html>

Затем внутри <body> создайте элемент <div> который может служить контейнером для нашего средства просмотра PDF.

1
2
3
<div id=»my_pdf_viewer»>
     
</div>

В основе нашего средства просмотра PDF для JavaScript будет элемент HTML5 <canvas> . Мы будем рендерить страницы наших файлов PDF внутри него. Поэтому добавьте следующий код внутри элемента <div> .

1
2
3
<div id=»canvas_container»>
    <canvas id=»pdf_renderer»></canvas>
</div>

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

1
2
3
4
5
<div id=»navigation_controls»>
    <button id=»go_previous»>Previous</button>
    <input id=»current_page» value=»1″ type=»number»/>
    <button id=»go_next»>Next</button>
</div>

Для поддержки операций масштабирования добавьте в интерфейс еще две кнопки: одну для увеличения и одну для уменьшения.

1
2
3
4
<div id=»zoom_controls»>
    <button id=»zoom_in»>+</button>
    <button id=»zoom_out»>-</button>
</div>

Теперь, когда готовый пользовательский интерфейс для нашего средства просмотра PDF JavaScript готов, давайте добавим PDF.js на нашу веб-страницу. Поскольку последняя версия библиотеки доступна на CDNJS , мы можем сделать это, просто добавив следующие строки в конец веб-страницы.

1
2
3
<script
    src=»https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.0.943/pdf.min.js»>
</script>

Если вы предпочитаете использовать локальную копию библиотеки, вы можете скачать ее из репозитория pdfjs-dist .

Прежде чем мы начнем загружать файл PDF, давайте создадим простой объект JavaScript для хранения состояния нашего средства просмотра PDF. Внутри него будет три элемента: ссылка на сам файл PDF, текущий индекс страницы и текущий уровень масштабирования.

1
2
3
4
5
6
7
8
9
<script>
    var myState = {
        pdf: null,
        currentPage: 1,
        zoom: 1
    }
 
    // more code here
</script>

На этом этапе мы можем загрузить наш файл PDF, вызвав метод getDocument() объекта pdfjsLib , который работает асинхронно.

1
2
3
4
5
pdfjsLib.getDocument(‘./my_document.pdf’).then((pdf) => {
 
    // more code here
 
});

Обратите внимание, что метод getDocument() внутренне использует объект XMLHttpRequest для загрузки файла PDF. Это означает, что файл должен присутствовать либо на вашем веб-сервере, либо на сервере, который разрешает запросы из разных источников.

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

После успешной загрузки PDF-файла мы можем обновить свойство pdf нашего объекта состояния.

1
myState.pdf = pdf;

Наконец, добавьте вызов функции с именем render() чтобы наша программа просмотра PDF автоматически отображала первую страницу файла PDF. Мы определим функцию на следующем шаге.

1
render();

Вызвав метод getPage() объекта pdf и передав ему номер страницы, мы можем получить ссылку на любую страницу в файле PDF. А сейчас давайте передадим ему свойство currentPage нашего объекта состояния. Этот метод также возвращает обещание, поэтому нам понадобится функция обратного вызова для обработки его результата.

Соответственно, создайте новую функцию с именем render() содержащую следующий код:

1
2
3
4
5
6
7
function render() {
    myState.pdf.getPage(myState.currentPage).then((page) => {
 
        // more code here
 
    });
}

Чтобы действительно отобразить страницу, мы должны вызвать метод render() объекта page доступного внутри обратного вызова. В качестве аргументов метод ожидает двухмерный контекст нашего холста и объект PageViewport , который мы можем получить, вызвав метод getViewport() . Поскольку метод getViewport() ожидает желаемый уровень масштабирования в качестве аргумента, мы должны передать ему свойство zoom нашего объекта состояния.

1
2
3
4
var canvas = document.getElementById(«pdf_renderer»);
var ctx = canvas.getContext(‘2d’);
 
var viewport = page.getViewport(myState.zoom);

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

1
2
canvas.width = viewport.width;
canvas.height = viewport.height;

На этом этапе мы можем продолжить и визуализировать страницу.

1
2
3
4
page.render({
    canvasContext: ctx,
    viewport: viewport
});

Если вы попытаетесь открыть веб-страницу в браузере, теперь вы сможете увидеть первую страницу вашего PDF-файла.

Просмотрщик PDF, отображающий первую страницу файла PDF

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

Чтобы это исправить, все, что нам нужно сделать, это задать фиксированную ширину и высоту для элемента <div> инкапсулирующего наш холст, и установить его свойство CSS overflow на auto . Это свойство при необходимости добавляет полосы прокрутки к элементу <div> , позволяя пользователям прокручивать как по горизонтали, так и по вертикали.

Добавьте следующий код в <head> веб-страницы:

1
2
3
4
5
6
7
<style>
    #canvas_container {
        width: 800px;
        height: 450px;
        overflow: auto;
    }
</style>

Вы, конечно, можете изменять ширину и высоту или даже использовать медиа-запросы, чтобы элемент <div> соответствовал вашим требованиям.

При желании вы можете включить следующие правила CSS, чтобы элемент <div> выглядел более отчетливо:

1
2
3
4
5
#canvas_container {
    background: #333;
    text-align: center;
    border: solid 3px;
}

Если вы обновите веб-страницу сейчас, вы должны увидеть что-то вроде этого на вашем экране:

Просмотрщик PDF, отображающий первую страницу файла PDF с прокруткой

Наш JavaScript Viewer в настоящее время способен отображать только первую страницу любого PDF-файла, данного ему. Чтобы позволить пользователям изменять отображаемую страницу, теперь мы должны добавить прослушиватели событий click к go_previous и go_next мы создали ранее.

Внутри прослушивателя go_previous кнопки go_previous мы должны go_previous нашего объекта состояния, убедившись, что оно не падает ниже 1 . После этого мы можем просто снова вызвать функцию render() чтобы отобразить новую страницу.

Кроме того, мы должны обновить значение текстового поля current_page чтобы оно отображало новый номер страницы. Следующий код показывает вам, как:

1
2
3
4
5
6
7
8
9
document.getElementById(‘go_previous’)
       .addEventListener(‘click’, (e) => {
           if(myState.pdf == null
              ||
           myState.currentPage -= 1;
           document.getElementById(«current_page»)
                   .value = myState.currentPage;
           render();
       });

Точно так же внутри слушателя go_next кнопки go_next мы должны go_next , не go_next , чтобы оно превышало количество страниц, присутствующих в файле PDF, которое мы можем определить с numPages свойства _pdfInfo объекта _pdfInfo .

01
02
03
04
05
06
07
08
09
10
11
12
document.getElementById(‘go_next’)
       .addEventListener(‘click’, (e) => {
           if(myState.pdf == null
              ||
                                              ._pdfInfo.numPages)
              return;
        
           myState.currentPage += 1;
           document.getElementById(«current_page»)
                   .value = myState.currentPage;
           render();
       });

Наконец, мы должны добавить прослушиватель событий нажатия клавиши в текстовое поле current_page чтобы пользователи могли напрямую переходить на любую страницу по своему желанию, просто набрав номер страницы и нажав клавишу Enter . Внутри прослушивателя событий нам нужно убедиться, что число, введенное пользователем, больше нуля и меньше или равно numPages .

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
document.getElementById(‘current_page’)
       .addEventListener(‘keypress’, (e) => {
           if(myState.pdf == null) return;
        
           // Get key code
           var code = (e.keyCode ? e.keyCode : e.which);
        
           // If key code matches that of the Enter key
           if(code == 13) {
               var desiredPage =
                       document.getElementById(‘current_page’)
                               .valueAsNumber;
                                
               if(desiredPage >= 1
                  && desiredPage <= myState.pdf
                                           ._pdfInfo.numPages) {
                       myState.currentPage = desiredPage;
                       document.getElementById(«current_page»)
                               .value = desiredPage;
                       render();
               }
           }
       });

Теперь наша программа просмотра PDF может отображать любую страницу файла PDF.

Просмотрщик PDF, отображающий страницу 3 файла PDF

Поскольку наша функция render() уже использует свойство zoom объекта состояния при рендеринге страницы, регулировать уровень масштабирования так же просто, как увеличивать или уменьшать свойство и вызывать функцию.

Внутри слушателя события zoom_in кнопки zoom_in давайте zoom_in свойство zoom на 0.5 .

1
2
3
4
5
6
document.getElementById(‘zoom_in’)
       .addEventListener(‘click’, (e) => {
           if(myState.pdf == null) return;
           myState.zoom += 0.5;
           render();
       });

А внутри слушателя события zoom_out кнопки zoom_out давайте zoom_out свойство zoom на 0.5 .

1
2
3
4
5
6
document.getElementById(‘zoom_out’)
       .addEventListener(‘click’, (e) => {
           if(myState.pdf == null) return;
           myState.zoom -= 0.5;
           render();
       });

Вы можете добавить верхнюю и нижнюю границы в свойство zoom , но они не обязательны.

Наш просмотрщик PDF готов. Если вы обновите веб-страницу снова, вы сможете просматривать все страницы, присутствующие в файле PDF, а также увеличивать или уменьшать их.

Просмотрщик PDF, отображающий страницу с высоким уровнем масштабирования

Теперь вы знаете, как использовать PDF.js для создания пользовательского JavaScript PDF Viewer для вашего сайта. С его помощью вы можете уверенно предлагать удобное взаимодействие с пользователем, демонстрируя брошюры, официальные документы, формы и другие документы своей организации, которые обычно предназначены для распространения в печатном виде.

Вы можете узнать больше о PDF.js на официальном репозитории GitHub .