前端使用vue-pdf、pdf-lib 给pdf添加水印,并预览与下载
效果预览
使用第三方插件
安装依赖插件
npm i vue-pdf --save
npm i pdf-lib --save
npm install --save @pdf-lib/fontkit //为 pdf-lib 加载自定义字体的工具
import 导入依赖
import pdf from"vue-pdf";import{ degrees, PDFDocument, rgb, StandardFonts }from"pdf-lib";import fontkit from"@pdf-lib/fontkit";
预览添加水印的pdf
setWatermarkContent(){let ele = document.createElement("canvas");
ele.width =250;
ele.height =200;let objmsg ={canvas: ele,fontText:"张三-2023-01-01",fontSize:20,fontFamily:"microsoft yahei",fontcolor:"#dadbdc",//字体颜色 默认 #dadbdcrotate:25,//旋转角度 数字类型textAlign:"left",//水印文字居中方式:left center right 默认 left};this.createWaterMark(objmsg);this.drawWaterMark(ele);},// 创建canvas水印图片createWaterMark({ canvas, fontText, fontFamily ="microsoft yahei", fontSize =30, fontcolor ="#dadbdc", rotate =30, textAlign ="left"}){let ctx = canvas.getContext("2d");
ctx.font =`${fontSize}px ${fontFamily}`;
ctx.rotate((-rotate * Math.PI)/180);
ctx.fillStyle = fontcolor;
ctx.textAlign = textAlign;
ctx.textBaseline ="Middle";
ctx.fillText(fontText, canvas.width /6, canvas.height /2);},// 给pdf增加水印遮罩层drawWaterMark(ele){let div = document.createElement("div");
div.style.pointerEvents ="none";
div.style.top ="0";
div.style.left ="0px";
div.style.position ="absolute";
div.style.background ="url("+ ele.toDataURL("image/png")+") left top repeat";let width = document.getElementById("pdfBox").clientWidth ||700;let height = document.getElementById("pdfBox").clientHeight ||700;
div.style.width = width +"px";
div.style.height = height +"px";
document.getElementById("myIframe").appendChild(div);},
下载添加水印的pdf
原理就是给显示pdf 的容器增加一层水印遮罩层
// 处理PDFasyncdownFile(){/*2.获取pdf文件的arrarybuffer文件流
可请求后台接口返回的base64文件流,然后转成arrayBuffer类型
可访问前端项目中的本地文件,不能直接访问服务器链接文件,会有跨域问题*/try{// 1.通过url获取pdf文件的arrarybuffer文件流const existingPdfBytes =awaitfetch(this.fileUrl).then((res)=> res.arrayBuffer());// 2.将arraybuffer数据转成pdf文档const pdfDoc =await PDFDocument.load(existingPdfBytes);// 3.1 内置字体(不支持中文), 如果水印中不包含中文可直接用内置字体(不支持中文)// const fontkitFile = await pdfDoc.embedFont(StandardFonts.Helvetica);// 3.2 自定义字体,如不需要使用自定义字体可以将这一段全部注释掉,也不用下载自定义字体文件和自定义字体工具fontkit// 将自己下载好的.ttf文件放置项目中,然后访问文件路径(不支持访问本地文件)const fontBytes =awaitfetch("/fonts/SourceHanSansCN-Normal.ttf").then((res)=> res.arrayBuffer());
pdfDoc.registerFontkit(fontkit);// 自定义字体挂载、fontkit为自定义字体注册工具const fontkitFile =await pdfDoc.embedFont(fontBytes);// 4. 为每页pdf添加文字水印const pages = pdfDoc.getPages();for(let i =0; i < pages.length; i++){const noPage = pages[i];const{ width, height }= noPage.getSize();for(let i =0; i <10; i++){for(let j =0; j <3; j++){
noPage.drawText("张三-2023-01-01",{x:230* j,y:(height /4)* i,size:20,font: fontkitFile,//字体(内置/自定义)color:rgb(0.46,0.53,0.6),rotate:degrees(45),opacity:0.3,});}}}//5. 保存pdf文件的unit64Arrary文件流const pdfBytes =await pdfDoc.save();this.saveByteArray(this.waterFile.fileName +".pdf", pdfBytes);}catch(error){this.$message.warning("文件下载失败!");}},// 下载文件saveByteArray(reportName, byte){var blob =newBlob([byte],{type:"application/pdf"});var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);var fileName = reportName;
link.download = fileName;
link.click();},
预览及下载总结
下载:
- 通过url获取pdf文件的arrarybuffer文件流
- 将arraybuffer数据转成pdf文档
- 添加水印字体(内置/自定义)
- 为每页pdf添加文字水印
- 保存pdf文件的unit64Arrary文件流
预览:
- 创建canvas容器(用于显示水印文字)
- 创建水印canvas
- 将水印canvas遮罩层定位到pdf容器中
完整代码
<template><div><div class="content"><div id="myIframe" style="max-width: 700px; min-height: 550px; position: relative; margin: 0 auto"><pdf id="pdfBox":page="pageNum":src="fileUrl" @progress="loadedRatio = $event" @num-pages="totalPages = $event"></pdf></div><el-button v-if="false" type="primary" @click="downFile" plain style="width: 300px">保存并下载pdf</el-button></div><span slot="footer"class="dialog-footer"><div class="btnGroup" v-if="totalPages"><div class="pageNum">{{ pageNum }}/{{ totalPages }}</div><el-button-group><el-button round plain type="primary" icon="el-icon-arrow-left" size="mini" @click="prePage">上一页</el-button><el-button round plain type="primary" size="mini" @click="nextPage">下一页<i class="el-icon-arrow-right el-icon--right"></i></el-button></el-button-group></div></span></div></template><script>/* npm i vue-pdf --save
npm install --save @pdf-lib/fontkit
npm i pdf-lib --save
*/import pdf from"vue-pdf";import{ degrees, PDFDocument, rgb, StandardFonts }from"pdf-lib";import fontkit from"@pdf-lib/fontkit";//为 pdf-lib 加载自定义字体的工具exportdefault{components:{
pdf,},data(){return{pageNum:1,//显示第一页loadedRatio:0,// 当前页面的加载进度,范围是0-1 ,等于1的时候代表当前页已经完全加载完成了totalPages:0,//pdf总页数fileUrl:"XXXXX.pdf",};},mounted(){this.getPageNum();},methods:{// 获取PDF总页数getPageNum(){let loadingTask = pdf.createLoadingTask(this.fileUrl);
loadingTask.promise
.then((pdf)=>{this.totalPages = pdf.numPages;this.$nextTick(()=>{this.setWatermarkContent();});}).catch((err)=>{this.$message.warning("pdf加载失败");});},// 上一页prePage(){let page =this.pageNum;
page = page >1? page -1:this.totalPages;this.pageNum = page;
window.scrollTo(0,0);},// 下一页nextPage(){let page =this.pageNum;
page = page <this.totalPages ? page +1:1;this.pageNum = page;
window.scrollTo(0,0);},setWatermarkContent(){// 1.创建canvas容器(用于显示水印文字)let ele = document.createElement("canvas");
ele.width =250;
ele.height =200;let objmsg ={canvas: ele,fontText:"张三-2023-01-01",// StringfontSize:20,fontFamily:"microsoft yahei",fontcolor:"#dadbdc",//字体颜色 默认 #dadbdcrotate:25,//旋转角度 数字类型textAlign:"left",//水印文字居中方式:left center right 默认 left};// 2.创建水印canvasthis.createWaterMark(objmsg);// 2.将水印canvas遮罩层定位到pdf容器中this.drawWaterMark(ele);},// 创建canvas水印图片createWaterMark({ canvas, fontText, fontFamily ="microsoft yahei", fontSize =30, fontcolor ="#dadbdc", rotate =30, textAlign ="left"}){let ctx = canvas.getContext("2d");
ctx.font =`${fontSize}px ${fontFamily}`;
ctx.rotate((-rotate * Math.PI)/180);
ctx.fillStyle = fontcolor;
ctx.textAlign = textAlign;
ctx.textBaseline ="Middle";
ctx.fillText(fontText, canvas.width /6, canvas.height /2);},// 给pdf增加水印遮罩层drawWaterMark(ele){let div = document.createElement("div");
div.style.pointerEvents ="none";
div.style.top ="0";
div.style.left ="0px";
div.style.position ="absolute";
div.style.background ="url("+ ele.toDataURL("image/png")+") left top repeat";let width = document.getElementById("pdfBox").clientWidth ||700;let height = document.getElementById("pdfBox").clientHeight ||700;
div.style.width = width +"px";
div.style.height = height +"px";
document.getElementById("myIframe").appendChild(div);},// PDF 下载asyncdownFile(){/*2.获取pdf文件的arrarybuffer文件流
可请求后台接口返回的base64文件流,然后转成arrayBuffer类型
可访问前端项目中的本地文件,不能直接访问服务器链接文件,会有跨域问题*/try{// 1.通过url获取pdf文件的arrarybuffer文件流const existingPdfBytes =awaitfetch(this.fileUrl).then((res)=> res.arrayBuffer());// 2.将arraybuffer数据转成pdf文档const pdfDoc =await PDFDocument.load(existingPdfBytes);// 3.1 内置字体(不支持中文), 如果水印中不包含中文可直接用内置字体(不支持中文)// const fontkitFile = await pdfDoc.embedFont(StandardFonts.Helvetica);// 3.2 自定义字体,如不需要使用自定义字体可以将这一段全部注释掉,也不用下载自定义字体文件和自定义字体工具fontkit// 将自己下载好的.ttf文件放置项目中,然后访问文件路径(不支持访问本地文件)const fontBytes =awaitfetch("/fonts/SourceHanSansCN-Normal.ttf").then((res)=> res.arrayBuffer());
pdfDoc.registerFontkit(fontkit);// 自定义字体挂载、fontkit为自定义字体注册工具const fontkitFile =await pdfDoc.embedFont(fontBytes);// 4. 为每页pdf添加文字水印const pages = pdfDoc.getPages();for(let i =0; i < pages.length; i++){const noPage = pages[i];const{ width, height }= noPage.getSize();for(let i =0; i <10; i++){for(let j =0; j <3; j++){
noPage.drawText('张三-2023-01-01',{x:230* j,y:(height /4)* i,size:20,font: fontkitFile,//字体(内置/自定义)color:rgb(0.46,0.53,0.6),rotate:degrees(45),opacity:0.3,});}}}//5. 保存pdf文件的unit64Arrary文件流const pdfBytes =await pdfDoc.save();this.saveByteArray("水印PDF.pdf", pdfBytes);}catch(error){this.$message.warning("文件下载失败!");}},// 下载文件saveByteArray(fileName, byte){var blob =newBlob([byte],{type:"application/pdf"});var link = document.createElement("a");
link.href = window.URL.createObjectURL(blob);var fileName = reportName;
link.download = fileName;
link.click();},},};</script>
本文转载自: https://blog.csdn.net/qq_37831545/article/details/128865029
版权归原作者 一朵野花压海棠 所有, 如有侵权,请联系我们删除。
版权归原作者 一朵野花压海棠 所有, 如有侵权,请联系我们删除。