背景
最近在做一个h5嵌入安卓app的项目,里面有个pdf预览的功能,后端直接返回的pdf链接。一开始我图省事就直接用iframe嵌入了,在pc电脑上显示是没什么问题的,但是在app上打开的时候发现显示不了。最开始我是去找了原生的开发,问了他这个问题,是不是原生可以改一下,毕竟pc可以显示,是不是做下兼容就好了。后面原生给我的答复是:和webview的内核有关,webview的内核 和浏览器的内核不一样。
没办法啦,只能自己想办法,应该把pdf转成图片就可以显示了,冲!
解决过程
说干就干,直接面向百度编程,网上还是很多这种案例的,下面是解决的过程:
1.引入pdfjs
npm install pdfjs-dist --save
2.创建canvas
<canvas ref={canvasRef} width={200} height={100} />
3. 将PDF转为图片显示在canvas上
import { getDocument } from "pdfjs-dist/legacy/build/pdf.mjs";
import { useEffect, useRef } from "react";
import "pdfjs-dist/build/pdf.worker.mjs";
const canvasRef = useRef(null);
useEffect(() => {
if (props.visible) {
const loadingTask = getDocument({
url: props.pdfUrl,
cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.5.207/cmaps/", // 解决字体不全问题
cMapPacked: true,
});
loadingTask.promise
.then(async (pdf) => {
const canvas: any = canvasRef.current;
const context: any = canvas.getContext("2d", {
willReadFrequently: true,
});
// 循环遍历每一页pdf,将其转成图片
for (let i = 1; i <= pdf._pdfInfo.numPages; i++) {
// 获取pdf页
const page = await pdf.getPage(i);
// 获取页的尺寸
const viewport = page.getViewport({ scale: 1 });
// 设置canvas的尺寸
canvas.width = viewport.width;
canvas.height = viewport.height;
// 将pdf页渲染到canvas上
await page.render({
canvasContext: context,
viewport: viewport,
}).promise;
// 将canvas转成图片,并添加到页面上
const img = new Image();
img.src = canvas.toDataURL("image/png");
img.onload = () => {
// 计算图片在画布中的位置和大小,这里简单让图片居中显示
const x = (canvas.width - img.width) / 2;
const y = (canvas.height - img.height) / 2;
// 将图片绘制到 canvas 上
context.drawImage(img, x, y);
};
}
})
.then(
function () {
console.log("# End of Document");
},
function (err) {
console.error("Error: " + err);
}
);
}
}, [props.visible]);
到这里就完成啦!可以看一下效果图片
遇到的问题
在开发的时候也是遇到了一些奇奇怪怪的问题,下面是一些解决方案:
1.因为我是做的h5,所以需要考虑一下显示的美观问题。刚开始图片显示的时候是根据pdf大小去直接展示的,很大一张,很丑。最开始我是常事缩小pdf的大小:page.getViewport({ scale: 0.5}),把scale改成0.5,但是这样实践下来,发现图片被压缩了,很模糊,看不清楚。后面直接用的比较暴力的办法去解决的哈哈哈哈哈哈。
直接更改了canvas的宽高,因为项目里做了px转rem的操作,所以可以实现图片自适应屏幕啦。大佬们有更好的解决办法嘛?
2.遇到过字体不全的报错
最开始是想让后端同学去改一下pdf的字体的,但是不知道咋回事,他改了没生效,没办法,只能继续自己找解决办法了😂。最后解决的办法很简单,就是加了两行代码:
const loadingTask = getDocument({
url: props.pdfUrl,
cMapUrl: "https://cdn.jsdelivr.net/npm/pdfjs-dist@2.5.207/cmaps/", // 解决字体不全问题
cMapPacked: true,
});
以上就是全部过程啦!完结!撒花!🎉
使用了两天,发现cMapUrl的cdn资源链接不是很稳定,会出现字体不现实的问题。后来换成了https://unpkg.com/pdfjs-dist@2.6.347/cmaps/ 这个链接,目前还没发现问题,观察一段时间再说。
编辑于2025-3-17