PHP无输入框上传PDF:浏览器标注后自动上传至upload.php
实现标注后PDF存入localStorage并自动上传至upload.php
方案一:上传多页标注图片(基于现有canvas渲染逻辑)
你的现有代码是将每一页PDF渲染为带标注的图片,我们可以调整逻辑,先收集所有页面的图片数据存入localStorage,再转成文件格式上传到后端。
前端修改代码
// 生成标注后数据并完成上传 async function generateAndUploadAnnotatedPages() { const pageDataUrls = []; const totalPages = pdfDoc.numPages; // 按顺序渲染所有带标注的页面 for (let pageNum = 1; pageNum <= totalPages; pageNum++) { const page = await pdfDoc.getPage(pageNum); const viewport = page.getViewport({ scale: 1.5 }); const canvas = document.createElement('canvas'); const context = canvas.getContext('2d'); canvas.width = viewport.width; canvas.height = viewport.height; const renderContext = { canvasContext: context, viewport: viewport }; // 渲染PDF页面并等待完成 await page.render(renderContext).promise; // 渲染当前页的标注 renderAnnotationsOnCanvas(context, pageNum); // 将canvas转为base64格式的图片数据 const imageData = canvas.toDataURL('image/png'); pageDataUrls.push(imageData); } // 存入localStorage(注意:localStorage单条数据上限约5MB,大PDF可能超出) localStorage.setItem('annotatedPDFPages', JSON.stringify(pageDataUrls)); // 从localStorage取出数据并准备上传 const storedPages = JSON.parse(localStorage.getItem('annotatedPDFPages')); const formData = new FormData(); // 将每个页面的base64数据转为Blob,添加到FormData storedPages.forEach((dataUrl, index) => { const blob = dataURLToBlob(dataUrl); formData.append(`pdf_pages[${index}]`, blob, `page_${index + 1}.png`); }); // 发送上传请求 try { const response = await fetch('upload.php', { method: 'POST', body: formData }); if (response.ok) { console.log('标注页面上传成功'); // 上传完成后可清除localStorage中的数据 localStorage.removeItem('annotatedPDFPages'); } else { console.error('上传请求失败'); } } catch (error) { console.error('上传过程出错:', error); } } // 辅助函数:将base64格式的dataURL转为Blob function dataURLToBlob(dataUrl) { const arr = dataUrl.split(','); const mime = arr[0].match(/:(.*?);/)[1]; const bstr = atob(arr[1]); const u8arr = new Uint8Array(bstr.length); for (let i = 0; i < bstr.length; i++) { u8arr[i] = bstr.charCodeAt(i); } return new Blob([u8arr], { type: mime }); }
方案二:合并为单PDF文件上传(更贴合需求)
如果需要上传完整的PDF文件而非单页图片,可以使用jsPDF库将带标注的页面图片合并为一个PDF文件,再进行存储和上传。
前端代码(需引入jsPDF)
// 先在页面引入jsPDF库:<script src="https://cdnjs.cloudflare.com/ajax/libs/jspdf/2.5.1/jspdf.umd.min.js"></script> async function generateAndUploadAnnotatedPDF() { const { jsPDF } = window.jspdf; // 初始化A4尺寸的PDF文档 const pdf = new jsPDF('p', 'mm', 'a4'); const totalPages = pdfDoc.numPages; for (let pageNum = 1; pageNum <= totalPages; pageNum++) { const page = await pdfDoc.getPage(pageNum); const viewport = page.getViewport({ scale: 1.5 }); const canvas = document.createElement('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; renderAnnotationsOnCanvas(context, pageNum); // 将canvas图片添加到PDF文档 const imgData = canvas.toDataURL('image/png'); const pageWidth = pdf.internal.pageSize.getWidth(); // 按比例计算图片高度,适配A4宽度 const pageHeight = (canvas.height * pageWidth) / canvas.width; // 第一页无需新增,后续页面添加新页 if (pageNum > 1) { pdf.addPage(); } pdf.addImage(imgData, 'PNG', 0, 0, pageWidth, pageHeight); } // 将生成的PDF转为Blob格式 const pdfBlob = pdf.output('blob'); // 将Blob转为base64存入localStorage(Blob无法直接存入) const reader = new FileReader(); reader.onload = function(e) { const pdfBase64 = e.target.result; localStorage.setItem('annotatedPDF', pdfBase64); // 准备FormData上传 const formData = new FormData(); formData.append('annotated_pdf', pdfBlob, 'annotated.pdf'); // 发送上传请求 fetch('upload.php', { method: 'POST', body: formData }) .then(response => { if (response.ok) { console.log('标注PDF上传成功'); localStorage.removeItem('annotatedPDF'); } else { console.error('上传失败'); } }) .catch(error => console.error('上传错误:', error)); }; reader.readAsDataURL(pdfBlob); }
后端upload.php示例
<?php // 确保上传目录存在 $uploadDir = 'uploads/'; if (!file_exists($uploadDir)) { mkdir($uploadDir, 0777, true); } // 处理单PDF文件上传(对应方案二) if (isset($_FILES['annotated_pdf'])) { $targetFile = $uploadDir . basename($_FILES['annotated_pdf']['name']); if (move_uploaded_file($_FILES['annotated_pdf']['tmp_name'], $targetFile)) { echo "PDF文件上传成功"; } else { echo "PDF上传失败"; } } // 处理多页图片上传(对应方案一) if (isset($_FILES['pdf_pages'])) { foreach ($_FILES['pdf_pages']['tmp_name'] as $index => $tmpName) { $fileName = $uploadDir . 'page_' . ($index + 1) . '.png'; move_uploaded_file($tmpName, $fileName); } echo "所有页面图片上传成功"; } ?>
关键注意事项
- localStorage存储限制:
localStorage单条数据上限约5MB,base64格式会比原文件大30%左右,大尺寸/多页PDF可能超出限制,这种情况建议使用IndexedDB替代。 - 异步处理顺序:原代码的for循环未处理异步渲染的顺序问题,使用
async/await可以保证页面按顺序渲染和收集。 - 文件上传格式:使用
FormData传递文件是前端上传文件的标准方式,后端可通过$_FILES全局变量获取上传的文件。
内容的提问来源于stack exchange,提问作者Dhruv Pandey
相关产品推荐
相关产品推荐

