使用jsPDF AutoTable添加S3图片报错及PDF无图问题排查
我尝试将AWS S3存储桶中的图片通过URL添加到jsPDF AutoTable生成的PDF表格中,使用版本:jspdf: ^2.5.1,jspdf-autotable: ^3.5.31,Angular 8。
数据格式
[{ netValue: 13702.5, prodCode: "UPP", prodDesc: "Privacy Panel", prodImg: "https://url/images/UPP02.png", prodQty: 20, unitPrice: 870 }]
HTML表格代码
<table class="table table-hover table-responsive-xxl table-bordered" id="prodTable" #prodTable> <thead> <tr class="table-reflow"> <th>S. N</th> <th>Product Code</th> <th>Description</th> <th>Image</th> <th>Qty</th> <th>Price</th> <th>Amount</th> </tr> </thead> <tbody> <tr *ngFor="let prod of prodDetailsArr; let i = index"> <td>{{ i+1 }}</td> <td>{{ prod.prodCode }}</td> <td>{{ prod.prodDesc }}</td> <td><img [src]="prod.prodImg"></td> <td>{{ prod.prodQty }}</td> <td>{{ prod.unitPrice }}</td> <td>{{ prod.netValue }}</td> </tr> </tbody> </table>
尝试的PDF生成代码
autoTable(doc, { html: '#prodTable', startY: 200, theme: 'plain', tableLineColor: [0, 0, 0], tableLineWidth: 0.5, margin: { left: 5, right: 7 }, didDrawCell: function(data) { if (data.column.index === 3 && data.cell.section === 'body') { var td = data.cell.raw; console.log(td) var img = td.getElementsByTagName('img')[0]; var dim = data.cell.height - data.cell.padding('vertical'); doc.addImage(img.src, data.cell.x, data.cell.y, dim, dim); } } })
遇到的错误
编译错误
Property 'getElementsByTagName' does not exist on type 'HTMLTableCellElement | CellInput'.
Property 'getElementsByTagName' does not exist on type 'string'.
运行时错误
- CORS错误:
zone-evergreen.js:2981 Access to XMLHttpRequest at 'https://url/images/UPP02.png' from origin 'http://localhost:4200' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
- addImage格式错误:
ERROR Error: addImage does not support files of type 'UNKNOWN', please ensure that a plugin for 'UNKNOWN' support is added.
at Object.P (jspdf.es.min.js:86:93253)
at push../node_modules/jspdf/dist/jspdf.es.min.js.e.addImage
- StackBlitz额外错误:
Incomplete or corrupt PNG File
解决方案
1. 修复编译错误
data.cell.raw的类型为HTMLTableCellElement | CellInput,需先做类型断言和校验,确保操作的是HTML元素:
didDrawCell: function(data) { if (data.column.index === 3 && data.cell.section === 'body') { const td = data.cell.raw as HTMLTableCellElement; if (td instanceof HTMLElement) { const img = td.getElementsByTagName('img')[0]; if (img) { const dim = data.cell.height - data.cell.padding('vertical'); // 后续图片处理逻辑 } } } }
2. 解决S3 CORS问题
在AWS S3存储桶中配置CORS规则,允许前端域名访问:
<CORSConfiguration> <CORSRule> <AllowedOrigin>http://localhost:4200</AllowedOrigin> <AllowedMethod>GET</AllowedMethod> <AllowedHeader>*</AllowedHeader> </CORSRule> </CORSConfiguration>
生产环境可替换为实际的前端域名,或使用*允许所有域名(不推荐)。
3. 解决addImage格式与图片损坏问题
jsPDF无法直接使用远程URL添加图片,需先将图片转换为Base64格式:
// Angular中封装图片转Base64方法 async getImageBase64(url: string): Promise<string> { const response = await this.httpClient.get(url, { responseType: 'blob' }).toPromise(); return new Promise((resolve, reject) => { const reader = new FileReader(); reader.onloadend = () => resolve(reader.result as string); reader.onerror = reject; reader.readAsDataURL(response); }); } // 预加载图片后生成PDF async generatePdf() { const doc = new jsPDF(); // 预加载所有图片的Base64 const imgBase64Arr = await Promise.all( this.prodDetailsArr.map(prod => this.getImageBase64(prod.prodImg)) ); autoTable(doc, { html: '#prodTable', startY: 200, theme: 'plain', tableLineColor: [0, 0, 0], tableLineWidth: 0.5, margin: { left: 5, right: 7 }, didDrawCell: (data) => { if (data.column.index === 3 && data.cell.section === 'body') { const imgBase64 = imgBase64Arr[data.row.index]; const dim = data.cell.height - data.cell.padding('vertical'); // 明确指定图片格式,如PNG/JPEG doc.addImage(imgBase64, 'PNG', data.cell.x, data.cell.y, dim, dim); } } }); doc.save('products.pdf'); }
额外注意事项
- 确保S3图片权限正确,可设置为公开可读,或使用预签名URL访问私有图片
- 若图片为JPG格式,需将
addImage的格式参数改为'JPEG'
内容的提问来源于stack exchange,提问作者Nooh Ahamad

