mozilla.pdf_使用Mozilla的PDF.Js在JavaScript中进行自定义PDF渲染

mozilla.pdf

本文由Jani HartikainenFlorian RapplJezen ThomasJeff Smith进行同行评审。 感谢所有SitePoint的同行评审员使SitePoint内容达到最佳状态!

当涉及到网络时,几乎每种现代浏览器都支持本地查看PDF文档。 但是,该本地组件不在开发人员的控制范围内。 想象一下,由于您的Web应用程序中存在一些业务规则,您想要禁用“ Print按钮,或者只显示很少的页面,而其他页面则需要付费会员资格。 您可以通过使用embed标签来使用浏览器的本机PDF呈现功能,但是由于您没有编程访问权限,因此无法控制呈现阶段来满足您的需求。

幸运的是,现在存在由Mozilla Labs创建的PDF.js这样的工具,该工具可以在浏览器中呈现PDF文档。 最重要的是,您作为开发人员可以完全根据您的要求渲染PDF文档的页面。 这不是很酷吗? 是的!

让我们看看PDF.js到底是什么。

什么是PDF.js

PDF.js是基于基于HTML5的技术构建的可移植文档格式(PDF),这意味着它可以在现代浏览器中使用,而无需安装任何第三方插件。

PDF.js已在许多不同地方使用,包括一些在线文件共享服务,如DropboxCloudUpJumpshare ,使用户可以在线查看PDF文档,而无需依赖浏览器的本机PDF呈现功能。

毫无疑问,PDF.js是Web应用程序中具有的出色且必不可少的工具,但是集成它并不像看起来那样简单。 关于如何集成某些功能(如渲染文本层或注释(外部/内部链接)以及支持受密码保护的文件)的文档很少甚至没有。

在本文中,我们将探索PDF.js,并研究如何集成不同的功能。 我们将涉及的一些主题是:

  • 基本整合
  • 使用SVG渲染
  • 渲染文字层
  • 放大/缩小

基本整合

下载所需文件

顾名思义,PDF.js是一个JavaScript库,可在浏览器中使用它来呈现PDF文档。 第一步是获取PDF.js正常运行所需的必要JavaScript文件。 以下是PDF.js所需的两个主要文件:

  • pdf.js
  • pdf.worker.js

要获取上述文件,如果您是Node.js用户,则可以按照GitHub存储库中所述的步骤进行操作。 使用gulp generic命令完成操作后,您将拥有那些必需的文件。

如果像我一样,您对Node.js感到不舒服,那么有一种更简单的方法。 您可以使用以下URL下载必要的文件:

上面提到的URL指向Mozilla的PDF.js 实时演示 。 通过这种方式下载文件,您将始终拥有该库的最新版本。

网络工作者和PDF.js

您下载的两个文件包含获取,解析和呈现PDF文档的方法。 pdf.js是主要的库,它实质上具有从某些URL提取PDF文档的方法。 但是,解析和呈现PDF不是一件容易的事。 实际上,根据PDF的性质,解析和渲染阶段可能需要更长的时间,这可能会导致其他JavaScript函数的阻塞。

HTML5引入了Web Workers ,用于在与浏览器JavaScript线程不同的线程中运行代码。 PDF.js在很大程度上依赖于Web Workers,可以通过将CPU繁重的操作(例如解析和渲染)从主线程中移出来提高性能。 在Web Workers中运行处理昂贵的代码是PDF.js中的默认设置,但必要时可以将其关闭。

PDF.js中的承诺

PDF.jsJavaScript API非常优雅且易于使用,并且很大程度上基于Promises 。 每次对API的调用都会返回一个Promise,该Promise允许干净地处理异步操作。

你好,世界!

让我们集成一个简单的“ Hello World!” PDF文件。 可在http://mozilla.github.io/pdf.js/examples/learning/helloworld.pdf中找到我们在此示例中使用的文档。

