Office文件转换预览解决方案(CentOS)

前言

对于Office的文件得在线预览基本有以下要求

  • 尽量支持Centos,否则文件要在不同服务器之间来回传输
  • 要支持在线预览
  • 要支持转换为PDF自行处理
  • 转换效果要好
  • 最好PPT支持动态效果

在这些前提下我们来看看常用得解决方案,以及最终得选择。

测试文件

http://wordupload.xhkjedu.com/resource/0/0.ppt

http://wordupload.xhkjedu.com/resource/0/0.docx

2.6M

http://wordupload.xhkjedu.com/resource/0/0.pdf

http://wordupload.xhkjedu.com/resource/665a33b7aacc4e81afea856ce4d9e4c3/83d58b6a09744c568604c7d3febadbb5.ppt

60.93MB

免费方案

JobConverter + OpenOffice/Ibreoffice

下载地址:https://mirrors.cloud.tencent.com/libreoffice/libreoffice/stable/

https://github.com/sbraconnier/jodconverter

https://blog.csdn.net/shixiansen6535/article/details/101672148

https://blog.csdn.net/qingtian_1993/article/details/79901843

自己开发转换或预览功能

特点

  • 基于OpenOffice或LiberOffice
  • 支持Window、CentOS、Ubuntu
  • PPT无动态预览效果
  • 可以本地部署

缺点

  • 转换效果不好
  • 部分转换失败

用微软提供的com组件实现

微软提供一个叫做SaveAsPDFandXPS的com组建来实现office转换成pdf。
java通过jacob来调用com组件
具体实现

  1. 安装office2007

  2. 安装SaveAsPDFandXPS

    说明:word、exccel、ppt转pdf用

  3. 安装Acrobat

    说明:pdf转图片用

  4. 配置jacob

    将jacob-1.18-x64.dll放置到用到的JDK/JRE目录的bin目录下

方案优点:

解决性能问题,完美解决兼容性问题

方案缺点:

需将转换服务单独部署,成为独立服务。

需要windows服务器。

需要实现linux系统和windows系统共享文件。(可以通过磁盘挂载的方式实现共享文件)

kkfileview

https://kkfileview.keking.cn/zh-cn/index.html

https://kkfileview.keking.cn/zh-cn/docs/production.html

在线预览:https://file.keking.cn/index

特点

  • 基于OpenOffice或LiberOffice

  • 支持Window、CentOS、Ubuntu

  • 支持Docker部署

  • 可以本地部署

缺点

  • PPT无动态预览效果

文件预览支持以下格式

  • 支持word excel ppt,pdf等办公文档

  • 支持txt,java,php,py,md,js,css等所有纯文本

  • 支持zip,rar,jar,tar,gzip等压缩包

  • 支持jpg,jpeg,png,gif等图片预览(翻转,缩放,镜像)

  • 支持mp3,mp4,flv等多媒体文件预览

XDOC

https://gitee.com/xdoc/xoffice

官方 http://view.xdocin.com/

特点

  • 基于MSOffice

  • 支持Window

  • 转换效果相对较好
  • 可以本地部署

缺点

  • PPT无动态预览效果

微软 office web app

https://www.cnblogs.com/lovechengcheng/p/4117391.html

https://www.cnblogs.com/yanweidie/p/4516164.html

https://github.com/marx-yu/WopiHost

特点

  • 基于MSOffice

  • 支持Window

  • PPT有动态预览效果

  • 转换效果相对较好
  • 可以本地部署

缺点

  • 部署要求较高

可以使用微软在线服务器或则自己搭建服务器

WPS WebOffice

官网 https://open.wps.cn/

体验地址 https://ljserver.cn/wpsonline/#/webFile

特点

  • PPT有动态预览效果
  • 转换效果相对较好

缺点

  • 不支持本地部署

收费方案

aspose-words

使用该jar处理

PageOffice

收费好多功能用不着

需要安装,不能动态播放ppt

http://www.zhuozhengsoft.com/

PPT无动态预览效果

WebOffice

官网 http://www.officectrl.com/

i doc view

官网 https://www.idocv.com/

演示 https://www.idocv.com/examples.html

PPT无动态预览效果

office web 365

官网 http://www.officeweb365.com/

永中office

https://www.yozodcs.com/page/example.html

ppt不支持动画,把动画播放后的页面展示了,近期要发布支持动画版本;

支持本地文件预览

展示

网页上展示文档的三种方式

(1)转换为PDF后加载

