如何创建pdf的buffer,让pdf.js实现预览pdf文件

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何创建pdf的buffer,让pdf.js实现预览pdf文件相关的知识,希望对你有一定的参考价值。

pdf.js简介

PDF.js 是基于开放的 html5 及 javascript 技术实现的开源产品。简单说就是一个 PDF
解析器。运用HTML5JavaScript(即pdf.js仅使用安全的web语言,不包含任何攻击者可以用的本地代码块)的PDF阅读器pdf.js,直接在标准的HTML页面上载入和渲染PDF文件, 还可以提高安全性(不需要安装第三方插件,安全性由浏览器保证),浏览器所做的安全措施已经为pdf.js提供了安全的运行环境。其对IE和 FireFox浏览器的要求是IE9+, FireFox19+。

在线示例: http://jsbin.com/pdfjs-helloworld-v2/1/edit
, http://jsbin.com/pdfjs-prevnext-v2/1/edit

源码:https://github.com/mozilla/pdf.js

官网:http://mozilla.github.io/pdf.js/

pdf.js VS 传统浏览器读取pdf

一般来说,PDF档案格式都是在浏览器中由外挂程式来描绘,通常是Adobe自己的PDF
reader或来自其他供应商的描绘工具,但这些外挂通常无法充分运用PDF的特点,而且由于含有大量的受信任代码,使得Google
Chrome浏览器必须运用SandBox沙箱原理,来检查PDF描绘工具是否遭到未知病毒感染。

使用adobe,必须在本地安装软件才能使用,而pdf.js不依赖环境、渲染速度快(测试过,确实很快)、安全性高。

pdf.js渲染PDF文件

pdf.js渲染PDF文件的流程:Fetch pdf (url / buffer) ——> canvas ——> 渲染

如果要深入pdf的渲染,需要去研究pdf.js源代码。pdf.js可通过pdf文件的地址或pdf数据流获取pdf,具体实现是调用接口函数 PDFJs.getDoc(url/buffer)将pdf载入html,通过canvas处理, 然后渲染pdf文件。网上给出的都是通过url来获取pdf的例子,而我在做项目的时候,后台(Python)要求是发pdf的数据流给前台,前台接收pdf的buffer,然后通过pdf.js来渲染。当然最初尝试buffer出现了很多问题,具体问题总结如下:

1)如何通过$.ajax接收后台发给前台的buffer数据;

2)如何将buffer传给pdf.js来处理(这里我使用了viewer.js, 所以需要考虑的是如何将buffer传给viewer.js来处理);

3)如何将pdf.js转换成pdf.js可以接收的buffer格式;

(对应问题解决见代码注释)

注:viewer.js是pdf.js的扩展,其将打印、翻页、缩放等功能进行了实现,且界面非常好看。也就是说如果你引入了viewer.js,pdf的渲染和渲染之后的功能界面都已经帮你实现了,你不用自己去写界面。

先从官网:http://mozilla.github.io/pdf.js/ 下载代码,然后使用文件viewer.html
, 我的html就是在viewer.html 的基础上修改的,下面我给出buffer的例子:

<!DOCTYPE html>
<html dir="ltr" mozdisallowselectionprint moznomarginboxes>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, maximum-scale=1">
<meta name="google" content="notranslate">
<title>在线预览</title>
% load static %% get_static_prefix as STATIC_URL %
<link href="STATIC_URLcss/preview.css" rel="stylesheet" type="text/css" />
<link rel="stylesheet" href="STATIC_URLpdfjs/web/viewer.css"/>
<script type="text/javascript" src="STATIC_URLpdfjs/web/compatibility.js"></script>
<link rel="resource" type="application/l10n" href="STATIC_URLpdfjs/web/locale/locale.properties"/>
<script type="text/javascript" src="STATIC_URLpdfjs/web/l10n.js"></script>
<script type="text/javascript" src="STATIC_URLpdfjs/build/pdf.js"></script>
<script type="text/javascript" src="STATIC_URLpdfjs/web/debugger.js"></script>
<script src="STATIC_URLjs/jquery-1.8.3.js" type="text/javascript"></script>
<script type="text/javascript">

//convertDataURIToBinary()

//不知道什么原因如果后台直接将pdf的数据流发给前台,得到的是乱码,将数据转换成 Uint8Array始终不成功

//所以就让后台将发送之前的数据流做 了base64编码发给前台,前台再解码得到的数据就不是乱码了。

var BASE64_MARKER = \';base64,\';

var preFileId = mark;

//viewer.js全局变量,传入buffer,回答问题2
var DEFAULT_URL