在本地网络服务器下创建一个项目,以便可以使用http://localhost/pdfjs_learning/index.html对其进行访问。 PDF.js进行Ajax调用以分块获取文档,因此,为了使Ajax调用在本地工作,我们需要将PDF.js文件放置在本地Web服务器中。 在本地Web服务器上创建pdfjs_learning文件夹后,将文件( pdf.jspdf.worker.js )放在上面下载的文件中。 将以下代码放在index.html

<!DOCTYPE html>
<html>
  <head>
    <title>PDF.js Learning</title>
  </head>
  <body>
    <script type="text/javascript" src="pdf.js"></script>
  </body>
</html>

如您所见,我们提供了指向主库文件pdf.js 。 PDF.js自动检测您的浏览器是否支持Web Workers,如果支持,它将尝试从与pdf.worker.js相同的位置加载pdf.js 。 如果文件在另一个位置,则可以在包含主库之后立即使用PDFJS.workerSrc属性对其进行配置:

<script type="text/javascript" src="pdf.js"></script>
<script type="text/javascript">
    PDFJS.workerSrc = "/path/to/pdf.worker.js";
</script>

如果您的浏览器不支持Web Workers,则无需担心,因为pdf.js包含在不使用Web Workers的情况下解析和呈现PDF文档所需的所有代码,但是取决于您的PDF文档,它可能会中止您的主要JavaScript执行线程。

免费学习PHP!

全面介绍PHP和MySQL,从而实现服务器端编程的飞跃。

原价$ 11.95 您的完全免费

让我们编写一些代码来渲染“ Hello World!”。 PDF文件。 将下面的代码在script标签,下面pdf.js标签。

// URL of PDF document
var url = "http://mozilla.github.io/pdf.js/examples/learning/helloworld.pdf";

// Asynchronous download PDF
PDFJS.getDocument(url)
  .then(function(pdf) {
    return pdf.getPage(1);
  })
  .then(function(page) {
    // Set scale (zoom) level
    var scale = 1.5;

    // Get viewport (dimensions)
    var viewport = page.getViewport(scale);

    // Get canvas#the-canvas
    var canvas = document.getElementById('the-canvas');

    // Fetch canvas' 2d context
    var context = canvas.getContext('2d');

    // Set dimensions to Canvas
    canvas.height = viewport.height;
    canvas.width = viewport.width;

    // Prepare object needed by render method
    var renderContext = {
      canvasContext: context,
      viewport: viewport
    };

    // Render PDF page
    page.render(renderContext);
  });

现在创建一个<canvas>元素,其body标签内的ID为the-canvas

<canvas id="the-canvas"></canvas>

创建<canvas>元素后,刷新浏览器,如果将所有内容放置在正确的位置,则应该看到Hello,world! 打印在您的浏览器中。 但这不是一个普通的Hello,世界!您好,世界! 您看到的基本上是使用JavaScript代码在浏览器中呈现的整个PDF文档。 拥抱真棒!

让我们讨论上述代码的不同部分,这些部分使PDF文档的呈现成为可能。

PDFJS是在浏览器中包含pdf.js文件时获得的全局对象。 该对象是基础对象,包含各种方法。

PDFJS.getDocument()是主要入口点,所有其他操作都在其中执行。 它用于异步获取PDF文档,发送多个Ajax请求以块的形式下载文档,这不仅快速而且高效。 可以将不同的参数传递给此方法,但最重要的参数是指向PDF文档的URL。

PDFJS.getDocument()返回一个Promise,该Promise可用于放置将在PDF.js完成获取文档后执行的代码。 Promise的成功回调将传递一个对象,该对象包含有关获取的PDF文档的信息。 在我们的示例中,此参数名为pdf

您可能想知道,由于PDF文档是分块获取的,因此对于大文件来说,成功回调仅在延迟几秒钟(甚至几分钟)后才被调用。 实际上,一旦获取了第一页的必要字节,就会触发回调。

