Ionic7+Capacitor5+Vue3相机拍照上传PDF报错求助
Ionic7 + Capacitor5 + Vue3:相机拍照生成PDF上传后端报错"Path cannot be empty"
问题背景
开发发票列表与PDF上传应用,包含三个功能:
- 从存储选择PDF并上传
- 从相册选图合并为PDF上传(正常运行)
- 相机拍照合并为PDF上传(出现异常)
使用相机拍照后点击上传,Symfony后端返回错误:
{
"class": "RuntimeException",
"file": "/var/www/html/wms-dev/vendor/guzzlehttp/psr7/src/Utils.php",
"line": 389,
"status_text": "Internal Server Error",
"message": "Unable to open "" using mode "r": Path cannot be empty",
...
}
问题分析
相册选图与相机拍照的核心差异在于图片资源的加载逻辑:
- 相册选图返回的
webPath是本地文件路径,浏览器可直接加载 - 相机拍照返回的
webPath是Capacitor临时URL(如capacitor://localhost/...),直接用img.src加载可能存在跨域或资源无法访问的问题,导致图片加载失败,生成的PDF内容为空,最终上传时后端接收空文件触发报错。
修复方案
修改createPdfFromPhotosAndUpload函数中的图片加载逻辑,通过fetch将webPath转换为Blob后生成可访问的临时URL,确保相机拍摄的图片能被正确加载:
async createPdfFromPhotosAndUpload() { this.sendingLoading = true try { const selectedPhotos = this.photos.filter((photo: any) => photo.selected); console.log("length of selectedPhotos Array ===>", selectedPhotos.length) if (selectedPhotos.length === 0) { console.log('No photos selected'); return; } const pdfDocs: Uint8Array[] = []; for (const photo of selectedPhotos) { const pdf = new jsPDF(); // 替换原图片加载逻辑,通过fetch获取Blob并生成临时URL const response = await fetch(photo.webPath); const blob = await response.blob(); const imgUrl = URL.createObjectURL(blob); const img = new Image(); img.src = imgUrl; await new Promise<void>((resolve, reject) => { img.onload = () => { URL.revokeObjectURL(imgUrl); // 释放临时URL内存 const imgWidth = 180; const imgHeight = (img.height * imgWidth) / img.width; pdf.addImage(img, 'JPEG', 15, 15, imgWidth, imgHeight); const pdfBytes = new Uint8Array(pdf.output('arraybuffer')); pdfDocs.push(pdfBytes); resolve(); }; // 处理图片加载失败的情况 img.onerror = (error) => { console.error('Failed to load image:', error); reject(new Error(`Image load failed: ${photo.webPath}`)); }; }); } // 合并PDF逻辑保持不变 const mergedPdf = await PDFDocument.create(); for (const pdfBytes of pdfDocs) { const pdf = await PDFDocument.load(pdfBytes); const copiedPages = await mergedPdf.copyPages(pdf, pdf.getPageIndices()); copiedPages.forEach(page => mergedPdf.addPage(page)); } const mergedPdfBytes = await mergedPdf.save(); const pdfDocument = new File([mergedPdfBytes], 'mergedDocument.pdf', { type: 'application/pdf' }); console.log("pdfDocument ===>", pdfDocument) const res = await this.uploadDocument(pdfDocument) if(res){ this.photos = this.photos.filter((photo: any) => !photo.selected) this.showToast('Document Envoyé !', 2000, 'success', planeIcon) if(!this.photos.length) this.togglePhotosModal() } } catch (error) { console.error("error creating pdf !!", error) } finally { this.sendingLoading = false } }
额外验证方案
如果上述修复仍无效,可尝试将相机拍照的返回格式改为Base64,直接使用字符串加载图片:
async prendrePhoto(){ this.isUsingCamera = true const photo = await Camera.getPhoto({ resultType: CameraResultType.Base64, // 修改为Base64格式 source: CameraSource.Camera, quality: 100 }) const photoWithSelected = { ...photo, selected: true, // 生成Base64格式的图片URL imgUrl: `data:image/${photo.format};base64,${photo.base64String}` } this.photos.push(photoWithSelected) if(!this.isPhotosModalOpen) this.togglePhotosModal() console.log("Photos taken ===>", this.photos) }
之后在生成PDF时,将img.src = photo.webPath替换为img.src = photo.imgUrl即可。
内容的提问来源于stack exchange,提问作者Chadizar Royland
相关产品推荐
相关产品推荐

