logo

从零开始使用PDF.js构建PDF阅读器

176
2023年10月30日
如何使用PDF.js库构建一个简单的自定义PDF查看器。PDF.js是Mozilla开发的一个开源PDF查看器库,使用HTML5构建,可以渲染和解析PDF文件。

便携文档格式(PDF)被广泛用于在各种平台上共享文档。PDF之所以受欢迎,是因为它以一种方式保持文档的格式和布局,使得任何操作系统或PDF查看器都不会显示任何修改的迹象。PDF是通过称为PDF查看器的软件工具来显示的,这些工具具有许多与文档交互的功能,如导航、放大和缩小以及跳转到特定页面。

每个PDF查看器都有特定的功能,这限制了新功能的可能性。因此,开发人员可能希望创建自己的PDF查看器软件,以满足其特定的需求和偏好,比如文档分析或数据提取。创建自定义PDF查看器有许多优势,其中一些如下:

  • 定制化 :开发自己的PDF查看器可以让您定制其界面、功能和功能,以满足您特定的需求。
  • 集成 :构建自定义PDF查看器可以让您无缝集成到您的平台或应用程序中,而不会牺牲任何功能。
  • 安全和隐私 :自定义PDF查看器可以让您控制加密和访问控制等安全措施,以确保PDF文件中敏感内容的保密性。

在本文中,您将使用PDF.js库构建一个简单的自定义PDF查看器。PDF.js是Mozilla开发的基于HTML5的开源PDF查看器库,用于呈现和解析PDF文档。

使用PDF.js库开发PDF查看器

在开始之前,您需要选择一个代码编辑器和PDF.js库,可以通过CDN(本教程中使用)连接,也可以从GitHub下载

设置环境

首先,您将设置一个包含HTML、CSS和JavaScript功能的简单网页的Vanilla JS项目。

在文件夹中设置一个名为PDF Viewer 的项目文件夹,并在文件夹中创建以下三个文件:

  1. index.html
  2. styles.css
  3. viewer.js

项目文件夹结构应如下所示:

项目结构

项目结构

为PDF查看器创建用户界面

下一步是创建一个界面来使用PDF查看器。

打开index.html文件,然后输入以下代码并保存:

<!DOCTYPE html>

<html lang="en">

<head>

  <meta charset="UTF-8">

  <meta name="viewport" content="width=device-width, initial-scale=1.0">

  <title>Simple PDF Viewer</title>

  <link rel="stylesheet" href="styles.css">

</head>

<body>

  <h1>Simple PDF Viewer</h1>

  <div id="pdf-container"></div>

  <div id="page-controls">

    <button id="prev-page">Previous</button>

    <span id="page-num">Page 1</span>

    <button id="next-page">Next</button>

    <input type="number" id="go-to-page-input" placeholder="Go to Page">

    <button id="go-to-page-btn">Go</button>

  </div>

  <div>

    <button id="zoom-out">Zoom Out</button>

    <button id="zoom-in">Zoom In</button>

  </div>

  <input type="file" id="file-input" accept=".pdf">

</body>

</html>

上述代码创建了一个简单的界面,包括以下元素:

  • 用于显示PDF文件的容器
  • “上一页”和“下一页”按钮,用于导航PDF文件的页面
  • 用于跳转到PDF文件指定页面编号的输入字段
  • “放大”和“缩小”按钮
  • 用于从用户本地文件资源管理器中选择PDF文件的按钮

除了创建用户界面外,还有两个用于外部JavaScript文件的脚本标签,用于向网页添加功能。

第一个脚本标签https://cdnjs.cloudflare.com/ajax/libs/pdf.js/2.11.338/pdf.min.js是用于呈现PDF文档的PDF.js库的链接。这将把PDF.js库集成到您的项目中。

第二个脚本标签viewer.js是用于实现PDF查看器功能的自定义JavaScript文件的链接。

这样,HTML文件中的代码就结束了。生成的网页应如下所示:

PDF查看器

PDF查看器

使用CSS为界面添加样式

虽然本教程不侧重于为用户界面添加样式,但您可以使其看起来更加美观。将以下代码保存在styles.css中:

/* styles.css */

body {

    display: flex;

    flex-direction: column;

    align-items: center;

    justify-content: center;

    height: 100vh;

    margin: 0;

    font-family: Arial, sans-serif;

  }



  #pdf-container {

    border: 1px solid #ccc;

    overflow: auto;

    width: 80%;

    max-width: 800px;

    height: 70vh;

  }



  .button-group, #zoom-controls, #file-controls {

    display: flex;

    align-items: center;

    margin-top: 10px;

  }



  .button-group button, #zoom-controls button, #file-controls button, #file-controls input[type="file"] {

    margin: 0 5px;

    padding: 5px 10px;

    border: none;

    background-color: #007bff;

    color: #fff;

    cursor: pointer;

    border-radius: 4px;

    font-size: 14px;

    transition: background-color 0.3s ease;

  }



  .button-group button:hover, #zoom-controls button:hover, #file-controls button:hover, #file-controls input[type="file"]:hover {

    background-color: #0056b3;

  }



  #go-to-page-input, #go-to-page-btn {

    margin-left: 5px;

  }

