pdf文件根据页数解析成图片 js vue3
安装pdfjs-dist
javascript
npm install pdfjs-dist
javascript
<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">
<canvas
v-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 = null
const 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 / 1048576
if (fileSizeInMB > 10) {
alert("文件大小不能>10M")
return
}
fileName.value = file.name
fileSize.value = fileSizeInMB.toFixed(2) + "Mb"
loading.value = true
try {
const arrayBuffer = await file.arrayBuffer()
pdfDoc = await pdfjsLib.getDocument({ data: arrayBuffer }).promise
totalPages.value = pdfDoc.numPages
currentPage.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.width
canvas.height = viewport.height
const renderContext = {
canvasContext: context,
viewport: viewport
}
await page.render(renderContext).promise
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.是为 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) return
currentPage.value--
}
// 下一页
const nextPage = () => {
if (currentPage.value >= totalPages.value) return
currentPage.value++
}
// 导出图片
const exportImages = async () => {
if (!pdfDoc) {
alert('请先上传pdf文件')
return
}
loading.value = true
try {
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渲染图片
javascript
<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>
还有对图片格式的转化,需要啥图片格式就转换啥
javascript
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"格式