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?