From 646d92b5548b290837556463d59b94605d6545c0 Mon Sep 17 00:00:00 2001 From: linfso Date: Mon, 3 Jun 2024 08:41:30 +0800 Subject: [PATCH] md --- src/utils/pdfjsUtils.js | 235 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 235 insertions(+) create mode 100644 src/utils/pdfjsUtils.js diff --git a/src/utils/pdfjsUtils.js b/src/utils/pdfjsUtils.js new file mode 100644 index 00000000..a2a47df5 --- /dev/null +++ b/src/utils/pdfjsUtils.js @@ -0,0 +1,235 @@ +import * as pdfjs from 'pdfjs-dist'; +import * as pdfjsWorker from 'pdfjs-dist/build/pdf.worker.entry'; +/** + * pdf转图片获取pdf页数,用于渲染页面 + * @param {file} file - 文件 + */ +export function getPdfnum(file) { + return new Promise((resolve, reject) => { + const imgFiles = []; + if (file.type === 'application/pdf') { + let reader = new FileReader(); + reader.readAsDataURL(file); //将文件读取为 DataURL + reader.onload = function () { + //文件读取成功完成时触发 + const loadingTask = pdfjs.getDocument(reader.result); + loadingTask.promise.then(async (pdf) => { + const pageNum = pdf.numPages; + if (pageNum > 10) { + reject('此pdf页数过多,请线下合并'); + } + //准备图片 + for (let i = 1; i <= pageNum; i++) { + imgFiles.push(i); + } + resolve(imgFiles); + }); + }; + reader.onerror = function () { + // 如果文件读取失败,拒绝Promise + reject(new Error('Failed to read the file')); + }; + } else { + resolve([]); + } + }); +} +//pdf转图片 +export function PdfToImg(file) { + return new Promise((resolve, reject) => { + const newimgList = []; + const fileName = file.name.substring(0, file.name.lastIndexOf('.')); + if (file.type === 'application/pdf') { + let reader = new FileReader(); + reader.readAsDataURL(file); //将文件读取为 DataURL + reader.onload = function () { + //文件读取成功完成时触发 + const loadingTask = pdfjs.getDocument(reader.result); + loadingTask.promise.then(async (pdf) => { + let pageNum = pdf.numPages; + // 处理 + for (let i = 1; i <= pageNum; i++) { + let canvasItem = ''; + pdf.getPage(i).then(async (page) => { + const canvas = document.getElementById('pdf_canvas_' + i); + const ctx = canvas.getContext('2d'); + const viewport = page.getViewport({ scale: 4 }); + canvas.height = viewport.height; + canvas.width = viewport.width; + const destWidth = 298; + const destheight = destWidth * (viewport.height / viewport.width); + canvas.style.width = destWidth + 'px'; + canvas.style.height = destWidth * (viewport.height / viewport.width) + 'px'; + newimgList.push(canvas); + await page.render({ canvasContext: ctx, viewport }); + // 使用file对象进行后续操作 + if (i === pageNum) { + setTimeout(async () => { + const res = await savePdfImage(newimgList, destWidth, destheight, fileName); + resolve(res); + }, 500); + } + }); + } + }); + }; + reader.onerror = function () { + // 如果文件读取失败,拒绝Promise + reject(new Error('Failed to read the file')); + }; + } else { + const reader = new FileReader(); + reader.onload = function (e) { + let pngData = e.target.result; + let obj = { + url: pngData, + name: fileName, + }; + resolve(obj); + }; + // 开始读取文件 + reader.readAsDataURL(file); + } + }); +} + +/** + * pdf保存图片 + * @param {Array} newimgList - canvas列表 + * @param {Number} x - 页面展示宽 + * @param {Number} y - 页面展示高 + * @param {String}fileName - 文件名称 + */ +function savePdfImage(newimgList, x, y, fileName) { + return new Promise((resolve, reject) => { + let allcanvas = document.getElementById('canvas'); + let allctx = allcanvas.getContext('2d'); + allcanvas.style.width = x; + allcanvas.style.height = y * newimgList.length; + const subCanvasWidth = newimgList[0].width; + const subCanvasHeight = newimgList[0].height; + allcanvas.width = subCanvasWidth; + allcanvas.height = subCanvasHeight * newimgList.length; + newimgList.forEach((subCanvas, index) => { + // 计算当前图片在Canvas中的垂直位置 + const yPosition = index * subCanvasHeight; + // 绘制图片 + // 使用drawImage的四个参数版本来指定绘制的源图像区域和目标区域 + allctx.drawImage(subCanvas, 0, yPosition, subCanvasWidth, subCanvasHeight); + if (index === newimgList.length - 1) { + let pngData = allcanvas.toDataURL('image/png'); + let obj = { + url: pngData, + name: fileName, + }; + resolve(obj); + } + }); + }); +} +/** + * 合并图片 + * @param {file} filelist - 文件列表 + * @param {Number} realWidth - 合并后的文件宽度 + * + */ +export function MeargeImg(filelist, realWidth) { + return new Promise(async (resolve, reject) => { + if (!filelist.length) { + reject('材料不能为空,请检查'); + } + let canvas = document.getElementById('myCanvas'); + const ctx = canvas.getContext('2d'); + let x = 0; + let y = 0; + //获取图片信息 + const dpr = window.devicePixelRatio; + const res = await getImginfo(filelist, realWidth); + //展示高度 + canvas.style.width = realWidth; + canvas.style.height = res; + canvas.width = realWidth * dpr; + canvas.height = res * dpr; + for (let i = 0; i < filelist.length; i++) { + const img = new Image(); + img.src = filelist[i].url; + img.crossOrigin = 'anonymous'; + img.onload = async () => { + let { imgWidth, imgHeight } = await setPosition(x, y, img, realWidth); + //获取比例 + ctx.drawImage(img, x, y, imgWidth, imgHeight); + y += imgHeight; + if (i === filelist.length - 1) { + // 下载图片 + let pngData = canvas.toDataURL('image/png'); + let filename = filelist[0].name + '.png' || '合并图片.png'; + let fileimg = await base64ToFile(pngData, filename); + let obj = { + target: { + files: [fileimg], + }, + }; + resolve({ data: obj }); + } + }; + } + ctx.scale(dpr, dpr); + }); +} +//获取实际位置,宽高 +function setPosition(x, y, img, realWidth) { + return new Promise((resolve, reject) => { + const scaledpr = img.width / realWidth; + let imgWidth = img.width; + let imgHeight = img.height; + if (scaledpr > 1) { + imgWidth = img.width / scaledpr; + imgHeight = img.height / scaledpr; + } + resolve({ + imgWidth: imgWidth, + imgHeight: imgHeight, + }); + }); +} +//获取所有图片的总高度 +function getImginfo(filelist, realWidth) { + return new Promise((resolve, reject) => { + let allHeight = 0; + let loadedCount = 0; // 用于追踪已加载图片数量 + let totalImages = filelist.length; // 图片总数 + for (let i = 0; i < totalImages; i++) { + const img = new Image(); + img.crossOrigin = 'anonymous'; + img.src = filelist[i].url; + img.onload = () => { + const scaledpr = img.width / realWidth; + let imgHeight = img.height; + if (scaledpr > 1) { + imgHeight = img.height / scaledpr; + } + allHeight += imgHeight; + loadedCount++; // 增加已加载图片计数 + if (loadedCount === totalImages) { + resolve(allHeight); + } + }; + img.onerror = (error) => { + reject(error); + }; + } + }); +} +//base64转file文件 +function base64ToFile(base64, filename) { + filename = filename || String(new Date().getTime()); + let arr = base64.split(','); + let mime = arr[0].match(/:(.*?);/)[1]; + let bstr = atob(arr[1]); + let n = bstr.length; + let u8arr = new Uint8Array(n); + while (n--) { + u8arr[n] = bstr.charCodeAt(n); + } + return new File([u8arr], filename, { type: mime }); +}