上述代码将元素居中,为显示PDF的空间进行了组织,并对所有按钮和输入字段进行了对齐。

生成的网页现在应如下所示:

带有CSS样式的PDF查看器

带有CSS样式的PDF查看器

使用JavaScript和PDF.js添加功能

现在,您已经使用CSS组织了PDF查看器的界面。最后一步是使用JavaScript和PDF.js库添加功能。

首先,为了向PDF查看器添加功能,您需要将所有相关代码放入名为DOMContentLoaded的事件侦听器中。这样可以确保在HTML文档完全加载后执行JavaScript代码:

document.addEventListener('DOMContentLoaded', function() {

    // 所有代码在此处

});

您还需要通过JavaScript启用与HTML(DOM)元素的交互,例如按钮和输入字段。document.getElementById()函数允许访问文档对象模型(DOM)元素,从而可以为稍后使用的每个元素创建变量:

const pdfContainer = document.getElementById('pdf-container');

const prevPageBtn = document.getElementById('prev-page');

const nextPageBtn = document.getElementById('next-page');

const pageNumSpan = document.getElementById('page-num');

const goToPageInput = document.getElementById('go-to-page-input'); 

const goToPageBtn = document.getElementById('go-to-page-btn'); 

const zoomOutBtn = document.getElementById('zoom-out');

const zoomInBtn = document.getElementById('zoom-in');

const fileInput = document.getElementById('file-input');

然后,您将初始化以下三个变量:pdfDocpageNumscalepdfDoc变量存储加载的PDF文档实例,pageNum变量跟踪当前显示的页面编号,scale变量用于跟踪缩放比例,以实现放大和缩小功能:

let pdfDoc = null;

let pageNum = 1;

let scale = 1.0;

接下来,renderPage()函数呈现加载的PDF文件的特定页面。它获取PDF页面,调整画布尺寸以匹配页面,清除容器,并将页面内容呈现到画布上,从而在容器内有效地显示页面:

async function renderPage(num) {
  const page = await pdfDoc.getPage(num);

  const viewport = page.getViewport({ scale: scale });

  const canvas = document.createElement('canvas');

  const canvasContext = canvas.getContext('2d');


  canvas.height = viewport.height;

  canvas.width = viewport.width;

  pdfContainer.innerHTML = '';

  pdfContainer.appendChild(canvas);

  const renderContext = {

    canvasContext,

    viewport,

  };

  await page.render(renderContext);
}

loadPDF()函数从给定的URL加载PDF文档,使用pdfjsLib.getDocument()方法。然后调用renderPage()来显示初始页面并更新页面计数:

async function loadPDF(url) {
  const loadingTask = pdfjsLib.getDocument(url);

  pdfDoc = await loadingTask.promise;

  renderPage(pageNum);

  pageNumSpan.textContent = `Page ${pageNum} of ${pdfDoc.numPages}`;
}

接下来,您将为多个按钮添加点击功能的事件侦听器,例如:

  • prevPageBtnnextPageBtn按钮用于页面导航,同时更新要显示的页面编号
  • goToPageBtn按钮,用于跳转到goToPageInput字段中输入的值(页面编号),以跳转到PDF文件的特定页面
  • zoomOutBtnzoomInBtn按钮,用于放大和缩小显示的页面
prevPageBtn.addEventListener('click', () => {

  if (pageNum > 1) {

    pageNum--;

    renderPage(pageNum);

    pageNumSpan.textContent = `Page ${pageNum} of ${pdfDoc.numPages}`;

  }

});



nextPageBtn.addEventListener('click', () => {

  if (pageNum < pdfDoc.numPages) {

    pageNum++;

    renderPage(pageNum);

    pageNumSpan.textContent = `Page ${pageNum} of ${pdfDoc.numPages}`;

  }

});



goToPageBtn.addEventListener('click', () => { // Event listener for the "Go to Page" button

  const targetPage = parseInt(goToPageInput.value);

  if (targetPage >= 1 && targetPage <= pdfDoc.numPages) {

    pageNum = targetPage;

    renderPage(pageNum);

    pageNumSpan.textContent = `Page ${pageNum} of ${pdfDoc.numPages}`;

  }

});



