0


Vue整合pdfjs实现前端拖拽盖章操作

vue整合pdfjs

浏览器是能直接接收pdf文件流的,pdf以iframe的格式嵌入到页面中。以防有需要的朋友,代码示例如下:

/**
      sealPdfApi:接口,参数为data,返回值为pdf文件流;
      */sealPdfApi(data).then(res=>{if(window.navigator && window.navigator.msSaveOrOpenBlob){this.$notify.error({title:"请使用google浏览器"});}else{var blob =newBlob([res],{type:"application/pdf"});this.pdfViewer =URL.createObjectURL(blob);//创建的pdf链接
          window.open(this.pdfViewer);//打开窗口,也可以页面使用iframe,src等于上面的pdf链接}})

使用以上方法需要特别注意的一点就是接口调用时,响应类型必须是blob类型,一般可以在项目的通用接口配置中修改。

    responseType: 'blob'

虽然这样的方法能正确显示pdf,但是对于公司的盖章需求有几个问题。

  • 拖拽盖章,一个pdf可能需要盖多个章
  • 盖章是需要调用后端接口的,接口参数需要每个印章在pdf中的位置 针对上面的需求,我一开始的想法是将想在iframe的外面包一层div,利用印章在div中的位置去获取对应的pdf坐标位置。但是这样另一个问题很难解决,如何在盖完章之后将章保留在页面上。想出来的方法相对来说都比较麻烦,感兴趣的大佬们可以尝试研究一下。

最终决定了一个方案,整合pdfjs,讲pdf用canvas的方式在页面上显示,在canvas的外层包裹一个div,获取印章在div块中的位置,在canvas中使用

ctx.drawImage()

方法来讲印章绘制到pdf中。
以下是整合pdfjs的组件部分代码,项目地址我会放在文章的底部:

exportdefault{name:'Pdf',props:{url:{type: String,default:''},type:{type: String,default:'canvas'},pdfjsDistPath:{type: String,default:'.'}},data(){return{pdfViewer:null,pdfLinkService:null,currentScale:'1.0',//缩放比例loadingTask:null}},methods:{onPagesInit({ source }){
            source.currentScaleValue =this.currentScale
        },asyncpdfLibInit(){let pdfjsLib = window.pdfjsLib;let pdfjsViewer = window.pdfjsViewer
            if(!pdfjsLib ||!pdfjsViewer){try{awaitgetPdfjsDist(this.pdfjsDistPath)this.CMAP_URL=`${this.pdfjsDistPath}/pdf/cmaps/`;// console.log( this.CMAP_URL)
                    pdfjsLib = window.pdfjsLib;
                    pdfjsLib.GlobalWorkerOptions.workerSrc =`${this.pdfjsDistPath}/pdf/build/pdf.worker.js`
                    pdfjsViewer = window.pdfjsViewer
                }catch(error){// console.log(error)// pdfjs文件获取失败return}}const container =this.$refs.container
            const eventBus =newpdfjsViewer.EventBus();// (Optionally) enable hyperlinks within PDF files.const pdfLinkService =newpdfjsViewer.PDFLinkService({eventBus: eventBus,});this.pdfLinkService = pdfLinkService
            const pdfViewer =newpdfjsViewer.PDFViewer({container: container,eventBus: eventBus,linkService: pdfLinkService,renderer:this.type,textLayerMode:0,downloadManager:newpdfjsViewer.DownloadManager({}),enableWebGL:true});this.pdfViewer = pdfViewer
            pdfLinkService.setViewer(pdfViewer);

            eventBus.on("pagesinit",this.onPagesInit);},renderPdf(){if(!this.url){return}// Loading document.if(this.pdfViewer ===null||this.pdfLinkService ===null){return}if(this.loadingTask !==null){this.loadingTask.destroy()this.loadingTask =null}this.loadingTask = window.pdfjsLib.getDocument({cMapUrl:this.CMAP_URL,cMapPacked:true,url:this.url,});returnthis.loadingTask.promise.then((pdfDocument)=>{if(pdfDocument.loadingTask.destroyed ||!this.url){return}this.pdfViewer.setDocument(pdfDocument)this.pdfLinkService.setDocument(pdfDocument,null);this.loadingTask =null}).catch(error=>{
                console.log(error)});}},mounted(){this.pdfLibInit().then(()=>{this.renderPdf()})},watch:{url(){// 如果存在pdfViewer则取消渲染if(this.pdfViewer){this.pdfViewer._cancelRendering()}this.renderPdf()}},render(){return(<div class="pdf-view"><div id="viewerContainer" ref="container"><div id="viewer"class="pdfViewer"/></div></div>)}}

以上代码会将pdf以canvas形式渲染到页面上。
组件调用代码如下:

<pdf:url="pdfUrl":type="'canvas'":pdfjsDistPath="'/static'"ref="pdf"/>

pdfUrl是pdf文件地址,如果后端返回的是文件流类型,就使用上述步骤整合出来的地址。pdfjsDistPath是pdfjs文件放置地址,这里我直接放到了vue项目的 static 中。(附带:该目录下的文件是不会被wabpack处理的,它们会被直接复制到最终的打包目录下面(默认是

dist/static

),且必须使用绝对路径来引用这些文件。任何放在 static 中的文件需要以绝对路径的形式引用:

/static/[filename]

。)

印章拖拽

实现拖拽的要素就是让图片脱离文档流。我将图片跟pdf组件放在同一个div下,给div的position设置relative,再给印章图片的position设置为absolute。

接下来要实现的是鼠标在移入pdf中时,印章出现,并且位置随着鼠标移动。给外层div加一个mouseMove事件。

move(e){if(this.signUrl !==""){var pdfContainer = document.getElementById("pdf-container");var scrollY = pdfContainer.scrollTop;var moveX = e.clientX - pdfContainer.offsetLeft -200;var moveY = e.clientY - pdfContainer.offsetTop + scrollY;var SignImg = document.getElementById("pdf-sign-img");if(moveX <0){
          SignImg.style.left =0+"px";}elseif(
          moveX >
          document
            .getElementsByClassName("canvasWrapper")[0].getElementsByTagName("canvas")[0].offsetWidth -
            SignImg.offsetWidth +11){
          SignImg.style.left =
            document
              .getElementsByClassName("canvasWrapper")[0].getElementsByTagName("canvas")[0].offsetWidth -
            SignImg.offsetWidth +11+"px";}else{
          SignImg.style.left = moveX +"px";}
        SignImg.style.top = moveY +"px";}},

以上代码中需要注意的是处理鼠标移动的边界问题,确保印章是在pdf所在的第一层div中移动。

盖章

盖章的操作主要在于找到正确的坐标点,然后调用canvas的

drawImage

方法。
这里有一个问题,就是渲染出来的页面,每一页对应一个canvas,首先我们需要计算出盖章位置对应的是页数,然后用查找到对应的dom元素下的canvas。

在这里插入图片描述

查找页数的方法就是目前图章所在的位置除以每一页的高度取整。

            var pageIndex = 0;
            var myCanvas = document
              .getElementsByClassName("canvasWrapper")[0]
              .getElementsByTagName("canvas")[0];
            if (CanvasTop > myCanvas.offsetHeight) {
              //获取当前印章所在页数
              pageIndex = Math.floor(CanvasTop / myCanvas.offsetHeight);
              myCanvas = document
                .getElementsByClassName("canvasWrapper")[pageIndex].getElementsByTagName("canvas")[0];
            }

找到对应的canvas之后,接下来需要计算每个印章在canvas中对应的坐标,x坐标比较容易计算,不管是在每一页都是不变的,

e.clientX - odiv.offsetLeft; 

y坐标需要用图章的纵坐标减去每一页的高度乘页数。

ctx.drawImage(img,CanvasLeft -11,CanvasTop - myCanvas.offsetHeight * pageIndex);

这样的话我们就能将图片画在对应的canvas上面了。
后端需要盖章的坐标时也可以在盖章之后传递,需要注意的是,可能后端的pdf大小跟前端绘制的pdf大小不一致,这个时候就需要比例换算了。具体的话视情况而定,本文主要是提供一个前端盖章的思路。

撤回操作实现

项目需求中,还有一个撤回的操作。这里因为没有比较好的方案,我直接在每次盖章完成之后,使用getImageData方法,将盖章那一页的canvas像素数据存储到数组中。

undo(){if(this.orignCanvas.length >0){var backCanvasInfo =this.orignCanvas[this.orignCanvas.length -1];var canvas = document.getElementsByClassName("canvasWrapper")[backCanvasInfo.pageIndex].getElementsByTagName("canvas")[0];var ctx = canvas.getContext("2d");
        ctx.putImageData(backCanvasInfo.canvansImg,0,0);this.orignCanvas.pop();this.sealInfo.pop();}else{this.$notify.error({title:"撤回到最后一步了"})}},

demo代码已经发布到我的github上,有兴趣的童靴可以看一下,还有许多可以优化的地方跟一些问题,比如浏览器比例或者是电脑显示比例不是百分之百的话,会出现盖章位置错乱的情况,欢迎大佬指点!有问题的同学可以关注交流。

demo链接


本文转载自: https://blog.csdn.net/qq_32521095/article/details/140604542
版权归原作者 给我一杯酒,再给我一支烟 所有, 如有侵权,请联系我们删除。

“Vue整合pdfjs实现前端拖拽盖章操作”的评论:

还没有评论