接到一个移动端网页pdf预览的需求,首先想到的方案是利用iframe进行显示。
后端响应头设置
Content-Disposition: inline
Content-Disposition
一般有以下几种情况
// inline 默认值,表示回复中的消息体会以页面的一部分或者整个页面的形式展示
Content-Disposition: inline
// attachment 意味着消息体应该被下载到本地;大多数浏览器会呈现一个“保存为”的对话框
Content-Disposition: attachment
// filename 下载后的文件名
Content-Disposition: attachment; filename="filename.jpg"
按照正常思维,设置之后,应该在iframe里面展示pdf内容。
在PC端模拟器测试时,一切与预期一致。但是到了移动端浏览器,就不同了。
iphone手机 自带的safari、微信、企业微信自带的浏览器都与预期一致。
Android手机(huawei mate9),在企业微信自带浏览器,是新窗口打开了pdf,在微信自带浏览器和手机自带浏览器,都是提示下载。
效果与需求不一致
pdf.js
简介
PDF.js是使用HTML5构建的可移植文档格式(PDF)查看器。PDF.js由社区驱动,并受Mozilla支持。目标是创建一个基于Web标准的通用平台,用于解析和呈现PDF。
pdfjs 在npm仓库提供了一个叫pdfjs-dist包。
引入pfdjs
const PDFJS = require("@/pdfjs-dist");
const workerSrc = require("@/pdfjs-dist/es5/build/pdf.worker.entry.js");
PDFJS.GlobalWorkerOptions.workerSrc = workerSrc;
下载pdf
const CMAP_URL = "https://unpkg.com/pdfjs-dist@2.5.207/cmaps/";
const loadingTask: any = PDFJS.getDocument({
url: this.pdfUrl,
cMapUrl: CMAP_URL,
cMapPacked: true,
withCredentials: true,
});
loadingTask.promise
.then((pdfDoc_) => {
// 拿到pdf可以存起来,用于接下来的展示
})
.catch((error: any) => {
});
获取某一页的内容
this.pdfDoc
.getPage(num)
.then(
(page: any) => {
const viewport = page.getViewport({ scale: 1 });
canvas.height = viewport.height;
canvas.width = viewport.width;
canvas.style.width = "100%";
const renderContext = {
canvasContext,
viewport: viewport,
};
page.render(renderContext);
}
)
.catch((e: any) => {
console.info(e);
});
问题
- pdf展示模糊
在高分辨率屏幕上,pdf可能会显示的不太清晰。
这是canvas 属性上设置的width/height是指物理像素,如果devicePixelRatio
的值为2,那么意味着一个css像素相当于2个物理像素。按照上面的设置,canvas的css宽度值与canvas的物理像素值一致,将会导致canvas画布被放大,展示变得模糊。
于是,根据屏幕的像素比,设置scale的值,使得在不同分辨率的设备,都能得到清晰的体验效果。
- pdf部分字体不显示
引入字体库
const CMAP_URL = "https://unpkg.com/pdfjs-dist@2.5.207/cmaps/"; // 字体库地址
const loadingTask: any = PDFJS.getDocument({
url: this.pdfUrl,
cMapUrl: CMAP_URL,
cMapPacked: true,
withCredentials: true,
});
- 签章不显示
手动修改源码
因为库的作者处于安全考虑,如果是Sig类型,会隐藏,所以,也没法指望作者放开了。只能自己手动。
pdf.worker.js
pdf下载
不同浏览器,依然表现不太一致
在微信里
先展示一个诱导下载QQ浏览器的页面,需要选择【其他方式下载】,多了一步,还好,能实现下载
在企业微信里
下载后直接预览
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。