Vue實(shí)現(xiàn)向PDF文件中添加二維碼
前言
這兩天剛看到一個(gè)需求,簡單描述一下,就是我們拿到一個(gè)pdf文件流(文件流可以是后端返回的,也可以是從自己本地選的)和一個(gè)url鏈接 ,現(xiàn)在要將url鏈接生成二維碼,并將這個(gè)二維碼添加到這個(gè)pdf文件中,然后再預(yù)覽或者下載這個(gè)pdf文件。
靈感出自于我之前寫過一篇Vue使用pdf-lib為文件流添加水印并預(yù)覽,上篇寫的是在pdf上加水印,其中一種方式就是通過圖片的方式添加上去的,所以這次添加二維碼基本差不多一個(gè)意思,我們可以先通過url鏈接生成一個(gè)二維碼,這個(gè)二維碼其實(shí)是個(gè)dom元素的,我們使用html2canvas庫可以將二維碼這個(gè)dom轉(zhuǎn)為一個(gè)canvas對(duì)象,有了canvas是不是可以獲取到Blob對(duì)象了?有了blob就可以獲取到buffer了,那我們就可以將這個(gè)二維碼以圖片的形式嵌入到pdf文件流中。
共用到三個(gè)庫分別是:html2canvas 、qrcodejs2-fixes、pdf-lib。
注意這里生成二維碼共有兩個(gè)庫,一個(gè)是qrcodejs2,這個(gè)由于兼容性問題只支持vue2,我這里的例子是用vue3來演示的,所以就是用第二個(gè):qrcodejs2-fixes,這個(gè)使用跟qrcodejs2一樣,區(qū)別就是一個(gè)適用vue2一個(gè)vue3
安裝
pnpm add html2canvas pnpm add qrcodejs2-fixes pnpm add pdf-lib
引入
import html2canvas from 'html2canvas'
import QRCode from 'qrcodejs2-fixes'
import { degrees, PDFDocument } from 'pdf-lib'封裝
這里單獨(dú)封裝一個(gè)方法,用的時(shí)候直接調(diào)用該方法,將pdf文件流(blob對(duì)象)和二維碼url鏈接地址傳入進(jìn)去 就可以,我這里就以window打開一個(gè)新頁簽預(yù)覽處理之后的pdf為例了,真實(shí)項(xiàng)目也可能是下載,都是差不多的,下載也很簡單,通過a標(biāo)簽,window.URL.createObjectURL轉(zhuǎn)為一個(gè)路徑,然后給a標(biāo)簽增加download屬性,值為文件名稱,click即下載了。這里就沒以下載為例
src/hooks/EmbedQrcodeToPdf.js
import html2canvas from 'html2canvas'
import QRCode from 'qrcodejs2-fixes'
import { degrees, PDFDocument } from 'pdf-lib'
export default function ({ pdfBlob, qrcodeUrl = 'https://www.baidu.com/' }) {
if(!pdfBlob) return
pdfBlob.arrayBuffer().then(async buffer => {
const pdfDoc = await PDFDocument.load(buffer)
const qrcodeDom = document.createElement('div')
qrcodeDom.id = 'wft-qrcode'
document.body.appendChild(qrcodeDom)
new QRCode(document.getElementById('wft-qrcode'), {
text: qrcodeUrl,
width: '128',
height: '128',
colorDark: '#000000',
colorLight: '#ffffff',
correctLevel: QRCode.CorrectLevel.H,
})
html2canvas(document.getElementById('wft-qrcode')).then(canvas => {
canvas.toBlob(qrcodeBlob => {
qrcodeBlob.arrayBuffer().then(async qrcodeBuffer => {
const image = await pdfDoc.embedPng(qrcodeBuffer)
const dims = image.scale(0.6)
const pages = pdfDoc.getPages()
for (let i = 0; i < pages.length; i++) {
let page = pages[i]
const { width, height } = page.getSize()
page.drawImage(image, {
x: width - 100, // 距離右側(cè)100
y: height - 100, // 距離上側(cè)100 就是右上角
width: dims.width,
height: dims.height,
rotate: degrees(0)
})
}
const pdfBytes = await pdfDoc.save()
preView(pdfBytes)
document.body.removeChild(qrcodeDom)
})
}, 'image/png')
})
})
}
// 打開新頁簽預(yù)覽
function preView(stream, docTitle = '測(cè)試PDF') {
const URL = window.URL || window.webkitURL;
const href = URL.createObjectURL(new Blob([stream], { type: 'application/pdf;charset=utf-8' }))
const wo = window.open(href)
// 設(shè)置新打開的頁簽 document title
let timer = setInterval(() => {
if (wo.closed) {
clearInterval(timer)
} else {
wo.document.title = docTitle
}
}, 500)
}封裝的方法中的二維碼樣式啥的,我也懶得動(dòng)態(tài)設(shè)置參數(shù)傳入了,大家有需要在封裝的方法中按需修改即可
引入調(diào)用使用的時(shí)候:
previewEmbedQrcodeToPdf({
pdfBlob: file, // 你的文件流
qrcodeUrl: 'xxxx' // 你的生成二維碼的url鏈接
})使用案例代碼(V3)
<template>
<div class="main">
<input id="fileInp" type="file">
</div>
</template>
<script setup>
import { onMounted, onUnmounted } from 'vue'
import previewEmbedQrcodeToPdf from '../hooks/EmbedQrcodeToPdf'
let cusInp = null
onMounted(() => {
cusInp = document.getElementById('fileInp')
cusInp.addEventListener('input', inpHander)
})
onUnmounted(() => {
cusInp.removeEventListener('input', inpHander)
})
function inpHander(event) {
const file = event.target.files[0]
if(!file) return
previewEmbedQrcodeToPdf({
pdfBlob: file
})
}
</script>
<style scoped>
.main {
width: 100%;
height: 100%;
}
</style>demo效果

