mozilla.pdf
本文由Jani Hartikainen , Florian Rappl , Jezen Thomas和Jeff Smith进行同行评审。 感谢所有SitePoint的同行评审员使SitePoint内容达到最佳状态!
当涉及到网络时,几乎每种现代浏览器都支持本地查看PDF文档。 但是,该本地组件不在开发人员的控制范围内。 想象一下,由于您的Web应用程序中存在一些业务规则,您想要禁用“ Print
按钮,或者只显示很少的页面,而其他页面则需要付费会员资格。 您可以通过使用embed
标签来使用浏览器的本机PDF呈现功能,但是由于您没有编程访问权限,因此无法控制呈现阶段来满足您的需求。
幸运的是,现在存在由Mozilla Labs创建的PDF.js这样的工具,该工具可以在浏览器中呈现PDF文档。 最重要的是,您作为开发人员可以完全根据您的要求渲染PDF文档的页面。 这不是很酷吗? 是的!
让我们看看PDF.js到底是什么。
什么是PDF.js
PDF.js是基于基于HTML5的技术构建的可移植文档格式(PDF),这意味着它可以在现代浏览器中使用,而无需安装任何第三方插件。
PDF.js已在许多不同地方使用,包括一些在线文件共享服务,如Dropbox , CloudUp和Jumpshare ,使用户可以在线查看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.js
, pdf.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!
mozilla.pdf