如何在Angular 9中合并图片与PDF为单个PDF并实现打印?
嗨,咱们来一步步解决你的这两个Angular 9需求吧,这俩都是日常开发里很常见的场景,我给你整理了靠谱的实现方案:
一、将多图片与PDF合并为单个PDF
我推荐使用pdf-lib这个库来实现,它对PDF文档的操作非常灵活,支持嵌入图片、合并现有PDF,而且完全基于浏览器端运行,不需要后端支持。
步骤1:安装依赖
首先在你的Angular 9项目里安装库和对应的TypeScript类型定义:
npm install pdf-lib @types/pdf-lib --save
步骤2:组件实现代码
下面是完整的组件示例,包含文件选择、合并逻辑和后续操作功能:
import { Component } from '@angular/core'; import { PDFDocument } from 'pdf-lib'; import { DomSanitizer, SafeResourceUrl } from '@angular/platform-browser'; @Component({ selector: 'app-pdf-merger', templateUrl: './pdf-merger.component.html', styleUrls: ['./pdf-merger.component.css'] }) export class PdfMergerComponent { selectedPdf: File | null = null; selectedImages: File[] = []; constructor(private sanitizer: DomSanitizer) {} // 选择要合并的基础PDF文件 onPdfSelected(event: Event) { const file = (event.target as HTMLInputElement).files?.[0]; if (file && file.type === 'application/pdf') { this.selectedPdf = file; } else { alert('请选择有效的PDF文件'); } } // 选择要添加的图片文件 onImagesSelected(event: Event) { const files = (event.target as HTMLInputElement).files; if (files) { this.selectedImages = Array.from(files).filter(file => file.type.startsWith('image/') ); } } // 核心合并逻辑,支持选择下载或打印 async mergeAndProcessFiles(shouldPrint: boolean = false) { if (!this.selectedPdf || this.selectedImages.length === 0) { alert('请选择PDF文件和至少一张图片'); return; } try { // 1. 加载现有PDF文档 const pdfBytes = await this.selectedPdf.arrayBuffer(); const pdfDoc = await PDFDocument.load(pdfBytes); // 2. 遍历图片,逐个添加到PDF末尾 for (const imgFile of this.selectedImages) { const imgBytes = await imgFile.arrayBuffer(); const img = imgFile.type === 'image/png' ? await pdfDoc.embedPng(imgBytes) : await pdfDoc.embedJpg(imgBytes); // 计算图片缩放比例,适配A4页面(避免超出边界) const a4Width = 595.28; // PDF标准A4宽度(单位:点) const a4Height = 841.89; // PDF标准A4高度 const scale = Math.min(a4Width / img.width, a4Height / img.height); const scaledWidth = img.width * scale; const scaledHeight = img.height * scale; // 添加新页面并绘制图片 const newPage = pdfDoc.addPage([scaledWidth, scaledHeight]); newPage.drawImage(img, { x: 0, y: 0, width: scaledWidth, height: scaledHeight, }); } // 3. 生成合并后的PDF字节数据 const mergedPdfBytes = await pdfDoc.save(); // 根据需求选择下载或打印 if (shouldPrint) { await this.printPdf(mergedPdfBytes); } else { this.downloadPdf(mergedPdfBytes); } } catch (error) { console.error('合并失败:', error); alert('PDF合并出错,请检查文件格式后重试'); } } // 下载合并后的PDF downloadPdf(pdfBytes: Uint8Array) { const blob = new Blob([pdfBytes], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); const aTag = document.createElement('a'); aTag.href = url; aTag.download = 'merged-result.pdf'; aTag.click(); URL.revokeObjectURL(url); } // 打印合并后的PDF async printPdf(pdfBytes: Uint8Array) { const blob = new Blob([pdfBytes], { type: 'application/pdf' }); const url = URL.createObjectURL(blob); const safeUrl = this.sanitizer.bypassSecurityTrustResourceUrl(url); // 创建隐藏iframe加载PDF,避免页面跳转 const iframe = document.createElement('iframe'); iframe.style.display = 'none'; iframe.src = safeUrl as string; document.body.appendChild(iframe); // 等待PDF加载完成后触发打印 iframe.onload = () => { setTimeout(() => { iframe.contentWindow?.print(); document.body.removeChild(iframe); URL.revokeObjectURL(url); }, 1000); // 延迟1秒确保PDF完全加载,可根据实际情况调整 }; } }
步骤3:模板代码(html)
在组件的模板里添加文件选择器和操作按钮:
<div class="pdf-merger-container"> <div> <label>选择基础PDF文件:</label> <input type="file" accept=".pdf" (change)="onPdfSelected($event)"> </div> <div> <label>选择要添加的图片(支持多张):</label> <input type="file" accept="image/png, image/jpeg" multiple (change)="onImagesSelected($event)"> </div> <div class="button-group"> <button (click)="mergeAndProcessFiles(false)" [disabled]="!selectedPdf || selectedImages.length === 0"> 合并并下载 </button> <button (click)="mergeAndProcessFiles(true)" [disabled]="!selectedPdf || selectedImages.length === 0"> 合并并打印 </button> </div> </div>
二、合并后实现打印功能
上面的代码里已经内置了完整的打印逻辑,核心思路是:
- 将合并后的PDF字节数据转为Blob URL
- 通过隐藏的iframe加载PDF(避免页面跳转)
- 等待PDF加载完成后调用浏览器原生的
print()方法
关键注意事项
- 因为Angular的安全策略,Blob URL需要通过
DomSanitizer处理成安全资源URL,否则会被框架阻止加载 - 延迟1秒触发打印是为了确保PDF完全加载,不同浏览器的加载速度不同,可根据实际情况调整这个时间
- 部分浏览器会默认拦截弹窗类请求,需要用户允许打印窗口弹出
如果需要更自定义的打印样式(比如添加页眉页脚、调整打印尺寸),可以考虑先把PDF转成HTML片段,用html2canvas渲染后再打印,但这种方式复杂度更高,上面的方案已经能满足大部分常规打印需求。
内容的提问来源于stack exchange,提问作者Priyank
相关产品推荐
相关产品推荐

