React 中使用 pdf.js 将 pdf 转换成图片
pdf.js 主要用于在网页上展示 pdf 文档,是一个用户解析和渲染 pdf 文件的开源库。本文主要介绍如何在 react 中使用 pdf.js 解析 pdf 文件,并最终转换成图片形式。
一、 安装 pdf.js 库文件
要在 react 中使用 pdf.js,首先需要安装对应的依赖。对此 pdf.js 提供了 pdfjs-dist 库,我们可以通过 npm 进行下载.
npm install pdfjs-dist --save
二、 在组件中使用。
在 pdf.js 的 issues 中找到 pdf.js 在 react 中的使用方法,参考 issue:【Using pdf.js in React】
1. 引入 pdf.js 文件
2. 编写文件上传组件
3. 编写上传属性和方法
4. pdf 解析
5. canvas 设置
6. 生成图片
从上面的代码可以看出,由 pdf 生成图片主要需要经历以下几个过程:
上传 pdf 文件 -> 解析 pdf -> 生成 canvas 对象 -> 转换成图片 -> (插入页面或导出文件)
三、在项目中查看效果
导入后查看
完整的 jsx 代码如下:
1 import React from 'react'; 2 import { Modal } from 'antd' 3 import * as PDFJS from "pdfjs-dist"; 4 import pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'; 5 6 const Dragger = Upload.Dragger; 7 8 PDFJS.GlobalWorkerOptions.workerSrc = pdfjsWorker; 9 10 export default class ImportPdf extends React.Component { 11 state = { 12 pdf: '', 13 } 14 15 openPage(pdfFile, pageNumber, context) { 16 var scale = 2; 17 pdfFile.getPage(pageNumber).then(function (page) { 18 // reference canvas via context 19 const viewport = page.getViewport(scale); 20 var canvas = context.canvas; 21 canvas.width = viewport.width; 22 canvas.height = viewport.height; 23 canvas.style.width = "100%"; 24 canvas.style.height = "100%"; 25 var renderContext = { 26 canvasContext: context, 27 viewport: viewport 28 }; 29 page.render(renderContext); 30 }); 31 return; 32 } 33 34 exportImg(self) { 35 // 将 canvas 导出成 img 36 $('#pdf-container canvas').each(function (index, ele) { 37 var canvas = document.getElementById("pageNum" + (index + 1)); 38 // 将 canvas 转成 base64 格式的图片 39 let base64ImgSrc = canvas.toDataURL("image/png") 40 const img = document.createElement("img") 41 img.setAttribute('class', 'pdf-img'); 42 img.src = base64ImgSrc 43 img.style.width = '100%'; 44 // 将图片挂载到 dom 中 45 $('#pdf-container').append(img); 46 }); 47 } 48 49 readPdf(file) { 50 // pdf.js无法直接打开本地文件,所以利用FileReader转换 51 const reader = new FileReader(); 52 reader.readAsArrayBuffer(file); 53 reader.onload = function (e) { 54 const typedarray = new Uint8Array(this.result); 55 const loadingTask = PDFJS.getDocument(typedarray); 56 loadingTask.promise.then(function (pdf) { 57 if (pdf) { 58 // pdf 总页数 59 const pageNum = pdf.numPages; 60 for (let i = 1; i <= pageNum; i++) { 61 // 生成每页 pdf 的 canvas 62 const canvas = document.createElement('canvas'); 63 canvas.id = "pageNum" + i; 64 // 将 canvas 添加到 dom 中 65 $('#pdf-container').append(canvas); 66 const context = canvas.getContext('2d'); 67 self.openPage(pdf, i, context); 68 } 69 setTimeout(() => { 70 self.exportImg(self) 71 }, 1000); 72 } 73 }).catch(function (reason) { 74 console.error("Error: " + reason); 75 }); 76 }; 77 } 78 79 render() { 80 const self = this; 81 const uploadProps = { 82 name: 'file', 83 accept: '.pdf', 84 action: '', 85 onChange(info) { 86 const status = info.file.status; 87 if (status != 'done') { 88 self.setState({ loading: true }); 89 } 90 if (status !== 'uploading') { 91 console.log(info.file, info.fileList); 92 } 93 if (status === 'done') { 94 self.setState({ loading: false }); 95 message.success(`${info.file.name} 导入成功`); 96 // 解析 pdf 文件 97 self.readPdf(info.file.originFileObj); 98 } else if (status === 'error') { 99 console.log(`${info.file.name} 导入失败`); 100 } 101 }, 102 }; 103 return ( 104 <Modal 105 title="导入pdf" 106 width={480} 107 className="import-pdf-modal" 108 footer={null} 109 > 110 <Spin tip="导入中" spinning={this.state.loading}> 111 <Dragger {...uploadProps} id="document"> 112 <p className="ant-upload-drag-icon"> 113 <Icon type="inbox" /> 114 </p> 115 <p className="ant-upload-text">点击或将文件拖拽到这里上传</p> 116 <p className="ant-upload-hint">支持扩展名:.pdf</p> 117 <div id='pdf-container' style={{ height: 0, overflow: 'hidden' }}></div> 118 </Dragger> 119 </Spin> 120 </Modal> 121 ) 122 } 123 }
【参考】
Is there a pre-built version PDF.js available?