1
2
3
4
5
6
7
8
9
10
11
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Document</title>
</head>
<body>
<object data="http://wordupload.xhkjedu.com/resource/0/0.pdf" width="50%" height="700px"></object>
</body>
</html>

或者使用pdf.js:https://github.com/mozilla/pdf.js

(2)转换为PDF后转为图片加载

(3)单独的预览服务,在新地址中(新标签/iframe)预览

总结

总得来说

基于MSOffice的处理效果都会相对较好,但是必须Windows环境。

基于OpenOffice/Ibreoffice的优点也就是跨平台了。

如果项目只要求预览

  • 如果服务器为win推荐微软 office web app 支持动态效果
  • Centos推荐使用kkfileview 不支持动态效果

如果项目要能获取到图片

推荐使用JobConverter + OpenOffice/Ibreoffice

kkfileview使用

拉取镜像

1
docker pull keking/kkfileview

运行

1
docker run -it -p 8012:8012 keking/kkfileview

访问

浏览器访问容器8012端口(http://xxx.xxx.xxx.xxx:8012 )即可看到项目演示用首页

http://doctest.xhkjedu.com:8200

当您的项目内需要预览文件时,只需要调用浏览器打开本项目的预览接口,并传入须要预览文件的url,示例如下:

1
2
var previewUrl = 'http://127.0.0.1:8080/file/test.txt'; //要预览文件的访问地址
window.open('http://127.0.0.1:8012/onlinePreview?url='+encodeURIComponent(previewUrl));

CentOS上部署JobConverter + Ibreoffice环境

官网:https://zh-cn.libreoffice.org/download/libreoffice/

参数说明:https://help.libreoffice.org/Common/Starting_the_Software_With_Parameters/zh-CN

安装Ibreoffice

用YUM安装

查看

1
yum list libreoffice

结果

可安装的软件包
libreoffice.x86_64 1:5.3.6.1-24.el7

可以看出yum上只有5.3版本

安装

1
2
3
4
5
6
# 卸载原来的
yum remove libreoffice-*
# 安装
yum install libreoffice
# 安装中文语言包
yum install libreoffice-langpack-zh-Han*

查看版本

1
soffice --version

转换

1
soffice --headless --convert-to pdf /usr/local/office_package/0.docx --outdir /usr/local/office_package/

注意

libreoffice和openoffice原来是一家,所以早期版本的libreoffice命令和openoffice一样,后来版本的libreoffice就变了

官方下载安装

下载

1
wget https://mirror-hk.koddos.net/tdf/libreoffice/stable/6.4.4/rpm/x86_64/LibreOffice_6.4.4_Linux_x86-64_rpm.tar.gz

移动

1
2
mkdir /usr/local/office_package/
mv LibreOffice_6.4.4_Linux_x86-64_rpm.tar.gz /usr/local/office_package/

解压

1
2
cd /usr/local/office_package/
tar -zxvf LibreOffice_6.4.4_Linux_x86-64_rpm.tar.gz

安装

1
2
cd /usr/local/office_package/LibreOffice_6.4.4.2_Linux_x86-64_rpm/RPMS/
yum localinstall *.rpm

下载汉化包

1
2
cd /usr/local/office_package/
wget http://download.documentfoundation.org/libreoffice/stable/6.4.4/rpm/x86_64/LibreOffice_6.4.4_Linux_x86-64_rpm_langpack_zh-CN.tar.gz

解压

1
tar -zxvf LibreOffice_6.4.4_Linux_x86-64_rpm_langpack_zh-CN.tar.gz

进入目录安装

1
2
cd /usr/local/office_package/LibreOffice_6.4.4.2_Linux_x86-64_rpm_langpack_zh-CN/RPMS/
yum localinstall *.rpm

查看可执行文件位置

1
which libreoffice6.4

查看具体安装位置

1
ll /usr/bin/libreoffice6.4

卸载

1
yum erase libreoffice\*

安装字体

在转换中我们会发现转换的pdf和原文档字体是有差异的,是因为系统上没有我们需要的字体,所以我们要安装字体

查看现有字体

1
fc-list

在CentOS 4.x开始用fontconfig来安装字体库

所以输入以下命令即可:

1
yum -y install fontconfig

打开目录

1
cd /usr/share/

我们会看到fontsfontconfig目录

添加字体

创建目录并进入

1
mkdir /usr/share/fonts/chinese

在Windows上找到C://Windows/Fonts下最后几列中文名称的字体都上传到/usr/share/fonts/chinese

设置目录权限

1
chmod -R 755 /usr/share/fonts/chinese

修改字体配置文件了,首先通过编辑器打开配置文件:

1
vi /etc/fonts/fonts.conf

可以看到一个Font list,即字体列表,在这里需要把我们添加的中文字体位置加进去:

1
<dir>/usr/share/fonts/chinese</dir>

接下来需要安装ttmkfdir来搜索目录中所有的字体信息,并汇总生成fonts.scale文件,

输入命令:

1
yum -y install ttmkfdir

然后执行ttmkfdir命令即可:

1
2
cd /usr/share/fonts/chinese &&\
ttmkfdir -e /usr/share/X11/fonts/encodings/encodings.dir

最后别忘了刷新内存中的字体缓存,这样就不用reboot重启了:

1
fc-cache

这样所有的步骤就算完成了,最后再次通过fc-list看一下字体列表:

1
fc-list

转换测试

下载doc文档

1
2
cd /usr/local/office_package/
wget http://wordupload.xhkjedu.com/resource/0/0.docx

转换参数

1
2
3
--convert-to pdf:writer_pdf_Export 1.doc
--convert-to "html:XHTML Writer File:UTF8" 1.doc
--convert-to "txt:Text (encoded):UTF8" 1.doc

可以简写为

1
2
3
--convert-to pdf 1.doc
--convert-to html 1.doc
--convert-to txt 1.doc

docx=>pdf

1
libreoffice6.4 --headless --invisible --convert-to pdf /usr/local/office_package/5.docx --outdir /usr/local/office_package/

或者

1
libreoffice6.4 --headless --invisible --convert-to pdf:writer_pdf_Export /usr/local/office_package/5.docx --outdir /usr/local/office_package/

或者

1
2
libreoffice6.4 -env:UserInstallation=file:///$HOME/.libreoffice-headless/ \
--headless --invisible --convert-to pdf /usr/local/office_package/0.docx --outdir /usr/local/office_package/

我这里直接就成功了

docx=>jpg

1
libreoffice6.4 --headless --invisible --convert-to jpg /usr/local/office_package/0.docx --outdir /usr/local/office_package/

或者

1
2
libreoffice6.4 -env:UserInstallation=file:///$HOME/.libreoffice-headless/ \
--headless --invisible --convert-to jpg /usr/local/office_package/5.docx --outdir /usr/local/office_package/

docx=>html

1
2
libreoffice6.4 -env:UserInstallation=file:///$HOME/.libreoffice-headless/ \
--headless --invisible --convert-to html /usr/local/office_package/5.docx --outdir /usr/local/office_package/

报错解决

错误1

/opt/libreoffice6.4/program/soffice.bin: error while loading shared libraries: libcairo.so.2: cannot open shared object file: No such file or directory

原因是 libcairo.so.2 这个库找不到,我们下载安装就可以了

安装命令如下

1
2
3
yum install cairo -y
yum install cups-libs -y
yum install libSM -y

错误2

问题描述:

Libreoffice发生转换不成功(比如转换wps文件),再做转换就会直接不做任何操作

当你运行其中一个LibreOffice的时候,再运行另外一个Libreoffice转换时,将不做任何操作。

解决方法 添加-env:UserInstallation=file:///$HOME/.libreoffice-headless/参数

5.3版本

1
2
soffice -env:UserInstallation=file:///$HOME/.libreoffice-headless/ \
--convert-to pdf /usr/local/office_package/0.docx --outdir /usr/local/office_package/

6.4版本

1
2
libreoffice6.4 -env:UserInstallation=file:///$HOME/.libreoffice-headless/ \
--headless --invisible --convert-to pdf /usr/local/office_package/0.docx --outdir /usr/local/office_package/

或者

1
2
libreoffice6.4 -env:UserInstallation=file:///$HOME/.libreoffice-headless/ \
--headless --invisible --convert-to pdf:writer_pdf_Export /usr/local/office_package/5.docx --outdir /usr/local/office_package/

导致这种问题的原因时有转换进程一直在运行,所以我们也可以杀掉进程

1
top

或者

1
top -bc |grep soffice.bin

查看卡死的进程杀死即可

1
kill -9 进程id

后端中使用

运行命令形式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
/**
* 利用libreOffice将office文档转换成pdf
* @param inputFile 目标文件地址
* @param pdfFile 输出文件夹
* @return
*/
public static boolean convertOffice2PDF(String inputFile, String pdfFile){
long start = System.currentTimeMillis();
String command;
boolean flag;
String osName = System.getProperty("os.name");
if (osName.contains("Windows")) {
command = "cmd /c start soffice --headless --invisible --convert-to pdf " + inputFile + " --outdir " + pdfFile;
}else {
command = "libreoffice6.4 --headless --invisible --convert-to pdf " + inputFile + " --outdir " + pdfFile;
}
flag = executeLibreOfficeCommand(command);
long end = System.currentTimeMillis();
logger.debug("用时:{} ms", end - start);
return flag;
}


/**
* 执行command指令
* @param command
* @return
*/
public static boolean executeLibreOfficeCommand(String command) {
logger.info("开始进行转化.......");
Process process;// Process可以控制该子进程的执行或获取该子进程的信息
try {
logger.debug("convertOffice2PDF cmd : {}", command);
process = Runtime.getRuntime().exec(command);// exec()方法指示Java虚拟机创建一个子进程执行指定的可执行程序,并返回与该子进程对应的Process对象实例。
// 下面两个可以获取输入输出流
// InputStream errorStream = process.getErrorStream();
// InputStream inputStream = process.getInputStream();
} catch (IOException e) {
logger.error(" convertOffice2PDF {} error", command, e);
return false;
}
int exitStatus = 0;
try {
exitStatus = process.waitFor();// 等待子进程完成再往下执行,返回值是子线程执行完毕的返回值,返回0表示正常结束
// 第二种接受返回值的方法
int i = process.exitValue(); // 接收执行完毕的返回值
logger.debug("i----" + i);
} catch (InterruptedException e) {
logger.error("InterruptedException convertOffice2PDF {}", command, e);
return false;
}
if (exitStatus != 0) {
logger.error("convertOffice2PDF cmd exitStatus {}", exitStatus);
} else {
logger.debug("convertOffice2PDF cmd exitStatus {}", exitStatus);
}
process.destroy(); // 销毁子进程
logger.info("转化结束.......");
return true;
}

使用三方库

添加依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<dependency>
<groupId>commons-io</groupId>
<artifactId>commons-io</artifactId>
<version>2.4</version>
</dependency>

<dependency>
<groupId>cn.keking</groupId>
<artifactId>jodconverter-core</artifactId>
<version>1.0-SNAPSHOT</version>
<exclusions>
<exclusion>
<artifactId>commons-io</artifactId>
<groupId>commons-io</groupId>
</exclusion>
</exclusions>
</dependency>

Java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
public static String toPdf(String srcPath, String desPath) throws OfficeException {
// 源文件目录
File inputFile = new File(srcPath);
if (!inputFile.exists()) {
System.out.println("源文件不存在!");
return "源文件不存在";
}
// 输出文件目录
File outputFile = new File(desPath);
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().exists();
}
// 连接OpenOffice/LibreOffice服务
OfficeManager officeManager = LocalOfficeManager.builder().officeHome("/opt/libreoffice6.4").install().build();
try {
officeManager.start();
// 转换文档到pdf
long time = System.currentTimeMillis();
JodConverter.convert(inputFile).to(outputFile).execute();
System.out.println(String.format("文件:%s转换PDF:%s完成,用时%s毫秒!", srcPath, desPath, (System.currentTimeMillis() - time) + ""));
} catch (OfficeException e) {
System.out.println(String.format("文件:%s转换PDF:%s失败!", srcPath, desPath));
return "OfficeException文件转换失败";
} finally {
// 关闭连接
OfficeUtils.stopQuietly(officeManager);
}
System.out.println("转换结束");
return "OfficeException文件转换失败";
}

