使用iTextPDF生成PDF时跨页表格内容褪色问题求助
问题:iTextPDF生成PDF时跨页表格内容颜色变淡
使用iTextPDF生成PDF时,表格内容延伸到下一页后显示颜色变淡。生成4页PDF时,第1页和第4页显示正常,但第2、3页的表格内容明显褪色。
使用的是单页PDF模板,需要复制模板页面,事件监听器无法自动复制到第二页,因此手动复制了第一页,后续监听器可正常工作,但仍存在表格内容褪色问题。
相关代码
public class PdfGenerator { public static void main(String[] args) throws IOException { ClassPathResource templateResource = new ClassPathResource("RandomTemplate.pdf"); File pdfFile = new File(templateResource.getFile().getAbsolutePath()); CustomEventHandler eventHandler = null; try (PdfReader pdfReader = new PdfReader(pdfFile); ) { ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); PdfWriter pdfWriter = new PdfWriter(outputStream); PdfDocument targetDocument = new PdfDocument(pdfReader, pdfWriter); PdfReader pdfReader2 = new PdfReader(pdfFile); PdfDocument sourceDocument = new PdfDocument(pdfReader2); eventHandler = new CustomEventHandler(sourceDocument); targetDocument.addEventHandler(PdfDocumentEvent.END_PAGE, eventHandler); Document document = new Document(targetDocument); document.setMargins(95, 24, 100, 24); sourceDocument.copyPagesTo(1, 1, targetDocument); for (int i = 0; i < 3; i++) { Table table = new Table(4); table.addHeaderCell(new Cell(1, 4).add(new Paragraph("Random Header Title")).setBold().setPaddingLeft(5).setBorderLeft(new SolidBorder(3))); table.addHeaderCell(new Cell().add(new Paragraph("RANDOM DATE")).setBold().setPaddingLeft(5).setBorderRight(Border.NO_BORDER).setBorderLeft(Border.NO_BORDER).setBorderBottom(Border.NO_BORDER)); table.addHeaderCell(new Cell().add(new Paragraph("RANDOM MEASUREMENT")).setBold().setPaddingLeft(5).setBorderRight(Border.NO_BORDER).setBorderLeft(Border.NO_BORDER).setBorderBottom(Border.NO_BORDER)); table.addHeaderCell(new Cell().add(new Paragraph("RANDOM PERCENTILE")).setBold().setPaddingLeft(5).setBorderRight(Border.NO_BORDER).setBorderLeft(Border.NO_BORDER).setBorderBottom(Border.NO_BORDER)).setFontSize(7); table.addHeaderCell(new Cell().add(new Paragraph("RANDOM SCORE")).setBold().setPaddingLeft(5).setBorderRight(Border.NO_BORDER).setBorderLeft(Border.NO_BORDER).setBorderBottom(Border.NO_BORDER)); for (int j = 0; j < 50; j++) { table.addCell(new Cell().add(new Paragraph("dd/mm/yyyy")).setPaddingLeft(5).setBorderRight(Border.NO_BORDER).setBorderLeft(Border.NO_BORDER).setBorderTop(Border.NO_BORDER)); table.addCell(new Cell().add(new Paragraph(String.valueOf(j + 1))).setPaddingLeft(5).setBorderRight(Border.NO_BORDER).setBorderLeft(Border.NO_BORDER).setBorderTop(Border.NO_BORDER)); table.addCell(new Cell().add(new Paragraph("#.#%")).setPaddingLeft(5).setBorderRight(Border.NO_BORDER).setBorderLeft(Border.NO_BORDER).setBorderTop(Border.NO_BORDER)).setFontSize(8); table.addCell(new Cell().add(new Paragraph("#.##")).setPaddingLeft(5).setBorderRight(Border.NO_BORDER).setBorderLeft(Border.NO_BORDER).setBorderTop(Border.NO_BORDER)); } table.setBorder(new SolidBorder(1)); table.setWidth(767); table.setMarginTop(20); document.add(table); } targetDocument.removeEventHandler(PdfDocumentEvent.END_PAGE, eventHandler); document.close(); targetDocument.close(); byte[] finalPdfBytes = outputStream.toByteArray(); FileOutputStream fileOutputStream = new FileOutputStream("FinalRandomOutput.pdf"); fileOutputStream.write(finalPdfBytes); fileOutputStream.close(); } catch (IOException e) { e.printStackTrace(); } } static class CustomEventHandler implements IEventHandler { private final PdfDocument sourceDocument; public CustomEventHandler(PdfDocument sourceDocument) { this.sourceDocument = sourceDocument; } @Override public void handleEvent(Event event) { System.out.println("Event Triggered"); PdfDocumentEvent documentEvent = (PdfDocumentEvent) event; PdfDocument pdfDocument = documentEvent.getDocument(); PdfPage originalPage = sourceDocument.getPage(1); pdfDocument.addPage(originalPage.copyTo(pdfDocument)); } } }
问题原因分析
你的CustomEventHandler在END_PAGE事件触发时,直接将模板页面添加到目标文档末尾,而不是为新页面设置模板背景。这会导致:
- 当表格内容触发分页时,iText会自动创建新的空白页,之后事件监听器又添加了一个模板页,相当于在表格所在的空白页后插入模板页。
- 表格内容被渲染在无模板的空白页上,和有模板背景的第1、4页形成视觉对比,看起来颜色变淡。
解决方案
正确的做法是在新页面创建时,将模板页面的内容作为背景绘制到当前页面,而不是直接添加新的模板页。
修改后的事件处理器
static class CustomEventHandler implements IEventHandler { private final PdfDocument sourceDocument; public CustomEventHandler(PdfDocument sourceDocument) { this.sourceDocument = sourceDocument; } @Override public void handleEvent(Event event) { PdfDocumentEvent documentEvent = (PdfDocumentEvent) event; PdfDocument pdfDocument = documentEvent.getDocument(); PdfPage currentPage = documentEvent.getPage(); PdfPage originalPage = sourceDocument.getPage(1); // 获取当前页面的底层画布,将模板内容作为背景绘制 PdfCanvas canvas = new PdfCanvas(currentPage.newContentStreamBefore(), currentPage.getResources(), pdfDocument); // 复制模板页面内容到当前页面 originalPage.copyAsFormXObject(pdfDocument).copyToCanvas(canvas, new AffineTransform()); } }
主方法对应修改
// 将事件监听改为START_PAGE,在页面创建时就设置背景 targetDocument.addEventHandler(PdfDocumentEvent.START_PAGE, eventHandler); // 移除手动复制模板页的代码,START_PAGE事件会自动处理所有页面 // sourceDocument.copyPagesTo(1, 1, targetDocument); // 直接创建文档并添加表格内容 Document document = new Document(targetDocument); document.setMargins(95, 24, 100, 24); // 表格添加逻辑保持不变 for (int i = 0; i < 3; i++) { // ...原表格代码 }
额外注意事项
- 确保模板页面尺寸和目标文档页面尺寸一致,避免背景错位。
- 移除原
END_PAGE事件的页面添加逻辑,避免重复创建页面。 - 文档关闭只需调用
document.close()即可,它会自动关联关闭PdfDocument。
这样修改后,所有页面都会自动应用模板背景,表格内容无论在第几页都会和背景正确叠加,不会出现颜色变淡的问题。
内容的提问来源于stack exchange,提问作者user26321118
相关产品推荐
相关产品推荐

