mirror of
https://gitee.com/kekingcn/file-online-preview.git
synced 2026-04-08 17:27:34 +00:00
cad pdf转换模块提取独立 优化多线程转换方法
This commit is contained in:
2
pom.xml
2
pom.xml
@@ -24,7 +24,7 @@
|
|||||||
<jodconverter.version>4.4.11</jodconverter.version>
|
<jodconverter.version>4.4.11</jodconverter.version>
|
||||||
<poi.version>5.2.5</poi.version>
|
<poi.version>5.2.5</poi.version>
|
||||||
<xdocreport.version>1.0.6</xdocreport.version>
|
<xdocreport.version>1.0.6</xdocreport.version>
|
||||||
<aspose-cad.version>24.8</aspose-cad.version>
|
<aspose-cad.version>25.10</aspose-cad.version>
|
||||||
|
|
||||||
<!-- ========== PDF 处理 ========== -->
|
<!-- ========== PDF 处理 ========== -->
|
||||||
<pdfbox.version>3.0.6</pdfbox.version>
|
<pdfbox.version>3.0.6</pdfbox.version>
|
||||||
|
|||||||
@@ -4,32 +4,18 @@ import cn.keking.config.ConfigConstants;
|
|||||||
import cn.keking.model.FileAttribute;
|
import cn.keking.model.FileAttribute;
|
||||||
import cn.keking.model.FileType;
|
import cn.keking.model.FileType;
|
||||||
import cn.keking.service.cache.CacheService;
|
import cn.keking.service.cache.CacheService;
|
||||||
import cn.keking.service.cache.NotResourceCache;
|
|
||||||
import cn.keking.utils.*;
|
import cn.keking.utils.*;
|
||||||
import cn.keking.web.filter.BaseUrlFilter;
|
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.Logger;
|
||||||
import org.slf4j.LoggerFactory;
|
import org.slf4j.LoggerFactory;
|
||||||
import org.springframework.beans.factory.InitializingBean;
|
|
||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.context.annotation.DependsOn;
|
import org.springframework.context.annotation.DependsOn;
|
||||||
import org.springframework.stereotype.Component;
|
import org.springframework.stereotype.Component;
|
||||||
import org.springframework.util.CollectionUtils;
|
|
||||||
import org.springframework.util.ObjectUtils;
|
import org.springframework.util.ObjectUtils;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import jakarta.servlet.http.HttpServletRequest;
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
import java.awt.image.BufferedImage;
|
|
||||||
import java.io.*;
|
import java.io.*;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.net.URLEncoder;
|
import java.net.URLEncoder;
|
||||||
@@ -38,7 +24,6 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Objects;
|
import java.util.Objects;
|
||||||
import java.util.concurrent.*;
|
|
||||||
import java.util.stream.IntStream;
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -47,10 +32,10 @@ import java.util.stream.IntStream;
|
|||||||
*/
|
*/
|
||||||
@Component
|
@Component
|
||||||
@DependsOn(ConfigConstants.BEAN_NAME)
|
@DependsOn(ConfigConstants.BEAN_NAME)
|
||||||
public class FileHandlerService implements InitializingBean {
|
public class FileHandlerService {
|
||||||
|
|
||||||
private static final String PDF2JPG_IMAGE_FORMAT = ".jpg";
|
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 Logger logger = LoggerFactory.getLogger(FileHandlerService.class);
|
||||||
private final String fileDir = ConfigConstants.getFileDir();
|
private final String fileDir = ConfigConstants.getFileDir();
|
||||||
private final CacheService cacheService;
|
private final CacheService cacheService;
|
||||||
@@ -144,15 +129,6 @@ public class FileHandlerService implements InitializingBean {
|
|||||||
cacheService.putImgCache(fileKey, imgs);
|
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 图片索引
|
* @param index 图片索引
|
||||||
* @return 图片访问地址
|
* @return 图片访问地址
|
||||||
*/
|
*/
|
||||||
private String getPdf2jpgUrl(String pdfFilePath, int index) {
|
public String getPdf2jpgUrl(String pdfFilePath, int index) {
|
||||||
String baseUrl = BaseUrlFilter.getBaseUrl();
|
String baseUrl = BaseUrlFilter.getBaseUrl();
|
||||||
pdfFilePath = pdfFilePath.replace(fileDir, "");
|
pdfFilePath = pdfFilePath.replace(fileDir, "");
|
||||||
String pdfFolder = pdfFilePath.substring(0, pdfFilePath.length() - 4);
|
String pdfFolder = pdfFilePath.substring(0, pdfFilePath.length() - 4);
|
||||||
@@ -214,230 +190,20 @@ public class FileHandlerService implements InitializingBean {
|
|||||||
* @param pdfFilePath pdf文件路径
|
* @param pdfFilePath pdf文件路径
|
||||||
* @return 图片访问集合
|
* @return 图片访问集合
|
||||||
*/
|
*/
|
||||||
private List<String> loadPdf2jpgCache(String pdfFilePath) {
|
public List<String> loadPdf2jpgCache(String pdfFilePath) { // 移除 static 修饰符
|
||||||
List<String> imageUrls = new ArrayList<>();
|
List<String> imageUrls = new ArrayList<>();
|
||||||
Integer imageCount = this.getPdf2jpgCache(pdfFilePath);
|
Integer imageCount = this.getPdf2jpgCache(pdfFilePath); // 使用 this. 调用
|
||||||
if (Objects.isNull(imageCount)) {
|
if (Objects.isNull(imageCount)) {
|
||||||
return imageUrls;
|
return imageUrls;
|
||||||
}
|
}
|
||||||
IntStream.range(0, imageCount).forEach(i -> {
|
IntStream.range(0, imageCount).forEach(i -> {
|
||||||
String imageUrl = this.getPdf2jpgUrl(pdfFilePath, i);
|
String imageUrl = this.getPdf2jpgUrl(pdfFilePath, i); // 使用 this. 调用
|
||||||
imageUrls.add(imageUrl);
|
imageUrls.add(imageUrl);
|
||||||
});
|
});
|
||||||
return imageUrls;
|
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 原字符串(待截取原串)
|
* @param str 原字符串(待截取原串)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package cn.keking.service.impl;
|
|||||||
import cn.keking.config.ConfigConstants;
|
import cn.keking.config.ConfigConstants;
|
||||||
import cn.keking.model.FileAttribute;
|
import cn.keking.model.FileAttribute;
|
||||||
import cn.keking.model.ReturnResponse;
|
import cn.keking.model.ReturnResponse;
|
||||||
|
import cn.keking.service.CadToPdfService;
|
||||||
import cn.keking.service.FileHandlerService;
|
import cn.keking.service.FileHandlerService;
|
||||||
import cn.keking.service.FilePreview;
|
import cn.keking.service.FilePreview;
|
||||||
import cn.keking.utils.DownloadUtils;
|
import cn.keking.utils.DownloadUtils;
|
||||||
@@ -15,7 +16,6 @@ import org.springframework.stereotype.Service;
|
|||||||
import org.springframework.ui.Model;
|
import org.springframework.ui.Model;
|
||||||
import org.springframework.util.StringUtils;
|
import org.springframework.util.StringUtils;
|
||||||
|
|
||||||
import static cn.keking.service.impl.OfficeFilePreviewImpl.getPreviewType;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @author chenjh
|
* @author chenjh
|
||||||
@@ -29,11 +29,15 @@ public class CadFilePreviewImpl implements FilePreview {
|
|||||||
private static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages";
|
private static final String OFFICE_PREVIEW_TYPE_ALL_IMAGES = "allImages";
|
||||||
|
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
|
private final CadToPdfService cadtopdfservice;
|
||||||
private final OtherFilePreviewImpl otherFilePreview;
|
private final OtherFilePreviewImpl otherFilePreview;
|
||||||
|
private final OfficeFilePreviewImpl officefilepreviewimpl;
|
||||||
|
|
||||||
public CadFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
public CadFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview, CadToPdfService cadtopdfservice,OfficeFilePreviewImpl officefilepreviewimpl ) {
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.otherFilePreview = otherFilePreview;
|
this.otherFilePreview = otherFilePreview;
|
||||||
|
this.cadtopdfservice = cadtopdfservice;
|
||||||
|
this.officefilepreviewimpl = officefilepreviewimpl;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -53,14 +57,14 @@ public class CadFilePreviewImpl implements FilePreview {
|
|||||||
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
return otherFilePreview.notSupportedFile(model, fileAttribute, response.getMsg());
|
||||||
}
|
}
|
||||||
String filePath = response.getContent();
|
String filePath = response.getContent();
|
||||||
String imageUrls = null;
|
boolean imageUrls = false;
|
||||||
if (StringUtils.hasText(outFilePath)) {
|
if (StringUtils.hasText(outFilePath)) {
|
||||||
try {
|
try {
|
||||||
imageUrls = fileHandlerService.cadToPdf(filePath, outFilePath, cadPreviewType, fileAttribute);
|
imageUrls = cadtopdfservice.cadToPdf(filePath, outFilePath, cadPreviewType, fileAttribute);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.error("Failed to convert CAD file: {}", filePath, e);
|
logger.error("Failed to convert CAD file: {}", filePath, e);
|
||||||
}
|
}
|
||||||
if (imageUrls == null) {
|
if (!imageUrls) {
|
||||||
return otherFilePreview.notSupportedFile(model, fileAttribute, "CAD转换异常,请联系管理员");
|
return otherFilePreview.notSupportedFile(model, fileAttribute, "CAD转换异常,请联系管理员");
|
||||||
}
|
}
|
||||||
//是否保留CAD源文件
|
//是否保留CAD源文件
|
||||||
@@ -82,7 +86,7 @@ public class CadFilePreviewImpl implements FilePreview {
|
|||||||
return SVG_FILE_PREVIEW_PAGE;
|
return SVG_FILE_PREVIEW_PAGE;
|
||||||
}
|
}
|
||||||
if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
|
if (baseUrl != null && (OFFICE_PREVIEW_TYPE_IMAGE.equals(officePreviewType) || OFFICE_PREVIEW_TYPE_ALL_IMAGES.equals(officePreviewType))) {
|
||||||
return getPreviewType(model, fileAttribute, officePreviewType, cacheName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
|
return officefilepreviewimpl.getPreviewType(model, fileAttribute, officePreviewType, cacheName, outFilePath, fileHandlerService, OFFICE_PREVIEW_TYPE_IMAGE, otherFilePreview);
|
||||||
}
|
}
|
||||||
model.addAttribute("pdfUrl", cacheName);
|
model.addAttribute("pdfUrl", cacheName);
|
||||||
return PDF_FILE_PREVIEW_PAGE;
|
return PDF_FILE_PREVIEW_PAGE;
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import cn.keking.model.ReturnResponse;
|
|||||||
import cn.keking.service.FileHandlerService;
|
import cn.keking.service.FileHandlerService;
|
||||||
import cn.keking.service.FilePreview;
|
import cn.keking.service.FilePreview;
|
||||||
import cn.keking.service.OfficeToPdfService;
|
import cn.keking.service.OfficeToPdfService;
|
||||||
|
import cn.keking.service.PdfToJpgService;
|
||||||
import cn.keking.utils.DownloadUtils;
|
import cn.keking.utils.DownloadUtils;
|
||||||
import cn.keking.utils.KkFileUtils;
|
import cn.keking.utils.KkFileUtils;
|
||||||
import cn.keking.utils.OfficeUtils;
|
import cn.keking.utils.OfficeUtils;
|
||||||
@@ -35,11 +36,13 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
private final OfficeToPdfService officeToPdfService;
|
private final OfficeToPdfService officeToPdfService;
|
||||||
private final OtherFilePreviewImpl otherFilePreview;
|
private final OtherFilePreviewImpl otherFilePreview;
|
||||||
|
private final PdfToJpgService pdftojpgservice;
|
||||||
|
|
||||||
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, OfficeToPdfService officeToPdfService, OtherFilePreviewImpl otherFilePreview) {
|
public OfficeFilePreviewImpl(FileHandlerService fileHandlerService, OfficeToPdfService officeToPdfService, OtherFilePreviewImpl otherFilePreview, PdfToJpgService pdftojpgservice) {
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.officeToPdfService = officeToPdfService;
|
this.officeToPdfService = officeToPdfService;
|
||||||
this.otherFilePreview = otherFilePreview;
|
this.otherFilePreview = otherFilePreview;
|
||||||
|
this.pdftojpgservice = pdftojpgservice;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -115,12 +118,12 @@ public class OfficeFilePreviewImpl implements FilePreview {
|
|||||||
return isHtmlView ? EXEL_FILE_PREVIEW_PAGE : PDF_FILE_PREVIEW_PAGE;
|
return isHtmlView ? EXEL_FILE_PREVIEW_PAGE : PDF_FILE_PREVIEW_PAGE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String pdfName, String outFilePath, FileHandlerService fileHandlerService, String officePreviewTypeImage, OtherFilePreviewImpl otherFilePreview) {
|
String getPreviewType(Model model, FileAttribute fileAttribute, String officePreviewType, String pdfName, String outFilePath, FileHandlerService fileHandlerService, String officePreviewTypeImage, OtherFilePreviewImpl otherFilePreview) {
|
||||||
String suffix = fileAttribute.getSuffix();
|
String suffix = fileAttribute.getSuffix();
|
||||||
boolean isPPT = suffix.equalsIgnoreCase("ppt") || suffix.equalsIgnoreCase("pptx");
|
boolean isPPT = suffix.equalsIgnoreCase("ppt") || suffix.equalsIgnoreCase("pptx");
|
||||||
List<String> imageUrls = null;
|
List<String> imageUrls = null;
|
||||||
try {
|
try {
|
||||||
imageUrls = fileHandlerService.pdf2jpg(outFilePath,outFilePath, pdfName, fileAttribute);
|
imageUrls = pdftojpgservice.pdf2jpg(outFilePath,outFilePath, pdfName, fileAttribute);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
||||||
for (Throwable throwable : throwableArray) {
|
for (Throwable throwable : throwableArray) {
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import cn.keking.model.FileAttribute;
|
|||||||
import cn.keking.model.ReturnResponse;
|
import cn.keking.model.ReturnResponse;
|
||||||
import cn.keking.service.FileHandlerService;
|
import cn.keking.service.FileHandlerService;
|
||||||
import cn.keking.service.FilePreview;
|
import cn.keking.service.FilePreview;
|
||||||
|
import cn.keking.service.PdfToJpgService;
|
||||||
import cn.keking.utils.DownloadUtils;
|
import cn.keking.utils.DownloadUtils;
|
||||||
import cn.keking.utils.WebUtils;
|
import cn.keking.utils.WebUtils;
|
||||||
import org.apache.commons.lang3.exception.ExceptionUtils;
|
import org.apache.commons.lang3.exception.ExceptionUtils;
|
||||||
@@ -24,10 +25,12 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
|
|
||||||
private final FileHandlerService fileHandlerService;
|
private final FileHandlerService fileHandlerService;
|
||||||
private final OtherFilePreviewImpl otherFilePreview;
|
private final OtherFilePreviewImpl otherFilePreview;
|
||||||
|
private final PdfToJpgService pdftojpgservice;
|
||||||
private static final String PDF_PASSWORD_MSG = "password";
|
private static final String PDF_PASSWORD_MSG = "password";
|
||||||
public PdfFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview) {
|
public PdfFilePreviewImpl(FileHandlerService fileHandlerService, OtherFilePreviewImpl otherFilePreview, PdfToJpgService pdftojpgservice) {
|
||||||
this.fileHandlerService = fileHandlerService;
|
this.fileHandlerService = fileHandlerService;
|
||||||
this.otherFilePreview = otherFilePreview;
|
this.otherFilePreview = otherFilePreview;
|
||||||
|
this.pdftojpgservice = pdftojpgservice;
|
||||||
}
|
}
|
||||||
@Override
|
@Override
|
||||||
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
public String filePreviewHandle(String url, Model model, FileAttribute fileAttribute) {
|
||||||
@@ -51,7 +54,7 @@ public class PdfFilePreviewImpl implements FilePreview {
|
|||||||
}
|
}
|
||||||
List<String> imageUrls;
|
List<String> imageUrls;
|
||||||
try {
|
try {
|
||||||
imageUrls = fileHandlerService.pdf2jpg(originFilePath,outFilePath, pdfName, fileAttribute);
|
imageUrls = pdftojpgservice.pdf2jpg(originFilePath,outFilePath, pdfName, fileAttribute);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
Throwable[] throwableArray = ExceptionUtils.getThrowables(e);
|
||||||
for (Throwable throwable : throwableArray) {
|
for (Throwable throwable : throwableArray) {
|
||||||
|
|||||||
@@ -4,74 +4,9 @@ import java.io.IOException;
|
|||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
import java.nio.charset.StandardCharsets;
|
|
||||||
import java.util.regex.Pattern;
|
|
||||||
import java.util.regex.Matcher;
|
|
||||||
|
|
||||||
public class RemoveSvgAdSimple {
|
public class RemoveSvgAdSimple {
|
||||||
|
|
||||||
/**
|
|
||||||
* 改进版本:直接处理SVG内容,保留包含transform的<g>元素及其内容
|
|
||||||
* @param svgContent SVG内容字符串
|
|
||||||
* @return 清理后的SVG内容
|
|
||||||
*/
|
|
||||||
public static String removeSvgAdPrecisely(String svgContent) {
|
|
||||||
// 使用非贪婪模式匹配包含transform的<g>元素及其完整内容
|
|
||||||
String preservePattern = "<g\\s+[^>]*transform\\s*=\\s*\"[^\"]*\"[^>]*>.*?</g>";
|
|
||||||
|
|
||||||
// 查找所有包含transform的<g>元素
|
|
||||||
Pattern pattern = Pattern.compile(preservePattern, Pattern.DOTALL);
|
|
||||||
Matcher matcher = pattern.matcher(svgContent);
|
|
||||||
|
|
||||||
StringBuilder result = new StringBuilder();
|
|
||||||
// 添加XML声明和SVG根元素
|
|
||||||
if (svgContent.contains("<?xml")) {
|
|
||||||
result.append("<?xml version=\"1.0\" standalone=\"no\"?>");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 找到SVG开始标签
|
|
||||||
int svgStart = svgContent.indexOf("<svg");
|
|
||||||
int svgEnd = svgContent.indexOf(">", svgStart) + 1;
|
|
||||||
|
|
||||||
if (svgStart != -1) {
|
|
||||||
// 添加SVG开始标签
|
|
||||||
result.append(svgContent.substring(svgStart, svgEnd));
|
|
||||||
|
|
||||||
// 收集所有包含transform的<g>元素
|
|
||||||
while (matcher.find()) {
|
|
||||||
result.append("\n").append(matcher.group());
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加SVG结束标签
|
|
||||||
result.append("\n</svg>");
|
|
||||||
} else {
|
|
||||||
// 如果没有找到SVG标签,返回空或原始内容
|
|
||||||
return svgContent;
|
|
||||||
}
|
|
||||||
|
|
||||||
return result.toString();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 简单暴力版本:直接删除特定广告内容
|
|
||||||
* @param svgContent SVG内容字符串
|
|
||||||
* @return 清理后的SVG内容
|
|
||||||
*/
|
|
||||||
public static String removeSvgAdSimple(String svgContent) {
|
|
||||||
// 查找包含广告的<g>元素(根据你的示例,广告通常包含stroke="#FFFFFF"等特征)
|
|
||||||
String adPattern1 = "<g>\\s*<path[^>]*stroke=\"#FFFFFF\"[^>]*>.*?</path>\\s*<path[^>]*fill=\"#FFFFFF\"[^>]*>.*?</path>\\s*</g>";
|
|
||||||
String adPattern2 = "<g>\\s*<path[^>]*M0 0L[^>]*stroke=\"#FFFFFF\"[^>]*>.*?</path>.*?</g>";
|
|
||||||
|
|
||||||
String result = svgContent;
|
|
||||||
result = result.replaceAll(adPattern1, "");
|
|
||||||
result = result.replaceAll(adPattern2, "");
|
|
||||||
|
|
||||||
// 也可以直接删除所有不含transform属性的顶级<g>元素
|
|
||||||
// 这个正则会删除不带transform的顶级<g>,但保留嵌套的<g>
|
|
||||||
result = result.replaceAll("(?s)<g>(?:(?!<g>).)*?</g>", "");
|
|
||||||
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 更可靠的版本:使用DOM解析思路,但用正则实现
|
* 更可靠的版本:使用DOM解析思路,但用正则实现
|
||||||
@@ -84,7 +19,7 @@ public class RemoveSvgAdSimple {
|
|||||||
// 找到XML声明
|
// 找到XML声明
|
||||||
if (svgContent.contains("<?xml")) {
|
if (svgContent.contains("<?xml")) {
|
||||||
int xmlEnd = svgContent.indexOf("?>") + 2;
|
int xmlEnd = svgContent.indexOf("?>") + 2;
|
||||||
cleaned.append(svgContent.substring(0, xmlEnd)).append("\n");
|
cleaned.append(svgContent, 0, xmlEnd).append("\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 找到SVG开始标签
|
// 找到SVG开始标签
|
||||||
@@ -92,7 +27,7 @@ public class RemoveSvgAdSimple {
|
|||||||
if (svgStart == -1) return svgContent;
|
if (svgStart == -1) return svgContent;
|
||||||
|
|
||||||
int svgEnd = svgContent.indexOf(">", svgStart) + 1;
|
int svgEnd = svgContent.indexOf(">", svgStart) + 1;
|
||||||
cleaned.append(svgContent.substring(svgStart, svgEnd)).append("\n");
|
cleaned.append(svgContent, svgStart, svgEnd).append("\n");
|
||||||
|
|
||||||
// 解析剩余内容
|
// 解析剩余内容
|
||||||
String remaining = svgContent.substring(svgEnd);
|
String remaining = svgContent.substring(svgEnd);
|
||||||
@@ -133,7 +68,7 @@ public class RemoveSvgAdSimple {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (gClose != -1) {
|
if (gClose != -1) {
|
||||||
cleaned.append(remaining.substring(gStart, gClose)).append("\n");
|
cleaned.append(remaining, gStart, gClose).append("\n");
|
||||||
pos = gClose;
|
pos = gClose;
|
||||||
} else {
|
} else {
|
||||||
pos = gTagEnd + 1;
|
pos = gTagEnd + 1;
|
||||||
@@ -166,14 +101,14 @@ public class RemoveSvgAdSimple {
|
|||||||
public static void removeSvgAdFromFile(String sourceFilePath, String targetFilePath) throws IOException {
|
public static void removeSvgAdFromFile(String sourceFilePath, String targetFilePath) throws IOException {
|
||||||
// 读取文件内容
|
// 读取文件内容
|
||||||
Path sourcePath = Paths.get(sourceFilePath);
|
Path sourcePath = Paths.get(sourceFilePath);
|
||||||
String svgContent = new String(Files.readAllBytes(sourcePath), StandardCharsets.UTF_8);
|
String svgContent = Files.readString(sourcePath);
|
||||||
|
|
||||||
// 清理SVG广告
|
// 清理SVG广告
|
||||||
String cleanedContent = removeSvgAdReliable(svgContent);
|
String cleanedContent = removeSvgAdReliable(svgContent);
|
||||||
|
|
||||||
// 写入目标文件
|
// 写入目标文件
|
||||||
Path targetPath = Paths.get(targetFilePath);
|
Path targetPath = Paths.get(targetFilePath);
|
||||||
Files.write(targetPath, cleanedContent.getBytes(StandardCharsets.UTF_8));
|
Files.writeString(targetPath, cleanedContent);
|
||||||
System.out.println("SVG广告清理完成!");
|
System.out.println("SVG广告清理完成!");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user