结论

  • 字体没有会导致转换后差异
  • WPS文件无论转为doc或docx都无法转换
  • 图片类型为嵌入型时部分转换图片丢失

CentOS上部署JobConverter + OpenOffice环境

下载安装

打开目录

1
cd /usr/local/office_package/

下载地址

1
wget https://jaist.dl.sourceforge.net/project/openofficeorg.mirror/4.1.7/binaries/zh-CN/Apache_OpenOffice_4.1.7_Linux_x86-64_install-rpm_zh-CN.tar.gz

解压

1
tar -zxvf Apache_OpenOffice_4.1.7_Linux_x86-64_install-rpm_zh-CN.tar.gz

进入

1
cd zh-CN/RPMS/

安装

1
2
3
yum localinstall *.rpm
cd desktop-integration
rpm -ivh openoffice4.1.7-redhat-menus-4.1.7-9800.noarch.rpm

命令执行完成之后,在opt文件目录中,会出现”openoffice4“文件夹,说明安装成功。

启动转换

启动

1
/opt/openoffice4/program/soffice -headless -accept="socket,host=127.0.0.1,port=8100;urp;" -nofirststartwizard &

查看是否启动成功

1
netstat -nltp|grep 8100

成功提示

tcp 0 0 127.0.0.1:8100 0.0.0.0:* LISTEN 14118/soffice.bin

