package com.example.sso.dao; import com.itextpdf.io.image.ImageData; import com.itextpdf.io.image.ImageDataFactory; import com.itextpdf.kernel.colors.DeviceRgb; import com.itextpdf.kernel.font.PdfFont; import com.itextpdf.kernel.font.PdfFontFactory; import com.itextpdf.kernel.geom.PageSize; import com.itextpdf.kernel.geom.Rectangle; import com.itextpdf.kernel.pdf.PdfDocument; import com.itextpdf.kernel.pdf.PdfWriter; import com.itextpdf.kernel.pdf.canvas.PdfCanvas; import com.itextpdf.layout.Canvas; import com.itextpdf.layout.Document; import com.itextpdf.layout.element.Image; import com.itextpdf.layout.element.Paragraph; import com.itextpdf.layout.properties.TextAlignment; import com.itextpdf.layout.properties.VerticalAlignment; import com.itextpdf.kernel.events.PdfDocumentEvent; import com.itextpdf.kernel.events.IEventHandler; import com.itextpdf.kernel.events.Event; import java.io.File; import java.io.IOException; import java.util.ArrayList; import java.util.List; public class Photo { // 使用 ThreadLocal 存储每个线程的独立变量 private static final ThreadLocal pdfDocThreadLocal = new ThreadLocal<>(); private static final ThreadLocal documentThreadLocal = new ThreadLocal<>(); private static final ThreadLocal currentPdfPathThreadLocal = new ThreadLocal<>(); private static final ThreadLocal chineseFontThreadLocal = new ThreadLocal<>(); // 存储每页的页脚文本(使用ThreadLocal确保线程安全) private static final ThreadLocal> footerTextsThreadLocal = new ThreadLocal<>(); // 页脚文本类 private static class FooterText { String text; float x; float y; DeviceRgb color; FooterText(String text, float x, float y, DeviceRgb color) { this.text = text; this.x = x; this.y = y; this.color = color; } } // 页脚事件处理器 private static class FooterEventHandler implements IEventHandler { @Override public void handleEvent(Event event) { PdfDocumentEvent docEvent = (PdfDocumentEvent) event; PdfCanvas canvas = new PdfCanvas(docEvent.getPage()); Rectangle pageSize = docEvent.getPage().getPageSize(); // 获取当前线程的字体和页脚文本 PdfFont chineseFont = chineseFontThreadLocal.get(); List footerTexts = footerTextsThreadLocal.get(); if (chineseFont == null || footerTexts == null || footerTexts.isEmpty()) { canvas.release(); return; } // 创建Canvas用于绘制 Canvas pageCanvas = new Canvas(canvas, pageSize); // 绘制所有页脚文本 for (FooterText footerText : footerTexts) { Paragraph paragraph = new Paragraph(footerText.text) .setFont(chineseFont) .setFontSize(12); if (footerText.color != null) { paragraph.setFontColor(footerText.color); } // 在指定位置绘制文本 pageCanvas.showTextAligned( paragraph, footerText.x, footerText.y, TextAlignment.LEFT, VerticalAlignment.BOTTOM ); } canvas.release(); } } /** * 开始创建PDF */ public static void startPDF(String pdfPath) throws IOException { // 获取当前线程的变量 PdfDocument pdfDoc = pdfDocThreadLocal.get(); Document document = documentThreadLocal.get(); // 如果已经存在,先关闭 if (pdfDoc != null || document != null) { closePDF(); } // 创建新的PDF文档 currentPdfPathThreadLocal.set(pdfPath); PdfWriter writer = new PdfWriter(pdfPath); pdfDoc = new PdfDocument(writer); // 注册页脚事件处理器 FooterEventHandler footerHandler = new FooterEventHandler(); pdfDoc.addEventHandler(PdfDocumentEvent.END_PAGE, footerHandler); // 使用标准A4纸 document = new Document(pdfDoc, PageSize.A4, false); document.setMargins(0, 0, 0, 0); // 初始化中文字体 PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); // 初始化页脚文本列表 footerTextsThreadLocal.set(new ArrayList<>()); // 保存到ThreadLocal pdfDocThreadLocal.set(pdfDoc); documentThreadLocal.set(document); chineseFontThreadLocal.set(chineseFont); System.out.println(Thread.currentThread().getName() + " 开始创建PDF: " + pdfPath); } /** * 设置页脚文本(会在每一页底部显示) */ public static void setFooterText(String text) throws IOException { Document document = documentThreadLocal.get(); PdfFont chineseFont = chineseFontThreadLocal.get(); if (document == null) { throw new IllegalStateException("请先调用 startPDF() 方法"); } if (chineseFont == null) { chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); chineseFontThreadLocal.set(chineseFont); } // 获取页脚文本列表 List footerTexts = footerTextsThreadLocal.get(); if (footerTexts == null) { footerTexts = new ArrayList<>(); footerTextsThreadLocal.set(footerTexts); } // 清空原有页脚,添加新的页脚文本 footerTexts.clear(); footerTexts.add(new FooterText(text, 50F, 30F, (DeviceRgb) DeviceRgb.BLACK)); System.out.println(Thread.currentThread().getName() + " 已设置页脚文本: " + text); } /** * 添加图片章节 */ public static void appendImageSection(String imagePath) throws IOException { Document document = documentThreadLocal.get(); if (document == null) { throw new IllegalStateException("请先调用 startPDF() 方法"); } // 添加图片 if (imagePath != null && new File(imagePath).exists()) { ImageData imageData = ImageDataFactory.create(imagePath); Image image = new Image(imageData); image.setHorizontalAlignment(com.itextpdf.layout.properties.HorizontalAlignment.CENTER); image.setMarginTop(5); image.setMarginBottom(5); image.setHeight(200); image.setWidth(200); document.add(image); } System.out.println(Thread.currentThread().getName() + " 已添加图片章节"); } /** * 添加文本章节 */ public static void appendTextSection(String text) throws IOException { Document document = documentThreadLocal.get(); PdfFont chineseFont = chineseFontThreadLocal.get(); if (document == null) { throw new IllegalStateException("请先调用 startPDF() 方法"); } if (chineseFont == null) { chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); chineseFontThreadLocal.set(chineseFont); } document.add(new Paragraph(text) .setFont(chineseFont) .setFontSize(20) .setBold() .setMarginTop(20)); System.out.println(Thread.currentThread().getName() + " 已添加文本章节"); } public static void TextAlignment(String text) throws IOException { Document document = documentThreadLocal.get(); PdfFont chineseFont = chineseFontThreadLocal.get(); if (document == null) { throw new IllegalStateException("请先调用 startPDF() 方法"); } if (chineseFont == null) { chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); chineseFontThreadLocal.set(chineseFont); } // 创建段落并设置居中对齐 Paragraph paragraph = new Paragraph(text) .setFont(chineseFont) .setFontSize(20) .setBold() .setMarginTop(20) .setTextAlignment(TextAlignment.CENTER); document.add(paragraph); System.out.println(Thread.currentThread().getName() + " 已添加文本章节"); } public static void appendTextSections(String text) throws IOException { Document document = documentThreadLocal.get(); PdfFont chineseFont = chineseFontThreadLocal.get(); if (document == null) { throw new IllegalStateException("请先调用 startPDF() 方法"); } if (chineseFont == null) { chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); chineseFontThreadLocal.set(chineseFont); } List footerTexts = footerTextsThreadLocal.get(); if (footerTexts == null) { footerTexts = new ArrayList<>(); footerTextsThreadLocal.set(footerTexts); } // 添加白色文本 footerTexts.add(new FooterText(text, 475F, 25f, (DeviceRgb) DeviceRgb.WHITE)); System.out.println(Thread.currentThread().getName() + " 已添加白色页脚文本: " + text); } public static void appendTextSections1(String text) throws IOException { Document document = documentThreadLocal.get(); PdfFont chineseFont = chineseFontThreadLocal.get(); if (document == null) { throw new IllegalStateException("请先调用 startPDF() 方法"); } if (chineseFont == null) { chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); chineseFontThreadLocal.set(chineseFont); } List footerTexts = footerTextsThreadLocal.get(); if (footerTexts == null) { footerTexts = new ArrayList<>(); footerTextsThreadLocal.set(footerTexts); } // 添加黑色文本 footerTexts.add(new FooterText(text, 310f, 25f, null)); System.out.println(Thread.currentThread().getName() + " 已添加黑色页脚文本: " + text); } public static void appendTextSectionss(String text) throws IOException { Document document = documentThreadLocal.get(); PdfFont chineseFont = chineseFontThreadLocal.get(); if (document == null) { throw new IllegalStateException("请先调用 startPDF() 方法"); } if (chineseFont == null) { chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); chineseFontThreadLocal.set(chineseFont); } List footerTexts = footerTextsThreadLocal.get(); if (footerTexts == null) { footerTexts = new ArrayList<>(); footerTextsThreadLocal.set(footerTexts); } // 添加白色文本 footerTexts.add(new FooterText(text, 400F, 50F, (DeviceRgb) DeviceRgb.WHITE)); System.out.println(Thread.currentThread().getName() + " 已添加白色页脚文本: " + text); } public static void appendTextSectionss1(String text) throws IOException { Document document = documentThreadLocal.get(); PdfFont chineseFont = chineseFontThreadLocal.get(); if (document == null) { throw new IllegalStateException("请先调用 startPDF() 方法"); } if (chineseFont == null) { chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); chineseFontThreadLocal.set(chineseFont); } List footerTexts = footerTextsThreadLocal.get(); if (footerTexts == null) { footerTexts = new ArrayList<>(); footerTextsThreadLocal.set(footerTexts); } // 添加黑色文本 footerTexts.add(new FooterText(text, 310, 50, null)); System.out.println(Thread.currentThread().getName() + " 已添加黑色页脚文本: " + text); } /** * 添加分页符 */ public static void addPageBreak() { Document document = documentThreadLocal.get(); if (document != null) { document.add(new com.itextpdf.layout.element.AreaBreak()); System.out.println(Thread.currentThread().getName() + " 已添加分页符"); } } /** * 关闭并保存PDF */ public static void closePDF() { // 获取当前线程的变量 Document document = documentThreadLocal.get(); PdfDocument pdfDoc = pdfDocThreadLocal.get(); String currentPdfPath = currentPdfPathThreadLocal.get(); PdfFont chineseFont = chineseFontThreadLocal.get(); if (document != null) { document.close(); documentThreadLocal.remove(); } if (pdfDoc != null) { pdfDoc.close(); pdfDocThreadLocal.remove(); } if (chineseFont != null) { chineseFontThreadLocal.remove(); } if (currentPdfPath != null) { System.out.println(Thread.currentThread().getName() + " PDF已保存: " + currentPdfPath); currentPdfPathThreadLocal.remove(); } } /** * 快速使用示例 */ public static void createPDFWithMultipleSections(String pdfPath) throws IOException { startPDF(pdfPath); try { // 添加各种内容 appendTextSection("这是文档的第一部分\n包含一些介绍性的文字"); appendImageSection("image1.jpg"); appendTextSection("这是图片1的描述文字"); appendImageSection("image2.png"); appendTextSection("这是图片2的描述文字"); } finally { // 确保资源被释放 closePDF(); } } public static void createSimpleChinesePDF() throws IOException { // 这个方法不使用ThreadLocal变量,因为它自己创建PDF // 1. 创建PDF PdfWriter writer = new PdfWriter("D:\\下载模板\\a.pdf"); PdfDocument pdfDoc = new PdfDocument(writer); Document document = new Document(pdfDoc); // 2. 加载中文字体(必须要有font-asian依赖) PdfFont chineseFont = PdfFontFactory.createFont("STSong-Light", "UniGB-UCS2-H"); // 3. 添加中文内容 Paragraph title = new Paragraph("中文标题") .setFont(chineseFont) .setFontSize(20) .setBold(); document.add(title); Paragraph content = new Paragraph("这是中文内容,可以正常显示。") .setFont(chineseFont) .setFontSize(12); document.add(content); // 4. 关闭文档 document.close(); pdfDoc.close(); System.out.println("PDF创建完成"); } /** * 测试多线程并发 */ }