iText7合并HTML转PDF与带嵌入式Excel的PDF时异常求助
iText7合并PDF时出现"Trailer not found"和交叉引用表错误的解决方法
嘿,刚看完你的代码和报错信息,问题其实很明确——你生成的PDF内容不完整,导致后续读取时解析失败。
问题根源
iText7的PdfDocument对象负责处理PDF的整个写入生命周期,包括生成交叉引用表和trailer(这两个是PDF文件的核心结构)。你的代码里,生成HTML转PDF的pdf对象、生成带附件PDF的pdfLaunch对象都没有被关闭,导致ByteArrayOutputStream里只写入了PDF的部分内容,缺少关键的结尾结构。当你用PdfReader读取这些不完整的流时,自然会抛出找不到xref或者trailer的错误。
修复方案
解决方法很简单:用Java的try-with-resources语法来管理PdfDocument和相关流,确保它们在使用完成后自动关闭,这样就能保证PDF内容完整写入输出流。
下面是修改后的完整代码:
import com.itextpdf.kernel.geom.PageSize; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.*; import com.itextpdf.kernel.pdf.annot.PdfAnnotation; import com.itextpdf.kernel.pdf.annot.PdfFileAttachmentAnnotation; import com.itextpdf.kernel.pdf.filespec.PdfFileSpec; import com.itextpdf.html2pdf.ConverterProperties; import com.itextpdf.html2pdf.HtmlConverter; import java.io.*; import java.nio.file.Files; import java.nio.file.Paths; public class PdfMergeFix { public static void main(String[] args) throws IOException { String htmlContent = "<html><body><h1>HTML to PDF Test</h1></body></html>"; String excelPath = "path/to/your/test.xlsx"; String outputDir = "path/to/output/dir"; String dest = "path/to/final/merged.pdf"; // 1. 将HTML转换为PDF,用try-with-resources确保PdfDocument关闭 ByteArrayOutputStream htmlToPdfContent = new ByteArrayOutputStream(); try (PdfWriter writer = new PdfWriter(htmlToPdfContent); PdfDocument pdf = new PdfDocument(writer)) { pdf.setTagged(); PageSize pageSize = PageSize.A4.rotate(); pdf.setDefaultPageSize(pageSize); ConverterProperties properties = new ConverterProperties(); HtmlConverter.convertToPdf(htmlContent, pdf, properties); // 这里不需要手动关闭,try-with-resources会自动处理 } // 清理输出目录 FileUtils.cleanDirectory(new File(outputDir)); // 2. 生成带Excel附件的PDF,同样用try-with-resources ByteArrayOutputStream pdfAttach = new ByteArrayOutputStream(); try (PdfWriter attachWriter = new PdfWriter(pdfAttach); PdfDocument pdfLaunch = new PdfDocument(attachWriter)) { Rectangle rect = new Rectangle(36, 700, 100, 100); byte[] embeddedFileContentBytes = Files.readAllBytes(Paths.get(excelPath)); PdfFileSpec fs = PdfFileSpec.createEmbeddedFileSpec(pdfLaunch, embeddedFileContentBytes, null, "test.xlsx", null, null); PdfAnnotation attachment = new PdfFileAttachmentAnnotation(rect, fs) .setContents("Click me"); pdfLaunch.addNewPage().addAnnotation(attachment); } // 3. 合并两个PDF到最终输出 try (ByteArrayOutputStream pdfResult = new ByteArrayOutputStream(); PdfWriter writerResult = new PdfWriter(pdfResult); PdfDocument pdfDocResult = new PdfDocument(writerResult); // 读取HTML转PDF的文档 PdfReader htmlPdfReader = new PdfReader(new ByteArrayInputStream(htmlToPdfContent.toByteArray())); PdfDocument htmlPdfDoc = new PdfDocument(htmlPdfReader); // 读取带附件的PDF文档 PdfReader attachPdfReader = new PdfReader(new ByteArrayInputStream(pdfAttach.toByteArray())); PdfDocument attachPdfDoc = new PdfDocument(attachPdfReader)) { // 复制HTML PDF的所有页面 htmlPdfDoc.copyPagesTo(1, htmlPdfDoc.getNumberOfPages(), pdfDocResult); // 复制带附件的PDF页面 attachPdfDoc.copyPagesTo(1, attachPdfDoc.getNumberOfPages(), pdfDocResult); // 写入最终文件 try (OutputStream outputStream = new FileOutputStream(dest)) { pdfResult.writeTo(outputStream); } } } }
关键修改点
- 所有
PdfDocument、PdfWriter、PdfReader实例都通过try-with-resources声明,确保资源自动关闭,避免手动遗漏 - 将生成HTML PDF和带附件PDF的逻辑分别封装在独立的try-with-resources块中,保证每个PDF生成完成后都能完整写入流
- 合并阶段的所有资源也统一用try-with-resources管理,进一步避免资源泄漏
这样修改后,生成的PDF都是完整的,合并时就不会再出现交叉引用表或trailer相关的错误了。
内容的提问来源于stack exchange,提问作者Neeraj Kunturkar
相关产品推荐
相关产品推荐