下载地址

https://sourceforge.net/projects/jodconverter/files/JODConverter/

文件转换

1
java -jar jodconverter-cli-2.2.2.jar 0.docx 00.pdf

注意

只有jodconverter-cli-2.2.2.jar是不行的 压缩包中的jar都要使用

项目中使用

1
2
3
4
5
6
7
8
<dependencies>
<!-- https://mvnrepository.com/artifact/org.jodconverter/jodconverter-local -->
<dependency>
<groupId>org.jodconverter</groupId>
<artifactId>jodconverter-local</artifactId>
<version>4.2.0</version>
</dependency>
</dependencies>

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
public static void Word2Pdf(String srcPath, String desPath) throws IOException {
// 源文件目录
File inputFile = new File(srcPath);
if (!inputFile.exists()) {
System.out.println("源文件不存在!");
return;
}
// 输出文件目录
File outputFile = new File(desPath);
if (!outputFile.getParentFile().exists()) {
outputFile.getParentFile().exists();
}
// 连接OpenOffice/LibreOffice服务
OfficeManager officeManager = LocalOfficeManager.builder().officeHome("/opt/openoffice4").install().build();
try {
officeManager.start();
// 转换文档到pdf
long time = System.currentTimeMillis();
JodConverter.convert(inputFile).to(outputFile).execute();
logger.info("文件:{}转换PDF:{}完成,用时{}毫秒!", srcPath, desPath, System.currentTimeMillis() - time);
} catch (OfficeException e) {
e.printStackTrace();
logger.warn("文件:{}转换PDF:{}失败!", srcPath, desPath);
} finally {
// 关闭连接
OfficeUtils.stopQuietly(officeManager);
}
}

