first commit

This commit is contained in:
2026-01-30 14:25:12 +08:00
commit 8dd8d2668a
899 changed files with 90844 additions and 0 deletions

View File

@@ -0,0 +1,206 @@
package com.qingyun.service.utils;
import cn.hutool.http.HttpUtil;
import com.documents4j.api.DocumentType;
import com.documents4j.api.IConverter;
import com.documents4j.job.LocalConverter;
import com.qingyun.common.config.QingYunConfig;
import com.qingyun.common.utils.file.FileUploadUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.ImageType;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
@Component
public class PdfUtil {
@Value("${server.port}")
private String port;
/**
* @param source 原文件
* @param desFilePath 生成图片的路径
* @param desFileName 生成图片的名称(多页文档时会变成:名称+下划线+从1开始的数字
* @return
*/
public Pair<Boolean, Object> pdfToImage(File source, String desFilePath, String desFileName) throws IOException {
//通过给定的源路径名字符串创建一个File实例
if (!source.exists()) {
return Pair.of(false, "文件不存在,无法转化");
}
//目录不存在则创建目录
File destination = new File(desFilePath);
if (!destination.exists()) {
boolean flag = destination.mkdirs();
System.out.println("创建文件夹结果:" + flag);
}
PDDocument doc = null;
try {
//加载PDF文件
doc = Loader.loadPDF(source);
PDFRenderer renderer = new PDFRenderer(doc);
//获取PDF文档的页数
int pageCount = doc.getNumberOfPages();
System.out.println("文档一共" + pageCount + "");
List<Object> fileList = new ArrayList<>();
for (int i = 0; i < pageCount; i++) {
// 只有一页的时候文件名为传入的文件名大于一页的文件名为文件名_自增加数字(从1开始)
String realFileName = pageCount > 1 ? desFileName + "_" + (i + 1) : desFileName;
// 每一页通过分辨率和颜色值进行转化
BufferedImage bufferedImage = renderer.renderImageWithDPI(i, 150, ImageType.RGB);
String relativePath = FileUploadUtils.getPathFileName(QingYunConfig.getUploadPath() + "/" + desFilePath, realFileName + "." + "png");
String filePath = QingYunConfig.getUploadPath() + "/" + desFilePath + "/" + realFileName + "." + "png";
// 确保目录存在
File imageFile = new File(filePath);
if (!imageFile.getParentFile().exists()) {
boolean mkdirs = imageFile.getParentFile().mkdirs(); // 创建父目录
if (!mkdirs) {
return Pair.of(false, "无法创建目录:" + imageFile.getParentFile().getAbsolutePath());
}
}
// 写入文件
ImageIO.write(bufferedImage, "png", imageFile);
// 文件名存入 list
fileList.add(relativePath);
}
return Pair.of(true, fileList);
} catch (IOException e) {
e.printStackTrace();
return Pair.of(false, "PDF转化图片异常");
} finally {
try {
if (doc != null) {
doc.close();
}
} catch (IOException e) {
System.out.println("关闭文档失败");
e.printStackTrace();
}
}
}
public File downloadFile(String pdfUrl, String name) throws IOException {
// name 去掉文件后缀
String newName = name.substring(0, name.lastIndexOf("."));
String projectUrl = QingYunConfig.getProjectUrl();
File tempFile = File.createTempFile(newName + System.currentTimeMillis(), getFileExtension(name));
long file = HttpUtil.downloadFile(projectUrl + pdfUrl, tempFile);
if (file <= 0) {
throw new IOException("无法下载 PDF 文件");
}
return tempFile;
}
public File convertWordToPdf(File wordFile) throws IOException, InterruptedException {
if (!wordFile.exists() || !wordFile.isFile()) {
throw new IOException("Word文件不存在或无效: " + wordFile.getAbsolutePath());
}
String osName = System.getProperty("os.name").toLowerCase();
if (osName.contains("win")) {
// Windows 系统使用 Apache POI 实现 Word 转 PDF
return convertWordToPdfWindows(wordFile);
} else {
// Linux 或其他系统使用 LibreOffice 实现 Word 转 PDF
return convertWordToPdfLinux(wordFile);
}
}
private File convertWordToPdfWindows(File wordFile) throws IOException {
File outputFile = new File(wordFile.getParent(),
FilenameUtils.getBaseName(wordFile.getName()) + ".pdf");
try {
IConverter converter = LocalConverter.builder().build();
Future<Boolean> conversion = converter
.convert(wordFile).as(DocumentType.MS_WORD)
.to(outputFile).as(DocumentType.PDF)
.prioritizeWith(1000) // optional
.schedule();
conversion.get(); // 这里会阻塞直到转换完成
return outputFile;
} catch (Exception e) {
throw new IOException("Word 转 PDF 失败: " + e.getMessage(), e);
}
}
private File convertWordToPdfLinux(File wordFile) throws IOException, InterruptedException {
// 保留现有的 Linux 实现逻辑
if (!isLibreOfficeInstalled()) {
throw new IOException("LibreOffice未安装! 请先执行: sudo apt-get install libreoffice");
}
File outputDir = wordFile.getParentFile();
String pdfName = FilenameUtils.getBaseName(wordFile.getName()) + ".pdf";
File outputFile = new File(outputDir, pdfName);
ProcessBuilder pb = new ProcessBuilder(
"/usr/bin/soffice",
"--headless",
"--convert-to", "pdf",
"--outdir", outputDir.getAbsolutePath(),
wordFile.getAbsolutePath()
);
pb.redirectErrorStream(true);
pb.redirectOutput(ProcessBuilder.Redirect.INHERIT);
Process process = pb.start();
boolean completed = process.waitFor(5, TimeUnit.MINUTES);
if (!completed) {
process.destroyForcibly();
throw new IOException("转换超时5分钟");
}
if (process.exitValue() != 0) {
throw new IOException("LibreOffice转换失败错误码: " + process.exitValue());
}
if (!outputFile.exists() || outputFile.length() == 0) {
throw new IOException("PDF文件未生成或为空");
}
return outputFile;
}
private boolean isLibreOfficeInstalled() {
try {
Process p = Runtime.getRuntime().exec("which soffice");
return p.waitFor(2, TimeUnit.SECONDS) && p.exitValue() == 0;
} catch (Exception e) {
return false;
}
}
/**
* 获取文件扩展名
* @param fileName 文件名
* @return 文件扩展名(包括点号)
*/
private String getFileExtension(String fileName) {
if (fileName == null || fileName.lastIndexOf('.') == -1) {
return ""; // 没有扩展名
}
return fileName.substring(fileName.lastIndexOf('.'));
}
}