mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-04-11 02:37:09 +00:00
cad pdf转换模块提取独立 优化多线程转换方法
This commit is contained in:
@@ -4,32 +4,18 @@ import cn.keking.config.ConfigConstants;
|
||||
import cn.keking.model.FileAttribute;
|
||||
import cn.keking.model.FileType;
|
||||
import cn.keking.service.cache.CacheService;
|
||||
import cn.keking.service.cache.NotResourceCache;
|
||||
import cn.keking.utils.*;
|
||||
import cn.keking.web.filter.BaseUrlFilter;
|
||||
import com.aspose.cad.*;
|
||||
import com.aspose.cad.fileformats.cad.CadDrawTypeMode;
|
||||
import com.aspose.cad.fileformats.tiff.enums.TiffExpectedFormat;
|
||||
import com.aspose.cad.imageoptions.*;
|
||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||
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.apache.pdfbox.tools.imageio.ImageIOUtil;
|
||||
import org.apache.poi.EncryptedDocumentException;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.InitializingBean;
|
||||
import org.springframework.beans.factory.annotation.Value;
|
||||
import org.springframework.context.annotation.DependsOn;
|
||||
import org.springframework.stereotype.Component;
|
||||
import org.springframework.util.CollectionUtils;
|
||||
import org.springframework.util.ObjectUtils;
|
||||
import org.springframework.util.StringUtils;
|
||||
|
||||
import jakarta.servlet.http.HttpServletRequest;
|
||||
import java.awt.image.BufferedImage;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URLDecoder;
|
||||
import java.net.URLEncoder;
|
||||
@@ -38,7 +24,6 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.stream.IntStream;
|
||||
|
||||
/**
|
||||
@@ -47,10 +32,10 @@ import java.util.stream.IntStream;
|
||||
*/
|
||||
@Component
|
||||
@DependsOn(ConfigConstants.BEAN_NAME)
|
||||
public class FileHandlerService implements InitializingBean {
|
||||
public class FileHandlerService {
|
||||
|
||||
private static final String PDF2JPG_IMAGE_FORMAT = ".jpg";
|
||||
private static final String PDF_PASSWORD_MSG = "password";
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(FileHandlerService.class);
|
||||
private final String fileDir = ConfigConstants.getFileDir();
|
||||
private final CacheService cacheService;
|
||||
@@ -144,15 +129,6 @@ public class FileHandlerService implements InitializingBean {
|
||||
cacheService.putImgCache(fileKey, imgs);
|
||||
}
|
||||
|
||||
/**
|
||||
* cad定义线程池
|
||||
*/
|
||||
private ExecutorService pool = null;
|
||||
|
||||
@Override
|
||||
public void afterPropertiesSet() throws Exception {
|
||||
pool = Executors.newFixedThreadPool(ConfigConstants.getCadThread());
|
||||
}
|
||||
|
||||
/**
|
||||
* 对转换后的文件进行操作(改变编码方式)
|
||||
@@ -192,7 +168,7 @@ public class FileHandlerService implements InitializingBean {
|
||||
* @param index 图片索引
|
||||
* @return 图片访问地址
|
||||
*/
|
||||
private String getPdf2jpgUrl(String pdfFilePath, int index) {
|
||||
public String getPdf2jpgUrl(String pdfFilePath, int index) {
|
||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||
pdfFilePath = pdfFilePath.replace(fileDir, "");
|
||||
String pdfFolder = pdfFilePath.substring(0, pdfFilePath.length() - 4);
|
||||
@@ -214,230 +190,20 @@ public class FileHandlerService implements InitializingBean {
|
||||
* @param pdfFilePath pdf文件路径
|
||||
* @return 图片访问集合
|
||||
*/
|
||||
private List<String> loadPdf2jpgCache(String pdfFilePath) {
|
||||
public List<String> loadPdf2jpgCache(String pdfFilePath) { // 移除 static 修饰符
|
||||
List<String> imageUrls = new ArrayList<>();
|
||||
Integer imageCount = this.getPdf2jpgCache(pdfFilePath);
|
||||
Integer imageCount = this.getPdf2jpgCache(pdfFilePath); // 使用 this. 调用
|
||||
if (Objects.isNull(imageCount)) {
|
||||
return imageUrls;
|
||||
}
|
||||
IntStream.range(0, imageCount).forEach(i -> {
|
||||
String imageUrl = this.getPdf2jpgUrl(pdfFilePath, i);
|
||||
String imageUrl = this.getPdf2jpgUrl(pdfFilePath, i); // 使用 this. 调用
|
||||
imageUrls.add(imageUrl);
|
||||
});
|
||||
return imageUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* pdf文件转换成jpg图片集
|
||||
* fileNameFilePath pdf文件路径
|
||||
* pdfFilePath pdf输出文件路径
|
||||
* pdfName pdf文件名称
|
||||
* loadPdf2jpgCache 图片访问集合
|
||||
*/
|
||||
public List<String> pdf2jpg(String fileNameFilePath, String pdfFilePath, String pdfName, FileAttribute fileAttribute) throws Exception {
|
||||
boolean forceUpdatedCache = fileAttribute.forceUpdatedCache();
|
||||
boolean usePasswordCache = fileAttribute.getUsePasswordCache();
|
||||
String filePassword = fileAttribute.getFilePassword();
|
||||
PDDocument doc;
|
||||
final String[] pdfPassword = {null};
|
||||
final int[] pageCount = new int[1];
|
||||
if (!forceUpdatedCache) {
|
||||
List<String> cacheResult = this.loadPdf2jpgCache(pdfFilePath);
|
||||
if (!CollectionUtils.isEmpty(cacheResult)) {
|
||||
return cacheResult;
|
||||
}
|
||||
}
|
||||
List<String> imageUrls = new ArrayList<>();
|
||||
File pdfFile = new File(fileNameFilePath);
|
||||
if (!pdfFile.exists()) {
|
||||
return null;
|
||||
}
|
||||
int index = pdfFilePath.lastIndexOf(".");
|
||||
String folder = pdfFilePath.substring(0, index);
|
||||
File path = new File(folder);
|
||||
if (!path.exists() && !path.mkdirs()) {
|
||||
logger.error("创建转换文件【{}】目录失败,请检查目录权限!", folder);
|
||||
}
|
||||
try {
|
||||
doc = Loader.loadPDF(pdfFile, filePassword);
|
||||
doc.setResourceCache(new NotResourceCache());
|
||||
pageCount[0] = doc.getNumberOfPages();
|
||||
} catch (IOException e) {
|
||||
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
||||
for (Throwable throwable : throwableArray) {
|
||||
if (throwable instanceof IOException || throwable instanceof EncryptedDocumentException) {
|
||||
if (e.getMessage().toLowerCase().contains(PDF_PASSWORD_MSG)) {
|
||||
pdfPassword[0] = PDF_PASSWORD_MSG; //查询到该文件是密码文件 输出带密码的值
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!PDF_PASSWORD_MSG.equals(pdfPassword[0])) { //该文件异常 错误原因非密码原因输出错误
|
||||
logger.error("Convert pdf exception, pdfFilePath:{}", pdfFilePath, e);
|
||||
}
|
||||
throw new Exception(e);
|
||||
}
|
||||
Callable <List<String>> call = () -> {
|
||||
try {
|
||||
String imageFilePath;
|
||||
BufferedImage image = null;
|
||||
PDFRenderer pdfRenderer = new PDFRenderer(doc);
|
||||
pdfRenderer.setSubsamplingAllowed(true);
|
||||
for (int pageIndex = 0; pageIndex < pageCount[0]; pageIndex++) {
|
||||
imageFilePath = folder + File.separator + pageIndex + PDF2JPG_IMAGE_FORMAT;
|
||||
image = pdfRenderer.renderImageWithDPI(pageIndex, ConfigConstants.getPdf2JpgDpi(), ImageType.RGB);
|
||||
ImageIOUtil.writeImage(image, imageFilePath, ConfigConstants.getPdf2JpgDpi());
|
||||
String imageUrl = this.getPdf2jpgUrl(pdfFilePath, pageIndex);
|
||||
imageUrls.add(imageUrl);
|
||||
}
|
||||
image.flush();
|
||||
} catch (IOException e) {
|
||||
throw new Exception(e);
|
||||
} finally {
|
||||
doc.close();
|
||||
}
|
||||
return imageUrls;
|
||||
};
|
||||
Future<List<String>> result = pool.submit(call);
|
||||
int pdftimeout;
|
||||
if(pageCount[0] <=50){
|
||||
pdftimeout = ConfigConstants.getPdfTimeout();
|
||||
}else if(pageCount[0] <=200){
|
||||
pdftimeout = ConfigConstants.getPdfTimeout80();
|
||||
}else {
|
||||
pdftimeout = ConfigConstants.getPdfTimeout200();
|
||||
}
|
||||
try {
|
||||
result.get(pdftimeout, TimeUnit.SECONDS);
|
||||
// 如果在超时时间内,没有数据返回:则抛出TimeoutException异常
|
||||
} catch (InterruptedException | ExecutionException e) {
|
||||
throw new Exception(e);
|
||||
} catch (TimeoutException e) {
|
||||
throw new Exception("overtime");
|
||||
} finally {
|
||||
//关闭
|
||||
doc.close();
|
||||
}
|
||||
if (usePasswordCache || ObjectUtils.isEmpty(filePassword)) { //加密文件 判断是否启用缓存命令
|
||||
this.addPdf2jpgCache(pdfFilePath, pageCount[0]);
|
||||
}
|
||||
return imageUrls;
|
||||
}
|
||||
|
||||
/**
|
||||
* cad文件转pdf
|
||||
*
|
||||
* @param inputFilePath cad文件路径
|
||||
* @param outputFilePath pdf输出文件路径
|
||||
* @return 转换是否成功
|
||||
*/
|
||||
public String cadToPdf(String inputFilePath, String outputFilePath, String cadPreviewType, FileAttribute fileAttribute) throws Exception {
|
||||
final InterruptionTokenSource source = new InterruptionTokenSource();//CAD延时
|
||||
final SvgOptions SvgOptions = new SvgOptions();
|
||||
final PdfOptions pdfOptions = new PdfOptions();
|
||||
final TiffOptions TiffOptions = new TiffOptions(TiffExpectedFormat.TiffJpegRgb);
|
||||
if (fileAttribute.isCompressFile()) { //判断 是压缩包的创建新的目录
|
||||
int index = outputFilePath.lastIndexOf("/"); //截取最后一个斜杠的前面的内容
|
||||
String folder = outputFilePath.substring(0, index);
|
||||
File path = new File(folder);
|
||||
//目录不存在 创建新的目录
|
||||
if (!path.exists()) {
|
||||
path.mkdirs();
|
||||
}
|
||||
}
|
||||
File outputFile = new File(outputFilePath);
|
||||
try {
|
||||
LoadOptions opts = new LoadOptions();
|
||||
opts.setSpecifiedEncoding(CodePages.SimpChinese);
|
||||
final Image cadImage = Image.load(inputFilePath, opts);
|
||||
try {
|
||||
RasterizationQuality rasterizationQuality = new RasterizationQuality();
|
||||
rasterizationQuality.setArc(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setHatch(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setText(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setOle(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setObjectsPrecision(RasterizationQualityValue.High);
|
||||
rasterizationQuality.setTextThicknessNormalization(true);
|
||||
CadRasterizationOptions cadRasterizationOptions = new CadRasterizationOptions();
|
||||
cadRasterizationOptions.setBackgroundColor(Color.getWhite());
|
||||
cadRasterizationOptions.setPageWidth(cadImage.getWidth());
|
||||
cadRasterizationOptions.setPageHeight(cadImage.getHeight());
|
||||
cadRasterizationOptions.setUnitType(cadImage.getUnitType());
|
||||
cadRasterizationOptions.setAutomaticLayoutsScaling(false);
|
||||
cadRasterizationOptions.setNoScaling(false);
|
||||
cadRasterizationOptions.setQuality(rasterizationQuality);
|
||||
cadRasterizationOptions.setDrawType(CadDrawTypeMode.UseObjectColor);
|
||||
cadRasterizationOptions.setExportAllLayoutContent(true);
|
||||
cadRasterizationOptions.setVisibilityMode(VisibilityMode.AsScreen);
|
||||
switch (cadPreviewType) { //新增格式方法
|
||||
case "svg":
|
||||
SvgOptions.setVectorRasterizationOptions(cadRasterizationOptions);
|
||||
SvgOptions.setInterruptionToken(source.getToken());
|
||||
break;
|
||||
case "pdf":
|
||||
pdfOptions.setVectorRasterizationOptions(cadRasterizationOptions);
|
||||
pdfOptions.setInterruptionToken(source.getToken());
|
||||
break;
|
||||
case "tif":
|
||||
TiffOptions.setVectorRasterizationOptions(cadRasterizationOptions);
|
||||
TiffOptions.setInterruptionToken(source.getToken());
|
||||
break;
|
||||
}
|
||||
Callable<String> call = () -> {
|
||||
try (OutputStream stream = new FileOutputStream(outputFile)) {
|
||||
switch (cadPreviewType) {
|
||||
case "svg":
|
||||
cadImage.save(stream, SvgOptions);
|
||||
break;
|
||||
case "pdf":
|
||||
cadImage.save(stream, pdfOptions);
|
||||
break;
|
||||
case "tif":
|
||||
cadImage.save(stream, TiffOptions);
|
||||
break;
|
||||
}
|
||||
} catch (IOException e) {
|
||||
logger.error("CADFileNotFoundException,inputFilePath:{}", inputFilePath, e);
|
||||
return null;
|
||||
} finally {
|
||||
cadImage.dispose();
|
||||
source.interrupt(); //结束任务
|
||||
source.dispose();
|
||||
}
|
||||
return "true";
|
||||
};
|
||||
Future<String> result = pool.submit(call);
|
||||
try {
|
||||
result.get(Long.parseLong(ConfigConstants.getCadTimeout()), TimeUnit.SECONDS);
|
||||
// 如果在超时时间内,没有数据返回:则抛出TimeoutException异常
|
||||
} catch (InterruptedException e) {
|
||||
logger.error("CAD转换文件异常:", e);
|
||||
return null;
|
||||
} catch (ExecutionException e) {
|
||||
logger.error("CAD转换在尝试取得任务结果时出错:", e);
|
||||
return null;
|
||||
} catch (TimeoutException e) {
|
||||
logger.error("CAD转换时间超时:", e);
|
||||
return null;
|
||||
} finally {
|
||||
source.interrupt(); //结束任务
|
||||
source.dispose();
|
||||
cadImage.dispose();
|
||||
// pool.shutdownNow();
|
||||
}
|
||||
} finally {
|
||||
source.dispose();
|
||||
cadImage.dispose();
|
||||
}
|
||||
} finally {
|
||||
source.dispose();
|
||||
}
|
||||
if(cadPreviewType.equals("svg")){
|
||||
System.out.println(" This is a new line.");
|
||||
System.out.println(outputFilePath);
|
||||
RemoveSvgAdSimple.removeSvgAdFromFile(outputFilePath);
|
||||
}
|
||||
return "true";
|
||||
}
|
||||
|
||||
/**
|
||||
* @param str 原字符串(待截取原串)
|
||||
|
||||
Reference in New Issue
Block a user