zoomOutBtn.addEventListener('click', () => {

  if (scale > 0.25) {

    scale -= 0.25;

    renderPage(pageNum);

  }

});



zoomInBtn.addEventListener('click', () => {

  if (scale < 3) {

    scale += 0.25;

    renderPage(pageNum);

  }

});

最后一部分是fileInput侦听器,用于检查change事件以加载和呈现用户从本地文件资源管理器中选择的任何文件:

fileInput.addEventListener('change', async (event) => {

  const selectedFile = event.target.files[0];

  if (selectedFile) {

    const fileURL = URL.createObjectURL(selectedFile);

    loadPDF(fileURL);

  }
});

以下是添加功能的完整代码。打开已创建的viewer.js文件,然后输入以下代码并保存:

document.addEventListener('DOMContentLoaded', function() {

    const pdfContainer = document.getElementById('pdf-container');

    const prevPageBtn = document.getElementById('prev-page');

    const nextPageBtn = document.getElementById('next-page');

    const pageNumSpan = document.getElementById('page-num');

    const goToPageInput = document.getElementById('go-to-page-input'); // Added input element

    const goToPageBtn = document.getElementById('go-to-page-btn'); // Added button element

    const zoomOutBtn = document.getElementById('zoom-out');

    const zoomInBtn = document.getElementById('zoom-in');

    const fileInput = document.getElementById('file-input');

 

    let pdfDoc = null;

    let pageNum = 1;

    let scale = 1.0;

 

    async function renderPage(num) {

      const page = await pdfDoc.getPage(num);

      const viewport = page.getViewport({ scale: scale });

 

      const canvas = document.createElement('canvas');

      const canvasContext = canvas.getContext('2d');

 

      canvas.height = viewport.height;

      canvas.width = viewport.width;

      pdfContainer.innerHTML = '';

      pdfContainer.appendChild(canvas);

 

      const renderContext = {

        canvasContext,

        viewport,

      };

      await page.render(renderContext);

    }

 

    async function loadPDF(url) {

      const loadingTask = pdfjsLib.getDocument(url);

      pdfDoc = await loadingTask.promise;

      renderPage(pageNum);

      pageNumSpan.textContent = `Page ${pageNum} of ${pdfDoc.numPages}`;

    }

 

    prevPageBtn.addEventListener('click', () => {

      if (pageNum > 1) {

        pageNum--;

        renderPage(pageNum);

        pageNumSpan.textContent = `Page ${pageNum} of ${pdfDoc.numPages}`;

      }

    });

 

    nextPageBtn.addEventListener('click', () => {

      if (pageNum < pdfDoc.numPages) {

        pageNum++;

        renderPage(pageNum);

        pageNumSpan.textContent = `Page ${pageNum} of ${pdfDoc.numPages}`;

      }

    });

 

    goToPageBtn.addEventListener('click', () => { // Event listener for the "Go to Page" button

      const targetPage = parseInt(goToPageInput.value);

      if (targetPage >= 1 && targetPage <= pdfDoc.numPages) {

        pageNum = targetPage;

        renderPage(pageNum);

        pageNumSpan.textContent = `Page ${pageNum} of ${pdfDoc.numPages}`;

      }

    });

 

    zoomOutBtn.addEventListener('click', () => {

      if (scale > 0.25) {

        scale -= 0.25;

        renderPage(pageNum);

      }

    });

 

    zoomInBtn.addEventListener('click', () => {

      if (scale < 3) {

        scale += 0.25;

        renderPage(pageNum);

      }

    });

 

    fileInput.addEventListener('change', async (event) => {

      const selectedFile = event.target.files[0];

      if (selectedFile) {

        const fileURL = URL.createObjectURL(selectedFile);

        loadPDF(fileURL);

      }

    });

});

这标志着使用PDF.js开发自定义PDF查看器的开发工作已经完成。

测试PDF查看器

使用PDF.js完成PDF查看器项目后,现在让我们尝试渲染一些PDF并看看它的效果。

如果你渲染一个PDF文件,它会看起来像这样:

PDF查看器测试

PDF查看器测试

放大:

PDF查看器:放大

PDF查看器:放大

缩小:

PDF查看器:缩小

PDF查看器:缩小

下一页:

PDF查看器:下一页

PDF查看器:下一页

上一页:

PDF查看器:上一页

PDF查看器:上一页

结论

在本文中,您了解了如何使用PDF.js库从头开始开发自定义PDF查看器。您可以在这些步骤的基础上构建许多不同版本的PDF查看器,并添加您需要的任何功能。

您可以在这个GitHub存储库中找到本文中使用的所有代码。

本文链接:https://www.iokks.com/art/a1d32299be5e
本博客所有文章除特别声明外,均采用CC BY 4.0 CN协议 许可协议。转载请注明出处!