pdf文件根据页数解析成图片 js vue3
pdf文件根据页数解析成图片 js vue3
安装pdfjs-dist
npm install pdfjs-dist
<template><div><div style="margin-top:1%"> <button @click="prevPage">上一页</button><button @click="nextPage">下一页</button><button @click="exportImages">导出图片</button><button @click="choosePdf">选择一个pdf文件</button><input ref="fileInput"style="display:none" type="file" accept="application/pdf"@change="handleFileChange"></div><div style="margin-top:1%;color:#000;"><span class="pdfInfos">页码:<span>{{ currentPage }}</span>/<span>{{ totalPages }}</span></span><span class="pdfInfos">文件名:<span>{{ fileName }}</span></span><span class="pdfInfos">文件大小:<span>{{ fileSize }}</span></span></div><div style="position: relative;"><div id="container"><canvasv-for="page in totalPages":key="page":id="`pageNum${page}`":ref="el => setCanvasRef(el, page)":style="{ display: page === currentPage ? 'block' : 'none', width: '100%', height: '100%' }"/></div><img id="imgloading" style="position: absolute;top: 20%;left: 2%;" :style="{ display: loading ? 'block' : 'none' }"src="loading.gif"></div></div>
</template><script setup>
import { ref, reactive } from 'vue'
import * as pdfjsLib from "pdfjs-dist/build/pdf";
import "pdfjs-dist/build/pdf.worker.mjs";// 响应式数据
const fileInput = ref(null)
const canvasRefs = reactive({})
const currentPage = ref(1)
const totalPages = ref(0)
const fileName = ref('')
const fileSize = ref('')
const loading = ref(false)
const scale = 2
let pdfDoc = nullconst images = ref([])
// base64转file
const base64ToFile = (base64, filename = "") => {const arr = base64.split(",");let mime = arr[0].match(/:(.*?);/)[1]; // 匹配出图片类型mime = mime.replace("data:", ""); // 去掉data:image/png;base64 // 去掉url中的base64,并转化为Uint8Array类型const bstr = atob(arr[1]);let n = bstr.length;const u8arr = new Uint8Array(n);while (n--) {u8arr[n] = bstr.charCodeAt(n);}return new File([u8arr], filename, { type: mime });
};// 设置canvas引用
const setCanvasRef = (el, page) => {if (el) {canvasRefs[page] = el}
}// 选择PDF文件
const choosePdf = () => {fileInput.value.click()
}// 处理文件变化
const handleFileChange = async (event) => {const file = event.target.files[0]if (!file) return// 检查文件大小const fileSizeInMB = file.size / 1048576if (fileSizeInMB > 10) {alert("文件大小不能>10M")return}fileName.value = file.namefileSize.value = fileSizeInMB.toFixed(2) + "Mb"loading.value = truetry {const arrayBuffer = await file.arrayBuffer()pdfDoc = await pdfjsLib.getDocument({ data: arrayBuffer }).promisetotalPages.value = pdfDoc.numPagescurrentPage.value = 1// 清空之前的canvas引用Object.keys(canvasRefs).forEach(key => {delete canvasRefs[key]})// 渲染所有页面for (let i = 1; i <= totalPages.value; i++) {await renderPage(pdfDoc, i)}} catch (error) {console.error('PDF加载失败:', error)} finally {loading.value = false}
}// 渲染PDF页面
const renderPage = async (pdfFile, pageNumber) => {try {const page = await pdfFile.getPage(pageNumber)const viewport = page.getViewport({ scale })// 等待DOM更新await new Promise(resolve => setTimeout(resolve, 0))const canvas = document.getElementById(`pageNum${pageNumber}`)if (canvas) {const context = canvas.getContext('2d')canvas.width = viewport.widthcanvas.height = viewport.heightconst renderContext = {canvasContext: context,viewport: viewport}await page.render(renderContext).promiseimages.value.push(canvas.toDataURL("image/png"));let rawFileAvatar = base64ToFile(canvas.toDataURL("image/png"), "avatar.png")images.value.push(URL.createObjectURL(rawFileAvatar));console.log(rawFileAvatar,'images.valueimages.value',images.value);// 1.将 Canvas 画布内容转换为 PNG 格式的 Base64 数据 URL。eg:canvas.toDataURL("image/png")// 2.将base64转换为file eg: base64ToFile(canvas.toDataURL("image/png")// 3.是为 File/Blob 对象创建一个临时的本地 URL 引用 eg:"blob:http://localhost:8087/54e91584-9cd5-4a18-9ecc-c5dec229d0c6}} catch (error) {console.error(`渲染第${pageNumber}页失败:`, error)}
}// 上一页
const prevPage = () => {if (currentPage.value <= 1) returncurrentPage.value--
}// 下一页
const nextPage = () => {if (currentPage.value >= totalPages.value) returncurrentPage.value++
}// 导出图片
const exportImages = async () => {if (!pdfDoc) {alert('请先上传pdf文件')return}loading.value = truetry {const zip = new window.JSZip()const images = zip.folder("images")// 遍历canvas,将其生成图片放进文件夹images中for (let i = 1; i <= totalPages.value; i++) {const canvas = document.getElementById(`pageNum${i}`)if (canvas) {const imageData = canvas.toDataURL("image/png", 1.0)const base64Data = imageData.split(',')[1]images.file(`photo-${i}.png`, base64Data, { base64: true })}}// 打包下载const content = await zip.generateAsync({ type: "blob" })window.saveAs(content, "picture.zip")} catch (error) {console.error('导出图片失败:', error)} finally {loading.value = false}
}
</script><style scoped>
button {width: 120px;height: 30px;background: none;border: 1px solid #b1afaf;border-radius: 5px;font-size: 12px;font-weight: 1000;color: #384240;cursor: pointer;outline: none;margin: 0 0.5%
}button:hover {background: #ccc;
}#container {width: 600px;height: 580px;margin-top: 1%;border-radius: 2px;border: 2px solid #a29b9b;
}.pdfInfos {margin: 0 2%;
}
</style>
如果不想用canvas渲染图片,也可以直接用img渲染图片
<template><div><input type="file" @change="handleFileUpload" accept="application/pdf" /><div class="imgItem" v-for="(image, index) in images" :key="index"><img :src="image" :alt="'Page ' + (index + 1)" /></div></div>
</template><script setup>
import { ref } from "vue";
import * as pdfjsLib from "pdfjs-dist/build/pdf";
import "pdfjs-dist/build/pdf.worker.mjs";const images = ref([]);const handleFileUpload = async (event) => {const file = event.target.files[0];if (!file) return;const reader = new FileReader();reader.onload = async (e) => {const pdf = await pdfjsLib.getDocument(e.target.result).promise;images.value = [];for (let pageNum = 1; pageNum <= pdf.numPages; pageNum++) {const page = await pdf.getPage(pageNum);const viewport = page.getViewport({ scale: 2 });const canvas = document.createElement("canvas");const ctx = canvas.getContext("2d");canvas.height = viewport.height;canvas.width = viewport.width;await page.render({ canvasContext: ctx, viewport }).promise;images.value.push(canvas.toDataURL("image/png"));console.log(images.value,'images.valueimages.value');}};reader.readAsArrayBuffer(file);
};
</script>
<style>
.imgItem {margin-bottom: 50px;
}
</style>
还有对图片格式的转化,需要啥图片格式就转换啥
images.value.push(canvas.toDataURL("image/png"));let rawFileAvatar = base64ToFile(canvas.toDataURL("image/png"), "avatar.png")images.value.push(URL.createObjectURL(rawFileAvatar));console.log(rawFileAvatar,'images.valueimages.value',images.value);// 1.将 Canvas 画布内容转换为 PNG 格式的 Base64 数据 URL。eg:canvas.toDataURL("image/png")// 2.将base64转换为file eg: base64ToFile(canvas.toDataURL("image/png")// 3.URL.createObjectURL是为 File/Blob 对象创建一个临时的本地 URL 引用 eg:"blob:http://localhost:8087/54e91584-9cd5-4a18-9ecc-c5dec229d012”格式