pdf.getPage()用于获取PDF文档中的各个页面。 当您提供有效的页码时, getPage()返回一个promise,当解决该问题时,将为我们提供一个代表所请求页面的page对象。 pdf对象还具有numPages属性,可用于获取PDF文档中的总页数。

scale是我们希望PDF文档页面呈现的缩放级别。

page.getViewport()返回提供的缩放级别的PDF文档的页面尺寸。

page.render()需要具有不同键/值对的对象才能将PDF页面呈现到画布上。 在我们的示例中,我们传递了从page.getViewport方法获得的Canvas元素的2d上下文和viewport对象。

使用SVG渲染

PDF.js支持两种渲染模式。 它是默认的流行渲染模式是基于Canvas的。 但是,它也允许您使用SVG呈现PDF文档。 让我们渲染Hello World! SVG中先前示例的PDF文档。

使用以下代码更新pdf.getPage()成功回调,以查看PDF.js的SVG渲染的实际效果。

.then(function(page) {

  // Set scale (zoom) level
  var scale = 1.5;

  // Get viewport (dimensions)
  var viewport = page.getViewport(scale);

  // Get div#the-svg
  var container = document.getElementById('the-svg');

  // Set dimensions
  container.style.width = viewport.width + 'px';
  container.style.height = viewport.height + 'px';

  // SVG rendering by PDF.js
  page.getOperatorList()
    .then(function (opList) {
      var svgGfx = new PDFJS.SVGGraphics(page.commonObjs, page.objs);
      return svgGfx.getSVG(opList, viewport);
    })
    .then(function (svg) {
      container.appendChild(svg);
    });

});

<div id="the-svg"></div>替换body标记中的<canvas>元素,然后刷新浏览器。

如果您正确放置了代码,您将看到世界,您好! 被渲染,但是这次使用的是SVG而不是Canvas。 继续并检查页面HTML,您将看到使用标准SVG组件完成了整个渲染。

如您所见,PDF.js并不限制您使用单一呈现机制。 您可以根据需要使用Canvas或SVG渲染。 对于本文的其余部分,我们将使用基于Canvas的渲染。

渲染文字层

PDF.js使您能够在使用Canvas渲染的PDF页面上渲染文本层。 为此,我们需要从PDF.js GitHub的存储库中获取另一个JavaScript文件。 继续并下载text_layer_builder.js插件 。 我们还需要获取其相应CSS文件text_layer_builder.css 。 下载两个文件,并将它们放置在本地服务器上的pdfjs_learning文件夹中。

在开始实际的文本层渲染之前,我们先获得一个内容比“ Hello World!”更多的PDF文档。 例。 我们将要呈现的文档再次取自Mozilla的现场演示, 在此处

由于该文档包含多个页面,因此我们需要稍微调整一下代码。 首先,删除我们在上一个示例中创建的<div>标记,并将其替换为:

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

此容器将用于保存多页PDF文档。 放置以Canvas元素呈现的页面的结构非常简单。 在div#container中,PDF的每个页面都有其自己的<div><div>id属性的格式为page-#{pdf_page_number} 。 例如,PDF文档的第一页将具有id属性设置为page-1<div> ,而第12页将具有page-12 。 在每个这些page-#{pdf_page_number} div内,将有一个Canvas元素。

让我们用以下代码替换getDocument()的成功回调。 不要忘记使用http://mozilla.github.io/pdf.js/web/compressed.tracemonkey-pldi-09.pdf (或您选择的其他一些在线PDF文档)更新url变量。

