package com.smppw.modaq.infrastructure.util; import cn.hutool.core.collection.ListUtil; import cn.hutool.core.io.FileUtil; import org.apache.pdfbox.Loader; import org.apache.pdfbox.io.RandomAccessReadBufferedFile; import org.apache.pdfbox.pdmodel.PDDocument; import org.apache.pdfbox.rendering.PDFRenderer; //import org.docx4j.Docx4J; //import org.docx4j.openpackaging.packages.OpcPackage; //import org.docx4j.openpackaging.packages.WordprocessingMLPackage; import javax.imageio.ImageIO; import java.awt.*; import java.awt.image.BufferedImage; import java.io.*; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.List; public class PdfUtil { // public static void validateDocx(String path) throws Exception { // File file = new File(path); // // // 基础检查 // if (!file.exists()) throw new FileNotFoundException("文件不存在"); // if (!file.canRead()) throw new IOException("无读取权限"); // if (file.length() == 0) throw new IOException("文件为空"); // // // 文件头检查 // try (InputStream is = new FileInputStream(file)) { // byte[] header = new byte[4]; // if (is.read(header) < 4) throw new IOException("文件过小"); // if (header[0] != 0x50 || header[1] != 0x4B) { // PK 头 // throw new IOException("不是ZIP格式文件"); // } // } // // // 尝试作为ZIP打开 // try (java.util.zip.ZipFile zip = new java.util.zip.ZipFile(file)) { // if (zip.getEntry("[Content_Types].xml") == null) { // throw new IOException("缺少[Content_Types].xml"); // } // } catch (IOException e) { // throw new IOException("无效的ZIP格式: " + e.getMessage()); // } // } // public static void convertDocxToPdf(String input, String output) throws Exception { // validateDocx(input); // try (OutputStream os = new FileOutputStream(output)) { // OpcPackage opc = OpcPackage.load(new File(input)); // if (opc instanceof WordprocessingMLPackage) { // Docx4J.toPDF((WordprocessingMLPackage) opc, os); // } else { // throw new Exception("不是WordprocessingML文档"); // } // } // } /** * 将 PDF 的首页和尾页转换为 PNG 图片 * * @param pdfFilepath 输入的 PDF 文件 * @param outputDir 输出目录 * @param dpi 图片分辨率(默认建议 300) * @return 生成的图片文件列表 */ public static List convertFirstAndLastPagesToPng(String pdfFilepath, File outputDir, int dpi) throws IOException { List generatedImages = ListUtil.list(false); try (PDDocument document = Loader.loadPDF(new RandomAccessReadBufferedFile(pdfFilepath))) { int totalPages = document.getNumberOfPages(); if (totalPages == 0) { throw new IOException("PDF 文件无有效页面"); } // 准备输出目录 if (!outputDir.exists() && !outputDir.mkdirs()) { throw new IOException("无法创建输出目录: " + outputDir); } String baseName = FileUtil.mainName(pdfFilepath); PDFRenderer renderer = new PDFRenderer(document); // 始终处理首页(页码从1开始) String firstImg = renderPage(renderer, 0, baseName + ".png", outputDir, dpi); generatedImages.add(compressAndSave(firstImg)); // 处理尾页(当总页数 > 1 时) if (totalPages > 1) { String lastImg = renderPage(renderer, totalPages - 1, baseName + "_footer.png", outputDir, dpi); generatedImages.add(compressAndSave(lastImg)); } } return generatedImages; } /** * 渲染单页并保存为图片 */ private static String renderPage(PDFRenderer renderer, int pageIndex, String fileName, File outputDir, int dpi) throws IOException { BufferedImage image = renderer.renderImageWithDPI(pageIndex, dpi); File outputFile = new File(outputDir, fileName); ImageIO.write(image, "PNG", outputFile); return outputFile.getAbsolutePath(); } /** * 检查图片分辨率是否超过限制 * * @param image 图片对象 * @param maxSize 最大允许尺寸(单边像素数) * @return 是否超出限制 */ private static boolean isResolutionExceeded(BufferedImage image, int maxSize) { return image.getWidth() > maxSize || image.getHeight() > maxSize; } // /** // * 压缩图片并转换为Base64 // * // * @param inputFile 输入图片文件 // * @param maxSize 最大允许尺寸(单边像素数) // * @param quality 压缩质量 (0.0-1.0) // * @param format 输出格式 ("jpg", "png"等) // * @return Base64编码的图片数据 // */ // public static String compressAndConvertToBase64(File inputFile, int maxSize, float quality, String format) // throws IOException { // // // 读取原始图片 // BufferedImage originalImage = ImageIO.read(inputFile); // // // 检查分辨率是否超出限制 // if (!isResolutionExceeded(originalImage, maxSize)) { // System.out.println("图片尺寸符合要求,无需压缩"); // } // // // 计算新尺寸(保持宽高比) // int originalWidth = originalImage.getWidth(); // int originalHeight = originalImage.getHeight(); // double ratio = (double) maxSize / Math.max(originalWidth, originalHeight); // int newWidth = (int) (originalWidth * ratio); // int newHeight = (int) (originalHeight * ratio); // // // 创建缩放后的图片 // Image scaledImage = originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH); // BufferedImage outputImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB); // // // 绘制缩放后的图片 // Graphics2D g2d = outputImage.createGraphics(); // g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); // g2d.drawImage(scaledImage, 0, 0, null); // g2d.dispose(); // // // 转换为Base64 // ByteArrayOutputStream baos = new ByteArrayOutputStream(); // ImageIO.write(outputImage, format, baos); // byte[] imageBytes = baos.toByteArray(); // // return Base64.getEncoder().encodeToString(imageBytes); // } public static String compressAndSave(String inputFile) throws IOException { return compressAndSave(FileUtil.file(inputFile)); } public static String compressAndSave(File inputFile) throws IOException { int maxSize = 8192; String format = FileUtil.extName(inputFile); return compressAndSave(inputFile, null, maxSize, format); } /** * 压缩图片并保存到文件 * * @param inputFile 输入文件 * @param outputFile 输出文件 * @param maxSize 最大尺寸 * @param format 输出格式 */ public static String compressAndSave(File inputFile, File outputFile, int maxSize, String format) throws IOException { BufferedImage originalImage = ImageIO.read(inputFile); if (!isResolutionExceeded(originalImage, maxSize)) { if (outputFile != null) { // 直接复制文件 Files.copy(inputFile.toPath(), outputFile.toPath(), StandardCopyOption.REPLACE_EXISTING); return outputFile.getAbsolutePath(); } return inputFile.getAbsolutePath(); } if (outputFile == null) { outputFile = inputFile; } int originalWidth = originalImage.getWidth(); int originalHeight = originalImage.getHeight(); double ratio = (double) maxSize / Math.max(originalWidth, originalHeight); int newWidth = (int) (originalWidth * ratio); int newHeight = (int) (originalHeight * ratio); Image scaledImage = originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH); BufferedImage outputImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB); Graphics2D g2d = outputImage.createGraphics(); g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR); g2d.drawImage(scaledImage, 0, 0, null); g2d.dispose(); // 保存到文件 ImageIO.write(outputImage, format, outputFile); return outputFile.getAbsolutePath(); } public static void main(String[] args) { try { // 示例用法 File inputFile = new File("D:\\home\\wwwroot\\daq_report_file\\wangzaijun@simuwang.com\\20250605\\image\\泓湖泓福积极配置2期私募证券投资基金-周报-20250530.png"); int maxSize = 8192; // OpenAI限制 // 1. 检查图片是否超出限制 BufferedImage image = ImageIO.read(inputFile); if (isResolutionExceeded(image, maxSize)) { System.out.println("图片超出尺寸限制,需要压缩"); System.out.println("原始尺寸: " + image.getWidth() + "x" + image.getHeight()); // // 2. 压缩并转换为Base64 // String base64Image = compressAndConvertToBase64(inputFile, maxSize, 0.85f, "png"); // System.out.println("Base64 数据长度: " + base64Image.length()); // System.out.println("Base64 前缀: " + base64Image.substring(0, 50) + "..."); // 3. 压缩并保存到文件 File outputFile = new File("D:\\home\\wwwroot\\daq_report_file\\wangzaijun@simuwang.com\\20250605\\image\\泓湖泓福积极配置2期私募证券投资基金-周报-20250530.png"); String output = compressAndSave(inputFile, outputFile, maxSize, "png"); System.out.println("图片已压缩保存到: " + output); // 验证压缩后尺寸 BufferedImage compressedImage = ImageIO.read(outputFile); System.out.println("压缩后尺寸: " + compressedImage.getWidth() + "x" + compressedImage.getHeight()); } else { System.out.println("图片尺寸符合要求"); } } catch (IOException e) { e.printStackTrace(); } } }