卸载

1
rpm -e `rpm -qa |grep openoffice` `rpm -qa |grep ooobasis`

常见错误

错误1

file /usr/bin/soffice from install of openoffice4.1.7-redhat-menus-4.1.7-9800.noarch conflicts with file from package libreoffice-core-1:5.3.6.1-24.el7.x86_64

原因是安装过libreoffice,卸载即可

1
yum remove libreoffice-*

错误2

javaldx: invalid settings. User must select a JRE from options dialog!

不影响运行不用处理

结论

  • 字体没有会导致转换后差异
  • WPS文件无论转为doc或docx都无法转换
  • 图片类型为嵌入型时部分转换图片丢失

转换结果和Ibreoffice没啥差异 弊端也都一样

aspose-words处理

下载及测试

aspose-words-18.6-jdk16

链接: https://pan.baidu.com/s/1r1gEi7ek5XAfEz6cczX96A 提取码: tavz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
import com.aspose.words.Document;
import com.aspose.words.License;
import com.aspose.words.SaveFormat;

import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

public class Main {

public static void main(String[] args) throws Exception {
docx2pdf("/Users/psvmc/Downloads/0/7.docx", "/Users/psvmc/Downloads/0/7.pdf");
}

/**
* 使用Aspose.Words前都要验证License 若不验证则转化出的pdf文档有水印
*
* @return
* @throws Exception
*/
public static boolean checkLicense() throws Exception {
boolean result = false;
try {
InputStream is = com.aspose.words.Document.class
.getResourceAsStream("/com.aspose.words.lic_2999.xml");
License asposeLicense = new License();
asposeLicense.setLicense(is);
System.out.println("验证License: " + asposeLicense.isLicensed());
result = true;
is.close();
} catch (Exception e) {
e.printStackTrace();
throw e;
}
return result;
}

public static void docx2pdf(String inPath, String outPath) throws Exception {
if (!checkLicense()) {
throw new Exception("com.aspose.words lic ERROR!");
}
System.out.println(inPath + " -> " + outPath);

try {
long old = System.currentTimeMillis();
File file = new File(outPath);
FileOutputStream os = new FileOutputStream(file);
Document doc = new Document(inPath); // word文档
// 支持RTF HTML,OpenDocument, PDF,EPUB, XPS转换
doc.save(os, SaveFormat.PDF);
long now = System.currentTimeMillis();
System.out.println("convert OK! " + ((now - old) / 1000.0) + "秒");
} catch (Exception e) {
e.printStackTrace();
}
}

/**
* docx转doc 需引入 aspose-words-16.4.0-jdk16.jar包 收费插件windows linux下均可用
* <p>
* wps不兼容docx的表格跨列合并,微信文件预览不支持docx下的表格
* 转换为doc格式的可以被wps兼容 微信可预览表格
*
* @param inPath 源文件路径
* @param outPath 输出文件路径
*/
public static void docx2doc(String inPath, String outPath) throws Exception {
if (!checkLicense()) {
throw new Exception("com.aspose.words lic ERROR!");
}
System.out.println(inPath + " -> " + outPath);
try {
File file = new File(outPath); // 新建一个空白pdf文档
FileOutputStream os = new FileOutputStream(file);
com.aspose.words.Document doc = new com.aspose.words.Document(inPath); // Address是将要被转化的word文档
doc.save(os, SaveFormat.DOC);// 全面支持DOC, DOCX, OOXML, RTF HTML, OpenDocument, PDF,EPUB, XPS, SWF 相互转换
} catch (Exception e) {
e.printStackTrace();
}
}
}