$(document).ready(function()
$.ajax(
type:"post",
async: false,

//ajax接收pdf数据流,注意dataType值的设置是否有错,如果不指定,jQuery将自动根据HTTP包MIME信息返回

//responseXML或responseText
. 回答问题1
contentType:"application/pdf;charset=utf-8",
url:"% url netPan.File.views.browserFuf%",
data:
id: preFileId
,
success:function(data)
var pdfAsDataUri = data;

//如果引入了viewer.js , 处理方法
var pdfAsArray = convertDataURIToBinary(pdfAsDataUri);
DEFAULT_URL = pdfAsArray;

// 只引入了pdf.js, 未引入viewer.js, 处理方法

// var pdfAsArray = convertDataURIToBinary(pdfAsDataUri);

// PDFJS.getDocument(pdfAsArray).then(); 自己写pdf的处理函数


);
);

function convertDataURIToBinary(dataURI) //编码转换,回答问题3

var base64Index = dataURI.indexOf(BASE64_MARKER) + BASE64_MARKER.length;
var base64 = dataURI.substring(base64Index);
var raw = window.atob(base64);
var rawLength = raw.length;

//转换成pdf.js能直接解析的Uint8Array类型,见pdf.js-4068
var array = new Uint8Array(new ArrayBuffer(rawLength));

for(i = 0; i < rawLength; i++)
array[i] = raw.charCodeAt(i);

return array;

</script>

<!--先设置全局变量DEFAULT_URL 的值,所以要后调入viewer.js -->
<script type="text/javascript" src="STATIC_URLpdfjs/web/viewer.js"></script>
</head>

<body>

省略内容

</body>

</html>
参考技术A pdf文静在buffer打不开,没有打印机是不能在这里打开的,楼主试试迅捷pdf虚拟打印机看看能不能将pdf文件在这里打开,要是不能打开也是不能勉强的,不过这个工具是确实蛮好的

pdf.js实现文字可复制并且选取文字背景不一致,修改选取文字背景

参考技术A 一、安装和引入pdf.js包。(这里不再做过多的赘述)

二、渲染pdf,同事添加div,进行用来存储文字,保证文字可以被选取复制。

通过input标签获取到数据文件,然后通过getPDF()方法进行渲染。

renderPDF()方法

至此,其实已经实现了pdf文字可复制的要求。但是,由于各个div里的文字宽度和高度的不同,导致选取文字的时候,选取的背景颜色不同统一,需要进行统一背景样式。

思路:渲染完成pdf以后,监听页面的鼠标按下事件和鼠标弹起事件。当用户选取文字完成以后,获取选取文字的长度和宽度,获取选取文字距离上边框和右边框的值。通过获取的值来创建div并设置长度宽度以及背景颜色,对文字进行遮罩,最后取消用户选择的文字。

1、首先确认鼠标点击相对文档的开始位置:

2、确认用户选取的文字是从哪开始,在哪结束。

3、最后通过applyColours()进行渲染。

applyColours()判断了很多种情况,当用户值选择了一行的情况,当渲染的文字有还行递归调用回来的等多种情况。同事判断是否换行是通过第一个节点与第二个节点的top值绝对值是否大于10,大于10就表示换行。同时,节点后面两个节点如果就调用另外一个渲染方法。

otherMothodload()方法:

至此,任务完成。

效果入下图:

未优化前:

优化后:

这种方法虽然实现背景的渲染,但是存在几个问题:

1、渲染第一行文字的位置是通过鼠标按下的位置来确定的,但是当用户鼠标按下的位置与选取的文字的位置偏差较大,会导致渲染的div与选取的文字位置有偏差。如下图:

2、选取文字的长度和宽度是通过获取文字的内容,文字的size,以及文字的字体。再页面中创建一个span标签,然后把文字带进document里,获取到宽度和高度。这种方法有些文字渲染出来的长度太长。如下图:

附上获取长度和宽度的方法:

以上两个问题,希望有大神给我一点思路和解决方案。欢迎小伙伴跟我一起讨论。

附上项目github:https://github.com/caohelen/pdfjs

以上是关于如何创建pdf的buffer,让pdf.js实现预览pdf文件的主要内容,如果未能解决你的问题,请参考以下文章

如何让 TypeScript 以生成工作 Node.JS 代码的方式加载 PDF.js NPM 模块和 @types 绑定?

PDF.js 如何取到PDF的目录页码

pdf.js实现文字可复制并且选取文字背景不一致,修改选取文字背景

如何将pdf.js嵌入fancybox

如何使用 PDF.JS 显示整个 PDF(不仅仅是一页)?

如何在网页中显示PDF文件