前言
我正在参加「掘金·启航计划」,最近后端老哥找到我讨论新需求,大致是客户在上传 pdf 文件之后,查看时需要显示缩略图,我心想这不是小case嘛😄,so easy!前端上传 pdf 的时候,后端解析一下,生成一张对应的缩略图不就好了嘛(本着能推则推的友好沟通原则),然而后端老哥告诉我由于各种原因,后端改造起来很麻烦,只能靠前端小老弟来解决了,😮💨愉快的摸鱼日子一去不返.于是我开始上网查资料,CV战士登场!!!
最开始我想的是反正项目里预览 pdf 时用到了pdfjs,那在加载缩略图时也直接用pdfjs展示第一页不就好了,这种方案当然是可行的,但是考虑到有点太浪费资源了,为了显示一张缩略图去请求整个pdf资源.所以最后采用的是在用户上传pdf文件时,利用pdfjs生成一张对应的缩略图,和pdf文件一并上传到服务器,完美搞定.(jym有更好的解决方案请务必告诉我)
下面就是核心代码,项目采用的是antd的Upload组件,我们只需要拦截原本的上传事件,然后利用pdfjs获取第一页的内容,然后利用canvas转成图片就行啦!
需要注意的是,pdfjs里面需要加载cmap文件,否则你生成的图片可能会是乱码或者空白哦.我这里采用的是这个版本"react-pdf": "5.7.2".
const onUploadChange = (e: ISafeAny) => {
const file = e.file;
if (/pdf/g.test(file.type)) {
const url = window.URL.createObjectURL(file);
pdfjs
.getDocument({ url, cMapUrl: `https://cdn.jsdelivr.net/npm/pdfjs-dist@${pdfjs.version}/cmaps/`, cMapPacked: true })
.promise.then((res) => res.getPage(1))
.then((page) => {
const scale = 1.5;
const viewport = page.getViewport({ scale });
const canvas = document.createElement('canvas');
const context = canvas.getContext('2d');
canvas.height = viewport.height;
canvas.width = viewport.width;
const renderContext = {
canvasContext: context!,
viewport: viewport
};
page.render(renderContext).promise.then(() => {
const src = canvas.toDataURL();// 这里是个base64
//后续上传操作......
});
});
return;
}
};
antd Upload使用方法类似这样
<Upload beforeUpload={() => false} maxCount={1} onChange={onUploadChange} fileList={[]} accept='.png, .jpg, .pdf'>
上传
</Upload>
好了,今天的写bug时间就到此为止吧,再写就不礼貌了.