结论

  • 处理文字行间距过大
  • 部分wps创建的文件无法转换

使用WPS转换(Windows环境)

这个也是COM方案,不同的是MSOffice换成了WPS,从而解决部分文件转换失败的问题。

相关jar和DLL

链接: https://pan.baidu.com/s/1yWaqdL0a-YWRiSP75ZSUPA 密码: rvi4

DLL根据系统是否64位选择对应的放到JDK目录下的bin目录中

其它jar引入项目中

工具类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
import java.awt.Color;
import java.awt.Rectangle;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.lang.reflect.Method;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.security.AccessController;
import java.security.PrivilegedAction;


import com.jacob.activeX.ActiveXComponent;
import com.jacob.com.ComThread;
import com.jacob.com.Dispatch;
import com.jacob.com.Variant;
import com.lowagie.text.Document;
import com.lowagie.text.DocumentException;
import com.lowagie.text.Element;
import com.lowagie.text.Font;
import com.lowagie.text.FontFactory;
import com.lowagie.text.Image;
import com.lowagie.text.PageSize;
import com.lowagie.text.Phrase;
import com.lowagie.text.pdf.ColumnText;
import com.lowagie.text.pdf.PdfContentByte;
import com.lowagie.text.pdf.PdfWriter;
import com.sun.image.codec.jpeg.JPEGCodec;
import com.sun.image.codec.jpeg.JPEGImageEncoder;
import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;