右上角這個(gè)二維碼就是我們生成的,添加到這個(gè)pdf中的,我這里是以baidu的鏈接為例的,所以掃出來也是百度的鏈接
到此這篇關(guān)于Vue實(shí)現(xiàn)向PDF文件中添加二維碼的文章就介紹到這了,更多相關(guān)Vue PDF添加二維碼內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
vue-cli和v-charts實(shí)現(xiàn)可視化圖表過程解析
這篇文章主要介紹了vue-cli和v-charts實(shí)現(xiàn)可視化圖表過程解析,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2019-10-10
vue+axios實(shí)現(xiàn)文件下載及vue中使用axios的實(shí)例
這篇文章主要介紹了vue+axios實(shí)現(xiàn)文件下載及vue中使用axios的實(shí)例,需要的朋友可以參考下2018-09-09
Vue2中Element?DatePicker組件設(shè)置默認(rèn)日期及控制日期范圍
后臺(tái)項(xiàng)目想使用時(shí)間選擇器選擇一段時(shí)間進(jìn)行數(shù)據(jù)篩選,所以下面這篇文章主要給大家介紹了關(guān)于Vue2中Element?DatePicker組件設(shè)置默認(rèn)日期及控制日期范圍的相關(guān)資料,文中通過實(shí)例代碼介紹的非常詳細(xì),需要的朋友可以參考下2022-11-11
preload對(duì)比prefetch的功能區(qū)別詳解
這篇文章主要為大家介紹了preload對(duì)比prefetch的使用區(qū)別詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-06-06
vuex中store存儲(chǔ)store.commit和store.dispatch的用法
這篇文章主要介紹了vuex中store存儲(chǔ)store.commit和store.dispatch的用法,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07
Vue實(shí)現(xiàn)組件通信的8種實(shí)戰(zhàn)方案詳解
組件與組件之間的數(shù)據(jù)傳遞組件的數(shù)據(jù)是獨(dú)立的,無法直接訪問其他組件的數(shù)據(jù),通過組件通信,可以訪問其他組件的數(shù)據(jù),本文給大家介紹了Vue實(shí)現(xiàn)組件通信的8種實(shí)戰(zhàn)方案,需要的朋友可以參考下2025-08-08
淺談vue 組件中的setInterval方法和window的不同
這篇文章主要介紹了淺談vue 組件中的setInterval方法和window的不同,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧2020-07-07

