iTextSharp中PdfCopy下如何添加页眉PDF?原方案致字符串替换失效
解决用iText添加页眉且不破坏PDF格式的方案
Hey,我刚好遇到过类似的问题!之前用PdfContentByte.addTemplate加页眉时,确实容易破坏原PDF的内部结构,导致后续的字符串替换这类依赖文档结构的功能失效。改用PdfCopy或者PdfSmartCopy是非常正确的思路,我来给你详细讲怎么实现:
核心思路
我们的目标是完整保留原内容PDF的结构,同时将页眉PDF的内容合并到每个内容页面的顶部。实现方式是:
- 将页眉PDF的页面转换为可复用的模板(Form XObject)
- 遍历内容PDF的每个页面,创建新页面后先绘制页眉模板,再绘制原内容页面的模板
- 全程基于页面的完整拷贝操作,不修改原内容的内部流结构
实现代码(iText 7)
iText 7的API更简洁,类型安全也更好,以下是完整示例:
import com.itextpdf.kernel.pdf.*; import com.itextpdf.kernel.pdf.canvas.PdfCanvas; import com.itextpdf.kernel.pdf.xobject.PdfFormXObject; import java.io.IOException; public class AddHeaderToPdf { public static void main(String[] args) throws IOException { // 替换为你的文件路径 String headerPdfPath = "header.pdf"; String contentPdfPath = "content.pdf"; String outputPdfPath = "output_with_header.pdf"; // 初始化文档对象 PdfDocument headerDoc = new PdfDocument(new PdfReader(headerPdfPath)); PdfDocument contentDoc = new PdfDocument(new PdfReader(contentPdfPath)); PdfDocument outputDoc = new PdfDocument(new PdfWriter(outputPdfPath)); // 将页眉页面转为可复用模板(假设页眉只有1页) PdfPage headerPage = headerDoc.getPage(1); PdfFormXObject headerTemplate = headerPage.copyAsFormXObject(outputDoc); Rectangle headerSize = headerPage.getPageSize(); float headerHeight = headerSize.getHeight(); // 遍历处理每个内容页面 for (int pageNum = 1; pageNum <= contentDoc.getNumberOfPages(); pageNum++) { PdfPage contentPage = contentDoc.getPage(pageNum); Rectangle contentSize = contentPage.getPageSize(); // 创建新页面,尺寸为内容页面高度 + 页眉高度(也可以保持原尺寸,页眉覆盖顶部) Rectangle newPageSize = new Rectangle(contentSize.getWidth(), contentSize.getHeight() + headerHeight); PdfPage newPage = outputDoc.addNewPage(newPageSize); // 绘制页眉到新页面顶部 PdfCanvas canvas = new PdfCanvas(newPage); canvas.addXObject(headerTemplate, 0, contentSize.getHeight()); // 绘制原内容页面到页眉下方 PdfFormXObject contentTemplate = contentPage.copyAsFormXObject(outputDoc); canvas.addXObject(contentTemplate, 0, 0); } // 关闭所有资源 headerDoc.close(); contentDoc.close(); outputDoc.close(); } }
实现代码(iText 5)
如果还在使用iText 5,代码逻辑类似,但API略有不同:
import com.itextpdf.text.Document; import com.itextpdf.text.DocumentException; import com.itextpdf.text.Rectangle; import com.itextpdf.text.pdf.*; import java.io.FileOutputStream; import java.io.IOException; public class AddHeaderWithPdfCopy { public static void main(String[] args) throws IOException, DocumentException { String headerPath = "header.pdf"; String contentPath = "content.pdf"; String outputPath = "output_with_header.pdf"; PdfReader headerReader = new PdfReader(headerPath); PdfReader contentReader = new PdfReader(contentPath); Document document = new Document(); PdfCopy pdfCopy = new PdfCopy(document, new FileOutputStream(outputPath)); document.open(); // 获取页眉页面并转为模板 PdfImportedPage headerPage = pdfCopy.getImportedPage(headerReader, 1); Rectangle headerRect = headerPage.getBoundingBox(); float headerHeight = headerRect.getHeight(); // 处理每个内容页面 for (int i = 1; i <= contentReader.getNumberOfPages(); i++) { PdfImportedPage contentPage = pdfCopy.getImportedPage(contentReader, i); Rectangle contentRect = contentPage.getBoundingBox(); // 设置新页面尺寸 document.setPageSize(new Rectangle(contentRect.getWidth(), contentRect.getHeight() + headerHeight)); document.newPage(); // 获取画布,先绘制页眉,再绘制内容 PdfContentByte canvas = pdfCopy.getDirectContent(); canvas.addTemplate(headerPage, 0, contentRect.getHeight()); canvas.addTemplate(contentPage, 0, 0); } // 关闭资源 document.close(); headerReader.close(); contentReader.close(); } }
关键说明
- 为什么这个方案不会破坏格式?因为我们是将原内容页面完整拷贝为
PdfFormXObject(iText7)或PdfImportedPage(iText5),没有修改原页面的内部内容流,所以原PDF的表单、可搜索文本、字符串替换标记等结构都能完整保留。 - 如果页眉有多页,可以根据需求调整逻辑(比如只取第一页作为页眉,或者循环使用不同页眉)。
PdfSmartCopy和PdfCopy的用法几乎一致,PdfSmartCopy会自动复用重复的内容,生成的PDF体积更小,你可以直接把代码里的PdfCopy换成PdfSmartCopy即可。
内容的提问来源于stack exchange,提问作者Shahid Huss
相关产品推荐
相关产品推荐