public class PdfUtil {
// 文档格式转换组件
public static final String WORDSERVER_STRING = "KWPS.Application";
// 幻灯片格式转换组件
public static final String PPTSERVER_STRING = "KWPP.Application";
// 表格格式转换组件
public static final String EXECLSERVER_STRING = "KET.Application";
private static final int wdFormatPDF = 17;
private static final int xlTypePDF = 0;
private static final int ppSaveAsPDF = 32;


public PdfUtil() {
}


/**
* @param srcFilePath            文档路径
* @param pdfFilePath            pdf路径
* @return void
* @throws Exception
* @throws
* @Description: 文档格式转换 支持 wps、wpt、doc、docx、dot、txt等所有文档格式文件
* @author JornTang
* @email 957707261@qq.com
* @date 2017年9月14日
*/
public static boolean wpsTopdf(String srcFilePath, String pdfFilePath)
throws Exception {
// wps com
ActiveXComponent pptActiveXComponent = null;
ActiveXComponent workbook = null;
// open thred
ComThread.InitSTA();
try {
pptActiveXComponent = new ActiveXComponent(WORDSERVER_STRING);
Variant openParams[] = {new Variant(srcFilePath),
new Variant(true), new Variant(true)};
workbook = pptActiveXComponent.invokeGetComponent("Documents")
.invokeGetComponent("Open", openParams);
workbook.invoke("SaveAs", new Variant[]{new Variant(pdfFilePath),
new Variant(wdFormatPDF)});
} catch (Exception e) {
throw e;
} finally {
if (workbook != null) {
workbook.invoke("Close");
workbook.safeRelease();
}
if (pptActiveXComponent != null) {
pptActiveXComponent.invoke("Quit");
pptActiveXComponent.safeRelease();
}
// close thred
ComThread.Release();
}
return true;
}


/**
* @param srcFilePath            幻灯片路径
* @param pdfFilePath            pdf路径
* @return boolean
* @throws
* @Description: 幻灯片格式转换 支持ppt、pps、pptx、ppsx、dps、dpt、pot、uof
* @author JornTang
* @date 2017年9月14日
*/
public static boolean pptTopdf(String srcFilePath, String pdfFilePath) {
ActiveXComponent pptActiveXComponent = null;
ActiveXComponent workbook = null;
boolean readonly = true;
ComThread.InitSTA();
try {
pptActiveXComponent = new ActiveXComponent(PPTSERVER_STRING);
workbook = pptActiveXComponent.invokeGetComponent("Presentations")
.invokeGetComponent(
"Open",
new Variant[]{new Variant(srcFilePath),
new Variant(readonly)});
workbook.invoke("SaveAs", new Variant[]{new Variant(pdfFilePath),
new Variant(ppSaveAsPDF)});
return true;
} catch (Exception e) {
throw e;
} finally {
if (workbook != null) {
workbook.invoke("Close");
workbook.safeRelease();
}
if (pptActiveXComponent != null) {
pptActiveXComponent.invoke("Quit");
pptActiveXComponent.safeRelease();
}
ComThread.Release();
}
}

/**
* @param srcFilePath            幻灯片路径
* @param pdfFilePath            pdf路径
* @return boolean
* @throws
* @Description: 表格格式转换 支持et、ett、xls、xlsx、xlt、uof、prn、csv
* @author JornTang
* @date 2017年9月14日
*/
public static boolean xlsTopdf(String srcFilePath, String pdfFilePath) {
ActiveXComponent et = null;
Dispatch workbook = null;
workbook = null;
ComThread.InitSTA();
try {
et = new ActiveXComponent(EXECLSERVER_STRING);
et.setProperty("Visible", new Variant(false));
Dispatch workbooks = et.getProperty("Workbooks").toDispatch();
workbook = Dispatch.invoke(
workbooks,
"Open",
1,
new Object[]{srcFilePath, Integer.valueOf(xlTypePDF),
Boolean.valueOf(true)}, new int[1]).toDispatch();
Dispatch.call(workbook, "ExportAsFixedFormat", new Object[]{
Integer.valueOf(xlTypePDF), pdfFilePath});
return true;
} catch (Exception e) {
throw e;
} finally {
if (workbook != null) {
Dispatch.call(workbook, "Close");
workbook.safeRelease();
}
if (et != null) {
et.invoke("Quit");
et.safeRelease();
}
ComThread.Release();
}
}


/**
* @param imagePath
* @param pdfFilePath
* @return boolean
* @throws DocumentException
* @throws IOException
* @throws
* @Description: 图片转pdf
* @author JornTang
* @date 2017年9月14日
*/
public static boolean iamgeTopdf(String imagePath, String pdfFilePath)
throws DocumentException, IOException {
File pdfFile = new File(pdfFilePath);
if (pdfFile.exists()) {
throw new FileNotFoundException("pdfFilePath already exists");
}
Document doc = new Document(PageSize.A4, 20, 20, 20, 20);
try {
PdfWriter.getInstance(doc, new FileOutputStream(
pdfFilePath));
doc.open();
doc.newPage();
Image png1 = Image.getInstance(imagePath);
float heigth = png1.getHeight();
float width = png1.getWidth();
int percent = getPercent(heigth, width);
png1.setAlignment(Image.MIDDLE);
png1.setAlignment(Image.TEXTWRAP);
png1.scalePercent(percent + 3);
doc.add(png1);
doc.close();
return true;
} catch (FileNotFoundException e) {
throw e;
} catch (DocumentException e) {
throw e;
} catch (IOException e) {
throw e;
}
}

/**
* @param writer
* @param content
* @param color
* @param x
* @param y
* @param z   
* @return void  
* @throws
* @Description: 添加文字
* @author JornTang
* @date 2017年9月14日
*/
private static void handleText(PdfWriter writer, String content, String color,
float x, float y, float z) {
PdfContentByte canvas = writer.getDirectContent();
Phrase phrase = new Phrase(content);
if (color != null) {
phrase = new Phrase(content, FontFactory.getFont(
FontFactory.COURIER, 12, Font.NORMAL, new Color(255, 0, 0)));
}


ColumnText.showTextAligned(canvas, Element.ALIGN_UNDEFINED, phrase, x,
y, z);
}

/**
* @param h
* @param w
* @return int  
* @throws
* @Description: 在不改变图片形状的同时,判断,如果h>w,则按h压缩,否则在w>h或w=h的情况下,按宽度压缩
* @author JornTang
* @date 2017年9月14日
*/
public static int getPercent1(float h, float w) {
int p = 0;
float p2 = 0.0f;
if (h > w) {
p2 = 297 / h * 100;
} else {
p2 = 210 / w * 100;
}
p = Math.round(p2);
return p;
}

/**
* @param h
* @param w
* @return int  
* @throws
* @Description: 统一按照宽度压缩 这样来的效果是,所有图片的宽度是相等的,自我认为给客户的效果是最好的 
* @author JornTang
* @date 2017年9月14日
*/
private static int getPercent(float h, float w) {
int p = 0;
float p2 = 0.0f;
p2 = 530 / w * 100;
p = Math.round(p2);
return p;
}


/**
* @param pdfFilePath
* @param imageFilePath
* @return void
* @throws IOException
* @throws
* @Description: pdf转图片
* @author JornTang
* @date 2017年9月14日
*/
public static void pdfTojpg(String pdfFilePath, String imageFilePath, int density)
throws Exception {
ByteBuffer buf = null;
RandomAccessFile raf = null;
FileChannel channel = null;
try {
// load a pdf from a byte buffer
File file = new File(pdfFilePath);
raf = new RandomAccessFile(file, "r");
channel = raf.getChannel();
// 这句代码通道建立了map映射,如果要删除file那么得接触映射
buf = channel.map(FileChannel.MapMode.READ_ONLY, 0, channel.size());
PDFFile pdffile = new PDFFile(buf);
int totalpage = pdffile.getNumPages();
System.out.println("总共几页:" + totalpage);
for (int i = 1; i <= totalpage; i++) {
// draw the first page to an image
// 以图片的形式来描绘首页
PDFPage page = pdffile.getPage(i);
Rectangle rect = new Rectangle(0, 0, (int) page.getBBox()
.getWidth(), (int) page.getBBox().getHeight());
// generate the image
// 生成图片
java.awt.Image img = page.getImage(rect.width * density, rect.height * density,
rect, // clip rect
null, // null for the ImageObserver
true, // fill background with white
true // block until drawing is done
);
BufferedImage tag = new BufferedImage(rect.width * density,
rect.height * density, BufferedImage.TYPE_INT_RGB);
tag.getGraphics().drawImage(
img.getScaledInstance(
rect.width * density,
rect.height * density,
java.awt.Image.SCALE_SMOOTH
), 0, 0,
rect.width * density,
rect.height * density,
null
);

String filename = file.getName();
filename = filename.substring(0, filename.indexOf("."));

String imge = imageFilePath + filename + "_" + i + ".jpg";
FileOutputStream out = new FileOutputStream(imge); // 输出到文件流
JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);
encoder.encode(tag); // JPEG编码
// 关闭输出流
out.close();
//break;

}
} catch (Exception e) {
throw e;
} finally {
buf.clear();
channel.close();
raf.close();
unmap(buf);
}
}


