PDF展示与合成Vue组件(lz-pdf-merage)
前言
主要是介绍使用pdfjs和jsPdf在vue组件中对pdf文件进行展示和对原有pdf进行合成(包括文字,图片合成)。
体验
demo地址
npm包引入
1
| npm install lz-pdf-merage
|
pdf展示
主要使用pdfjs(使用的版本是2.1.266)对pdf文件通过对canvas对其进行预览展示,主要原理如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
| import Pdfjs from 'pdfjs-dist'
this.pdf = await Pdfjs.getDocument({ url: pdfPath })
this.pdf.getPage(1)
let canvas = document.getElementById('canvas') let context = canvas.getContext('2d') let scale = 3.2
let viewport = page.getViewport(scale, this.rotate)
canvas.height = viewport.height; canvas.width = viewport.width; canvas.style.width = `${this.width * widthScale}px` canvas.style.height = `${this.width/viewport.width * viewport.height * widthScale}px`; //将pdf数据渲染到指定的canvas上 let renderContext = { canvasContext: context, viewport: viewport }; await page.render(renderContext);
|
需要注意的点:
- 为了解决pdf在canvas上渲染后模糊的问题,需要将pdf通过getViewport(scale,0)方法进行放大。同时设置canvas的style的width和height使其在页面上正常展示。
- 对于对pdf进行放大缩小的功能,pdf本身已经放大了3.2倍了,所以只需要控制canvas的style样式展示(即通过widthScale控制),就可以在页面上呈现放大缩小的效果。
- 旋转功能的实现,一样是通过getViewport(scale, this.rotate)控制。
pdf合成
pdf合成主要是创建一个新的canvas元素,其大小与pdf预览的canvas一致,然后将需要添加的图片和文字记录坐标并添加到新的canvas元素上。最后通过drawImage分别获取到两个canvas对应的图片,通过jsPdf将两张图片合成新的pdf页,从而实现pdf合成。
canvas元素合成
主要代码及解释如下:
1 2
| <canvas class="draw-canvas" ref="drawCanvas"></canvas> <Page ref="page" :defaultRotate="pageRotate" :page="currentPage" :width="pdfWidth - 25" @saveRotate="saveRotate" @drawFinish="handleFinishDraw"></Page>
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
| handleFinishDraw(canvas){ let current = this.current - 1 this.baseCanvasImages[current] = { url: canvas.toDataURL('image/jpeg'), width: canvas.width, height: canvas.height } if (!this.canvasArray[current]) { let { width, height } = canvas.getBoundingClientRect() let drawCanvas = this.setDrawCanvas(canvas) this.canvasArray[current] = new DrawObj(drawCanvas, current, canvas.width/width, canvas.height/height) } this.canvasArray[current].drawItemList() } setDrawCanvas(canvas) { let drawCanvas = this.$refs.drawCanvas drawCanvas.width = canvas.width drawCanvas.height = canvas.height drawCanvas.style.width = canvas.style.width drawCanvas.style.height = canvas.style.height return drawCanvas },
|
pdf合成叠加
主要介绍对pdfjs渲染而成的canvas和drawCanvas通过jsPdf进行合成
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
| async getTheMeragePdf() { const pdf = new jsPDF('p', 'pt', 'a4') let pdfImages = await this.getThePdfImages() for(let i = 0; i< pdfImages.length; i++) { let imageObj = pdfImages[i] pdf.addImage(imageObj.url, 'JPEG', 0,0, 592.28, 592.28/imageObj.width * imageObj.height) if(this.canvasArray[i]) { let drawCanvas = this.canvasArray[i].getDrawCanvas() const drawData = drawCanvas.toDataURL('image/png') pdf.addImage(drawData, 'PNG', 0,0, 592.28, 592.28/drawCanvas.width * drawCanvas.height) } if (i < pdfImages.length - 1) pdf.addPage() } pdf.save('合成的pdf') }\ async getThePdfImages() { let pdfImages = Array(this.total).fill(Infinity) for(let i = 0; i<pdfImages.length; i++) { if(this.baseCanvasImages[i]){ pdfImages[i] = this.baseCanvasImages[i] } else { pdfImages[i] = await this.$refs.page.drawPage(this.pdf.getPage(i+1)) } } return pdfImages },
|
DrawObj
DrawObj是一个自定义的类,它主要实现在canvas中进行添加图片,添加文字,对添加的图片,文字进行移动和删除功能。
对元素的操作都会反映到_drawItemList数组中,每一次操作都会清空画布,然后再重新对_drawItemList里的元素进行重绘,元素操作对_drawItemList数组的修改如下:
- 添加元素时,会向_drawItemList数组中添加一个元素对象(主要包括元素内容,元素类型,元素位置等信息)。
- 删除元素时, 会删除_drawItemList数组中该元素。
- 移动元素时, 会修改_drawItemList数组中对应元素的X,Y。
需要注意的是由于在pdf展示时是对原有canvas进行缩小展示的,所以在调用canvas绘制元素前要调用ctx.scale(this._scaleX, this._scaleY),this._scaleX和this._scaleY在初始化DrawObj时传入:
1 2 3
| this.canvasArray[current] = new DrawObj(drawCanvas, current, canvas.width/ width, canvas.height/height) }
|
pdf打印
pdf打印的原理主要还是pdfjs对canvas进行渲染生成,然后将每一页对应的canvas通过drawImage方法生成图片,再将图片添加到body上,并通过 @media print媒体查询控制打印样式最后调用window.print()打印。具体代码可以看这里
printPdf。