之前写了一个版本的,不过代码繁琐而且不好用,效率有些问题。尤其pdf转图片速度太慢。下面是优化版本的代码。
spriing_boot 版本信息:2.0.1.RELEASE
1、配置信息:
packagecom.yunfatong.conf;importlombok.extern.slf4j.Slf4j;importorg.apache.commons.lang3.ArrayUtils;importorg.apache.commons.lang3.StringUtils;importorg.apache.commons.lang3.math.NumberUtils;importorg.jodconverter.DocumentConverter;importorg.jodconverter.LocalConverter;importorg.jodconverter.office.LocalOfficeManager;importorg.jodconverter.office.OfficeManager;importorg.springframework.boot.autoconfigure.condition.ConditionalOnBean;importorg.springframework.boot.autoconfigure.condition.ConditionalOnClass;importorg.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;importorg.springframework.boot.autoconfigure.condition.ConditionalOnProperty;importorg.springframework.boot.context.properties.EnableConfigurationProperties;importorg.springframework.context.annotation.Bean;importorg.springframework.context.annotation.Configuration;importjava.util.HashSet;importjava.util.Set;/*** openoffice 配置
*
*@authorliran
* @date 20190517*/@Configuration
@ConditionalOnClass({DocumentConverter.class})
@ConditionalOnProperty(prefix= "jodconverter", name = {"enabled"}, havingValue = "true", matchIfMissing = true)
@EnableConfigurationProperties({JodConverterProperties.class})
@Slf4jpublic classJodConverterAutoConfiguration {private finalJodConverterProperties properties;publicJodConverterAutoConfiguration(JodConverterProperties properties) {this.properties =properties;
}privateOfficeManager createOfficeManager() {
LocalOfficeManager.Builder builder=LocalOfficeManager.builder();if (!StringUtils.isBlank(this.properties.getPortNumbers())) {
Set iports = new HashSet<>();
String[] var3= StringUtils.split(this.properties.getPortNumbers(), ", ");int var4 =var3.length;for (int var5 = 0; var5 < var4; ++var5) {
String portNumber=var3[var5];
iports.add(NumberUtils.toInt(portNumber,2002));
}
builder.portNumbers(ArrayUtils.toPrimitive(iports.toArray(newInteger[iports.size()])));
}
builder.officeHome(this.properties.getOfficeHome());
builder.workingDir(this.properties.getWorkingDir());
builder.templateProfileDir(this.properties.getTemplateProfileDir());
builder.killExistingProcess(this.properties.isKillExistingProcess());
builder.processTimeout(this.properties.getProcessTimeout());
builder.processRetryInterval(this.properties.getProcessRetryInterval());
builder.taskExecutionTimeout(this.properties.getTaskExecutionTimeout());
builder.maxTasksPerProcess(this.properties.getMaxTasksPerProcess());
builder.taskQueueTimeout(this.properties.getTaskQueueTimeout());returnbuilder.build();
}
@Bean(initMethod= "start", destroyMethod = "stop")
@ConditionalOnMissingBeanpublicOfficeManager officeManager() {return this.createOfficeManager();
}
@Bean
@ConditionalOnMissingBean
@ConditionalOnBean({OfficeManager.class})publicDocumentConverter jodConverter(OfficeManager officeManager) {returnLocalConverter.make(officeManager);
}
}
packagecom.yunfatong.conf;importorg.springframework.boot.context.properties.ConfigurationProperties;importjava.util.regex.Pattern;/*** openoffice 配置
*
*@authorliran
* @date 20190517*/@ConfigurationProperties("jodconverter")public classJodConverterProperties {private booleanenabled;privateString officeHome;private String portNumbers = "2002";privateString workingDir;privateString templateProfileDir;private boolean killExistingProcess = true;private long processTimeout = 120000L;private long processRetryInterval = 250L;private long taskExecutionTimeout = 120000L;private int maxTasksPerProcess = 200;private long taskQueueTimeout = 30000L;publicJodConverterProperties() {
}public booleanisEnabled() {return this.enabled;
}public void setEnabled(booleanenabled) {this.enabled =enabled;
}publicString getOfficeHome() {//根据不同系统分别设置//office-home: C:\Program Files (x86)\OpenOffice 4 #windows下默认 不用修改//#office-home: /opt/openoffice4 #linux 默认 不用修改
String osName = System.getProperty("os.name");if (Pattern.matches("Linux.*", osName)) {this.officeHome = "/opt/openoffice4";
}else if (Pattern.matches("Windows.*", osName)) {this.officeHome = "C:\\Program Files (x86)\\OpenOffice 4";
}else{this.officeHome = "/opt/openoffice4";
}return this.officeHome;
}public voidsetOfficeHome(String officeHome) {this.officeHome =officeHome;
}publicString getPortNumbers() {return this.portNumbers;
}public voidsetPortNumbers(String portNumbers) {this.portNumbers =portNumbers;
}publicString getWorkingDir() {return this.workingDir;
}public voidsetWorkingDir(String workingDir) {this.workingDir =workingDir;
}publicString getTemplateProfileDir() {return this.templateProfileDir;
}public voidsetTemplateProfileDir(String templateProfileDir) {this.templateProfileDir =templateProfileDir;
}public booleanisKillExistingProcess() {return this.killExistingProcess;
}public void setKillExistingProcess(booleankillExistingProcess) {this.killExistingProcess =killExistingProcess;
}public longgetProcessTimeout() {return this.processTimeout;
}public void setProcessTimeout(longprocessTimeout) {this.processTimeout =processTimeout;
}public longgetProcessRetryInterval() {return this.processRetryInterval;
}public void setProcessRetryInterval(longprocesRetryInterval) {this.processRetryInterval =procesRetryInterval;
}public longgetTaskExecutionTimeout() {return this.taskExecutionTimeout;
}public void setTaskExecutionTimeout(longtaskExecutionTimeout) {this.taskExecutionTimeout =taskExecutionTimeout;
}public intgetMaxTasksPerProcess() {return this.maxTasksPerProcess;
}public void setMaxTasksPerProcess(intmaxTasksPerProcess) {this.maxTasksPerProcess =maxTasksPerProcess;
}public longgetTaskQueueTimeout() {return this.taskQueueTimeout;
}public void setTaskQueueTimeout(longtaskQueueTimeout) {this.taskQueueTimeout =taskQueueTimeout;
}
}
application.yml
jodconverter:
enabled:trueoffice-home: linuxOrwindows
#/opt/openoffice4 #linux 默认 不用修改 C:\Program Files (x86)\OpenOffice 4#windows下默认 不用修改
port-numbers: 2002max-tasks-per-process: 10
2、转换入口
package com.yunfatong.ojd.util.pdf;
import cn.hutool.core.date.DatePattern;
import com.yunfatong.ojd.common.exception.CommonException;
import com.yunfatong.ojd.service.FileSystemStorageService;
import com.yunfatong.ojd.util.SpringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.jodconverter.DocumentConverter;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import java.io.File;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
/**
* word 转pdf
*
* @author lr
*/
@Component
@Slf4j
public class TransferUtil {
[email protected] 主要是配置不启用的话 无法注入
private DocumentConverter documentConverter;
@Autowired
private FileSystemStorageService fileSystemStorageService;
/**
* fileSystemStorageService 就是拼接出本地路径的作用
* storage.winLocation=D:\\ojd\\upload\\images\\
* ##上传图片linux存储路径
* storage.linuxLocation=/home/ojd/upload/images/
*/
final static String WORD_SUFFIX_DOC = "doc";
final static String WORD_SUFFIX_DOCX = "docx";
/**
* word ->pdf
*
* @param webPath 浏览器可访问路径(数据库存的)如 /test/wd.word
* @return 相同文件夹下的转换后的pdf 路径 如/test/wd_20190517151515333.pdf
* @throws Exception
*/
public String transferWordToPdf(String webPath) throws Exception {
if(documentConverter==null){
documentConverter = SpringUtil.getBean(DocumentConverter.class);
}
//转换成本地实际磁盘路径
String originLocalFilePath = fileSystemStorageService.getLocation(webPath);
File inputFile = new File(originLocalFilePath);
if (!inputFile.exists() || !inputFile.isFile() || (!StringUtils.contains(inputFile.getName(), WORD_SUFFIX_DOC) && !StringUtils.contains(inputFile.getName(), WORD_SUFFIX_DOCX))) {
throw new CommonException("word -> pdf转换错误 当前文件不是word或 文件不存在: " + webPath);
}
DateTimeFormatter formatter = DateTimeFormatter.ofPattern(DatePattern.PURE_DATETIME_MS_PATTERN);
String timeNow = formatter.format(LocalDateTime.now());
String newPdfWebPath = StringUtils.substringBeforeLast(webPath, ".") + "_" + timeNow + ".pdf";
try {
File outputFile = new File(fileSystemStorageService.getLocation(newPdfWebPath));
documentConverter.convert(inputFile).to(outputFile).execute();
} catch (Exception e) {
log.error("word->pdf 转换错误------------> Exception:{}", e);
throw e;
}
return newPdfWebPath;
}
public List transferPdfToImage(String webPath) throws Exception {
String originLocalFilePath = fileSystemStorageService.getLocation(webPath);
File inputFile = new File(originLocalFilePath);
if (!inputFile.exists() || !inputFile.isFile() || webPath.lastIndexOf(".pdf") < 0) {
throw new CommonException("pdf-> img 源文件不是pdf文件 或者文件不存在!" + webPath);
}
String localPdfpath = fileSystemStorageService.getLocation(webPath);
String newImgWebPathPreSuffix = StringUtils.substringBeforeLast(webPath, ".");
String localImgPath = fileSystemStorageService.getLocation(newImgWebPathPreSuffix);
PdfTransferUtil pdfTranfer = new PdfTransferUtil();
List ins = pdfTranfer.pdf2Image(localPdfpath, "png", 1.5f);
List webPaths = new ArrayList<>(ins.size());
for (int i = 0; i < ins.size(); i++) {
byte[] data = ins.get(i);
String pathReal = localImgPath + "_ojd_" + i + ".png";
FileUtils.writeByteArrayToFile(new File(pathReal), data);
webPaths.add(pathReal);
}
return webPaths;
}
}
pdf 转图片参考https://gitee.com/cycmy/pdftranfer.git
packagecom.yunfatong.ojd.util.pdf;importlombok.extern.slf4j.Slf4j;importorg.icepdf.core.pobjects.Document;importorg.icepdf.core.pobjects.Page;importorg.icepdf.core.util.GraphicsRenderingHints;importjavax.imageio.ImageIO;importjavax.imageio.stream.ImageOutputStream;importjava.awt.image.BufferedImage;importjava.io.ByteArrayOutputStream;importjava.io.InputStream;importjava.util.ArrayList;importjava.util.List;importjava.util.concurrent.Callable;importjava.util.concurrent.ExecutorService;importjava.util.concurrent.Executors;importjava.util.concurrent.Future;/***@authorlr
* //原文:https://blog.csdn.net/qq_35974759/article/details/83149734
*/@Slf4jpublic classPdfTransferUtil {//*********************************pdf to image **********************************************************
/*** 将指定pdf字节数组转换为指定格式图片二进制数组
*
*@parampdfBytes PDF字节数组
*@paramimageType 转换图片格式 默认png
*@paramzoom 缩略图显示倍数,1表示不缩放,0.3则缩小到30%
*@returnList
*@throwsException*/
public List pdf2Image(byte[] pdfBytes, String imageType, float zoom) throwsException {
Document document= newDocument();
document.setByteArray(pdfBytes,0, pdfBytes.length, null);returnpageExtraction(document, imageType, 0f, zoom);
}/*** 将指定pdf输入流转换为指定格式图片二进制数组
*
*@paraminputPDF PDF二进制流
*@paramimageType 转换图片格式 默认png
*@paramzoom 缩略图显示倍数,1表示不缩放,0.3则缩小到30%
*@returnList
*@throwsException*/
public List pdf2Image(InputStream inputPDF, String imageType, float zoom) throwsException {
Document document= newDocument();
document.setInputStream(inputPDF,null);returnpageExtraction(document, imageType, 0f, zoom);
}/*** 将指定pdf文件转换为指定格式图片二进制数组
*
*@parampdfPath 原文件路径,例如d:/test.pdf
*@paramimageType 转换图片格式 默认png
*@paramzoom 缩略图显示倍数,1表示不缩放,0.3则缩小到30%
*@returnList
*@throwsException*/
public List pdf2Image(String pdfPath, String imageType, float zoom) throwsException {
Document document= newDocument();
document.setFile(pdfPath);returnpageExtraction(document, imageType, 0f, zoom);
}//*********************************pdf to image **********************************************************
private List pageExtraction(Document document, String imageType, float rotation, floatzoom) {//setup two threads to handle image extraction.
ExecutorService executorService = Executors.newFixedThreadPool(5);try{//create a list of callables.
int pages =document.getNumberOfPages();
List result = new ArrayList(pages);
List> callables = new ArrayList>(pages);for (int i = 0; i < pages; i++) {
callables.add(newCapturePage(document, i, imageType, rotation, zoom));
}
List> listFuture =executorService.invokeAll(callables);
executorService.submit(newDocumentCloser(document)).get();for (Futurefuture : listFuture) {
result.add(future.get());
}returnresult;
}catch(Exception ex) {
log.error(" pdf 转换图片错误 Error handling PDF document " +ex);
}finally{
executorService.shutdown();
}return null;
}public class CapturePage implements Callable{privateDocument document;private intpageNumber;privateString imageType;private floatrotation;private floatzoom;private CapturePage(Document document, int pageNumber, String imageType, float rotation, floatzoom) {this.document =document;this.pageNumber =pageNumber;this.imageType =imageType;this.rotation =rotation;this.zoom =zoom;
}
@Overridepublic byte[] call() throwsException {
BufferedImage image=(BufferedImage) document.getPageImage(pageNumber, GraphicsRenderingHints.SCREEN, Page.BOUNDARY_CROPBOX, rotation, zoom);
ByteArrayOutputStream bs= newByteArrayOutputStream();
ImageOutputStream imOut=ImageIO.createImageOutputStream(bs);
ImageIO.write(image, imageType, imOut);
image.flush();returnbs.toByteArray();
}
}/*** Disposes the document.*/
public class DocumentCloser implements Callable{privateDocument document;privateDocumentCloser(Document document) {this.document =document;
}
@OverridepublicVoid call() {if (document != null) {
document.dispose();
log.info("Document disposed");
}return null;
}
}
}
springutils
packagecom.yunfatong.ojd.util;/*** @Auther liran
* @Date 2018/8/30 14:49
* @Description*/
importorg.springframework.beans.BeansException;importorg.springframework.context.ApplicationContext;importorg.springframework.context.ApplicationContextAware;importorg.springframework.stereotype.Component;
@Componentpublic class SpringUtil implementsApplicationContextAware {private staticApplicationContext applicationContext;
@Overridepublic void setApplicationContext(ApplicationContext applicationContext) throwsBeansException {if(SpringUtil.applicationContext == null) {
SpringUtil.applicationContext=applicationContext;
}
System.out.println("========ApplicationContext配置成功,在普通类可以通过调用SpringUtils.getAppContext()获取applicationContext对象,applicationContext="+SpringUtil.applicationContext+"========");
}//获取applicationContext
public staticApplicationContext getApplicationContext() {returnapplicationContext;
}//通过name获取 Bean.
public staticObject getBean(String name){returngetApplicationContext().getBean(name);
}//通过class获取Bean.
public static T getBean(Classclazz){returngetApplicationContext().getBean(clazz);
}//通过name,以及Clazz返回指定的Bean
public static T getBean(String name,Classclazz){returngetApplicationContext().getBean(name, clazz);
}
}
pom.xml
org.jodconverter
jodconverter-core
4.2.2
org.jodconverter
jodconverter-local
4.2.2
org.jodconverter
jodconverter-spring-boot-starter
4.2.2
org.icepdf.os
icepdf-core
6.2.2
javax.media
jai_core
org.icepdf.os
icepdf-viewer
6.2.2
3、调用测试:
importcom.yunfatong.ojd.service.FileSystemStorageService;importlombok.extern.slf4j.Slf4j;importorg.junit.Test;importorg.junit.runner.RunWith;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.boot.test.context.SpringBootTest;importorg.springframework.test.context.junit4.SpringRunner;importjava.util.List;
@RunWith(SpringRunner.class)
@SpringBootTest
@Slf4jpublic classWordTransferPdfUtilTest {
@Autowired
TransferUtil wordTransferPdfUtil;
@Autowired
FileSystemStorageService fileSystemStorageService;
@Testpublic voidtransferLocalFile() {
try {
/*******************word 转pdf******************/
long time = System.currentTimeMillis();
System.out.println("start :======" + time);
wordTransferPdfUtil.transferWordToPdf("courtChongqing/test_new/555.docx");
log.error(System.currentTimeMillis() + " time============================== :" + ((System.currentTimeMillis() - time) / 1000));
/*******************pdf转图片******************/
long time2 = System.currentTimeMillis();
List pdfImages2 = wordTransferPdfUtil.transferPdfToImage("courtChongqing/test_new/333.pdf");
for (String pdfImage : pdfImages2) {
log.error(pdfImage);
}
log.error(" time===============================22222222 :" + ((System.currentTimeMillis() - time2) / 1000));
// System.out.println("pdf path =============" + path);
} catch (Exception e) {
e.printStackTrace();
}
} }
原文:https://www.cnblogs.com/liran123/p/10883582.html