/**
* @param buffer
* @return void
* @throws
* @Description: 解除map映射
* @author JornTang
* @date 2017年9月14日
*/
public static <T> void unmap(final Object buffer) {
AccessController.doPrivileged(new PrivilegedAction<T>() {
@Override
public T run() {
try {
Method getCleanerMethod = buffer.getClass().getMethod(
"cleaner", new Class[0]);
getCleanerMethod.setAccessible(true);
sun.misc.Cleaner cleaner = (sun.misc.Cleaner) getCleanerMethod
.invoke(buffer, new Object[0]);
cleaner.clean();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}


public static void main(String[] args) {
try {
pdfTojpg("D:\\school\\0.pdf", "D:\\school\\", 3);
} catch (Exception e) {
e.printStackTrace();
}
}
}

使用WPS转换(CentOS环境)

暂时还未找到CentOS下调用wps转换的方法。

下载地址http://community.wps.cn/download/

下载

1
2
cd /usr/local/office_package/ &&\
wget https://wdl1.cache.wps.cn/wps/download/ep/Linux2019/9522/wps-office-11.1.0.9522-1.x86_64.rpm

安装依赖

1
2
3
4
yum install -y libpng12 &&\
yum install -y libGLU &&\
yum install -y libpulse-mainloop-glib* &&\
yum install -y libXss*

安装

1
rpm -ivh wps-office-11.1.0.9522-1.x86_64.rpm

PDF转图片

将pdf转成图片,安装ImageMagick

1
yum install ImageMagick

转换

1
convert -verbose -density 160 -trim 0.pdf -quality 90 0.jpg

会生成0-0.jpg,0-1.jpg,0-2.jpg