PDFJS.getDocument(url)
  .then(function(pdf) {

    // Get div#container and cache it for later use
    var container = document.getElementById("container");

    // Loop from 1 to total_number_of_pages in PDF document
    for (var i = 1; i <= pdf.numPages; i++) {

        // Get desired page
        pdf.getPage(i).then(function(page) {

          var scale = 1.5;
          var viewport = page.getViewport(scale);
          var div = document.createElement("div");

          // Set id attribute with page-#{pdf_page_number} format
          div.setAttribute("id", "page-" + (page.pageIndex + 1));

          // This will keep positions of child elements as per our needs
          div.setAttribute("style", "position: relative");

          // Append div within div#container
          container.appendChild(div);

          // Create a new Canvas element
          var canvas = document.createElement("canvas");

          // Append Canvas within div#page-#{pdf_page_number}
          div.appendChild(canvas);

          var context = canvas.getContext('2d');
          canvas.height = viewport.height;
          canvas.width = viewport.width;

          var renderContext = {
            canvasContext: context,
            viewport: viewport
          };

          // Render PDF page
          page.render(renderContext);
        });
    }
});

刷新浏览器并等待几秒钟(在后台提取新的PDF文档时),文档加载完成后,您应该会在浏览器中看到呈现精美的PDF页面。 现在我们已经看到了如何呈现多个页面,让我们讨论如何呈现文本层。

将以下两行添加到index.html以包括文本层呈现所需的必要文件:

<link type="text/css" href="text_layer_builder.css" rel="stylesheet">
<script type="text/javascript" src="text_layer_builder.js"></script>

PDF.js在多个<div>元素内呈现“画布”上方的文本层,因此最好将所有这些<div>元素包装在一个容器元素中。 用以下代码替换page.render(renderContext)行以查看实际的文本层:

page.render(renderContext)
  .then(function() {
    // Get text-fragments
    return page.getTextContent();
  })
  .then(function(textContent) {
    // Create div which will hold text-fragments
    var textLayerDiv = document.createElement("div");

    // Set it's class to textLayer which have required CSS styles
    textLayerDiv.setAttribute("class", "textLayer");

    // Append newly created div in `div#page-#{pdf_page_number}`
    div.appendChild(textLayerDiv);

    // Create new instance of TextLayerBuilder class
    var textLayer = new TextLayerBuilder({
      textLayerDiv: textLayerDiv, 
      pageIndex: page.pageIndex,
      viewport: viewport
    });

    // Set text-fragments
    textLayer.setTextContent(textContent);

    // Render text-fragments
    textLayer.render();
  });

刷新浏览器,这一次您不仅会看到正在渲染的PDF页面,而且还可以从中选择并复制文本。 PDF.js太酷了!

让我们讨论以上代码片段的一些重要部分。

与PDF.js中的任何其他方法一样, page.render()返回一个promise,当PDF页面成功呈现到屏幕上时,promise将被解析。 我们可以使用成功回调来渲染文本层。

page.getTextContent()是一种返回该特定页面的文本片段的方法。 这也会返回一个Promise,并且成功返回该Promise文本片段表示形式的回调。

TextLayerBuilder是一个类,需要每个页面的pdf.getPage()已有的一些参数。 textLayerDiv参数表示<div> ,它将用作容纳多个<div>的容器,每个<div>表示某些特定的文本片段。

新创建的TextLayerBuilder实例具有两个重要方法: setTextContent() (用于设置page.getTextContent()返回的文本片段page.getTextContent()render() (用于渲染文本层)。

如您所见,我们正在将CSS类textLayer分配给textLayerDiv 。 该类具有可确保文本片段很好地适合Canvas元素顶部的样式,以便用户可以自然方式选择/复制文本。

放大/缩小

使用PDF.js,您还可以控制PDF文档的缩放。 实际上,缩放非常简单,我们只需要更新scale值即可。 使用所需的因子增大或减小scale以更改缩放级别。 这留给读者练习,但是请尝试一下,让我们知道您的评论意见。

结论

PDF.js是一个了不起的工具,它为我们提供了使用JavaScript的灵活替代浏览器本机PDF组件的工具。 该API简单,精确,优雅,可以根据需要使用。 在评论中让我知道您打算如何在下一个项目中使用PDF.js!

翻译自: https://www.sitepoint.com/custom-pdf-rendering/

mozilla.pdf

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值