first commit
This commit is contained in:
@@ -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('.'));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user