.NET 采用开源软件OpenOffice 实现文档转码服务(word ppt excel)转PDF
前言
前几年做了个项目,里面有个需求,需要在浏览器中在线浏览word excel ppt pdf等文档。
最近又开始研究并记录下来
当时方案:
- 因为浏览器中阅读文档暂时只能通过pdf方式读取,所以就要想办法实现 word excel ppt 转为pdf文件实现在线浏览。
- 考虑到文件的安全性问题,一些在线的Saas服务就不考虑了,定制化本地安装的saas服务又不现实。
- .net 中已有一些组件可以实现word 转pdf了 如aspose.net , spire.doc for .net 等等,不过这些都是收费的。
- 微软的Office 也有提供com组件实现文档转码服务,前提是必须在Windows服务器上安装Office, 但Office同样需要license
- 考虑到成本问题。
最后采用了开源 OpenOffice +OpenOffice SDK 部署在Windows服务器中实现该需求
必要前提:
- 在windows服务器 framework 4 因为是好些年前的项目了,当时采用的是.net framework 4.6.1, Linux系统倒是没试过。
- OpenOffice 软件
- OpenOffice SDK 必须保证版本一致,否则会有问题。
正文:
以下是两个中间件服务
| 服务类型 | 服务名称 | 简称 | 描述 |
| Windows Service | Convert trigger Service | CTS | 目的是来监控输入文件夹,当文件夹{InputFolder}中存在文件后,会出发转码操作。 |
| Windows Console App | Convert Service | CS | 执行转码操作,会将{InputFolder}文件夹下的文件进行转码,并放置到{OutputFolder}目录下。 |
CTS服务采用Process类 调用CS 服务
以下是物理架构的关系图:

下面是CS服务中执行转码的核心代码。

1 public class OpenOfficeHelper : IOpenOffice
2 {
3 // For thread safety
4 private Mutex _openOfficeLock;
5
6 /// <summary>
7 /// constructor
8 /// </summary>
9 public OpenOfficeHelper()
10 {
11 _openOfficeLock = new Mutex(false, "OpenOfficeMutexLock-MiloradCavic");
12 }
13
14 /// <summary>
15 /// Converts document to PDF
16 /// </summary>
17 /// <param name="sourcePath">Path to document to convert(e.g: C:\test.doc)</param>
18 /// <param name="destinationPath">Path on which to save PDF (e.g: C:\test.pdf)</param>
19 /// <returns>Path to destination file if operation is successful, or Exception text if it is not</returns>
20 public void ConvertDocToPDF(string sourcePath, string destinationPath)
21 {
22 bool obtained = _openOfficeLock.WaitOne(60 * 1000, false);
23
24 XComponent xComponent = null;
25 try
26 {
27 if (!obtained)
28 {
29 throw new System.Exception(string.Format("Request for using OpenOffice wasn't served after {0} seconds. Aborting...", 30));
30 }
31
32 sourcePath = PathConverter(sourcePath);
33 destinationPath = PathConverter(destinationPath);
34
35 // 载入文件前属性设定,设定文件开启时隐藏
36 PropertyValue[] loadDesc = new PropertyValue[1];
37 loadDesc[0] = new PropertyValue();
38 loadDesc[0].Name = "Hidden";
39 loadDesc[0].Value = new uno.Any(true);
40
41 //Get a ComponentContext
42 unoidl.com.sun.star.uno.XComponentContext xLocalContext = uno.util.Bootstrap.bootstrap();
43
44 //Get MultiServiceFactory
45 unoidl.com.sun.star.lang.XMultiServiceFactory xRemoteFactory = (unoidl.com.sun.star.lang.XMultiServiceFactory)xLocalContext.getServiceManager();
46
47 //Get a CompontLoader
48 XComponentLoader aLoader = (XComponentLoader)xRemoteFactory.createInstance("com.sun.star.frame.Desktop");
49
50 //Load the sourcefile
51 xComponent = aLoader.loadComponentFromURL(sourcePath, "_blank", 0, new unoidl.com.sun.star.beans.PropertyValue[0]);
52
53 //Wait for loading
54 while (xComponent == null)
55 {
56 Thread.Sleep(3000);
57 }
58
59 SaveDocument(xComponent, destinationPath);
60
61 xComponent.dispose();
62
63 }
64 catch (System.Exception ex)
65 {
66 throw ex;
67 }
68 finally
69 {
70 Process[] pt = Process.GetProcessesByName("soffice.bin");
71 if (pt != null && pt.Length > 0)
72 {
73 foreach (var item in pt)
74 {
75 item.Kill();
76 }
77 }
78 if (obtained)
79 {
80 _openOfficeLock.ReleaseMutex();
81 }
82 }
83 }
84
85 /// <summary>
86 /// 执行保存
87 /// </summary>
88 /// <param name="xComponent">The x component.</param>
89 /// <param name="filePath">Name of the file.</param>
90 private void SaveDocument(XComponent xComponent, string filePath)
91 {
92 unoidl.com.sun.star.beans.PropertyValue[] propertyValue = new unoidl.com.sun.star.beans.PropertyValue[1];
93
94 propertyValue[0] = new unoidl.com.sun.star.beans.PropertyValue();
95 propertyValue[0].Name = "FilterName";
96 propertyValue[0].Value = new uno.Any("writer_pdf_Export");
97
98 ((XStorable)xComponent).storeToURL(filePath, propertyValue);
99 }
100
101 /// <summary>
102 /// Convert into OO file format
103 /// </summary>
104 /// <param name="file">The file.</param>
105 /// <returns>The converted file</returns>
106 private static string PathConverter(string file)
107 {
108 try
109 {
110 file = file.Replace(@"\", "/");
111
112 return "file:///" + file;
113 }
114 catch (System.Exception ex)
115 {
116 throw ex;
117 }
118 }
119
120
121 }
原理其实就是 调用了OpenOffice 软件,另存为成PDF文件。
CTS服务的代码就不放出来,其实就是起一个Timer 定时器,定时监控 {InputFolder}文件夹下是否存在待转码文件, 存在,则起一个Process 实例 执行CS应用进行转码操作即可。
踩坑记录:
接下来就是遇到的坑了
- 当执行第一次转码操作时,CS服务会调用OpenOffice软件,界面屏幕会弹出一个弹窗(这个弹出只会弹出一次,不会弹出了),这个弹窗内容是需要填写的基本名称,否则会导致OpenOffice一致停留在这个界面


- 但我们CTS服务默认是以Local System 账户运行的,而CS服务的启动是由 Windows Service 触发的, 所以OpenOffice软件其实是由Local System用户打开的,但Local System 打开没有界面弹窗的,无法填写,也就导致无法转码了。如何证明呢,看第三点。


- 查看任务管理器发现其实 OpenOffice 软件已经打开(进程为soffice.bin进程),而且运行用户正好就是Local System。

解决方案有两种:
- 新建一个Windows用户DocConverter,将该用户放到管理员组下,然后以该用户登录windows后,打开OpenOffice,第一次弹窗后 填写对应的基本信息后,将Windows Service 启动用户改为DocCoverter用户,然后再启动转码服务。 这时候会发现已经能够正常工作了。
- 想办法以Local System用户身份打开一次OpenOffice,然后填写OpenOffice的基本信息即可,怎么打开呢,这里借助PsTools工具,以cmd命令行模式打开即可, 下载PSTools,ps工具包 点我下载
(1)打开压缩包,将里面的psexec.exe复制到System32文件夹下(64位用户请将psexec64.exe复制到SysWOW64文件夹下)
(2)以管理员身份运行命令提示符,输入"psexec -i -d -s cmd.exe"(64位用户类似),等待1~2秒后,就会出现以system权限运行的命令提示符了
(3)在被启动的命令提示符里输入命令"whoami"并回车,会发现返回一条信息为"nt authority\system",说明此命令提示符已以本地系统的身份运行了。


基本上就是这样。
参考:
.NET 采用开源软件OpenOffice 实现文档转码服务(word ppt excel)转PDF的更多相关文章
- 【Python】读取各种文档(txt、csv、excel、pdf)方法
1.读取txt文件 注意事项: 1..txt文件同下方脚本所在的.py文件需要在同一个文件夹下 # coding=utf-8 txt读取 with open("1233.txt") ...
- 一款开源免费的.NET文档操作组件DocX(.NET组件介绍之一)
在目前的软件项目中,都会较多的使用到对文档的操作,用于记录和统计相关业务信息.由于系统自身提供了对文档的相关操作,所以在一定程度上极大的简化了软件使用者的工作量. 在.NET项目中如果用户提出了相关文 ...
- linkedin开源的kafka-monitor安装文档
linkedin开源的kafka-monitor安装文档 linkedin 开源的kafka-monitor的安装使用可以参考官方的readme:流程介绍的已经比较清楚,但是还是有一些地方需要修正.让 ...
- 电脑软件安装过程文档.BA
MD 01-打印并阅读-电脑软件安装过程文档.BAT-即此批处理脚本文档MD 02-阅读-电脑软件安装经验教训文档.DOCX-MD 03-制作-杏雨梨云USB维护系统2019中秋版之国庆更新-可启动U ...
- S01-晓亮的电脑软件安装过程文档 腾讯QQ 595076941 2019年10月
S01-晓亮的电脑软件安装过程文档 腾讯QQ 595076941 2019年10月 本文档的创建作者的腾讯QQ聊天号码是 595076941 S02-电脑软件安装过程中不要随意关闭窗口除非必需关闭窗口 ...
- 软件基础1Word文档编辑
word文档编辑 启动Word2010 创建文档,<你好word>. 编辑文字. 保存的三种方式. ctrl+s. 点击文件选择保存,或另存为. 快速工具栏保存按钮. 设置字体 1.通过工 ...
- java操作office和pdf文件java读取word,excel和pdf文档内容
在平常应用程序中,对office和pdf文档进行读取数据是比较常见的功能,尤其在很多web应用程序中.所以今天我们就简单来看一下Java对word.excel.pdf文件的读取.本篇博客只是讲解简单应 ...
- C# 基于NPOI+Office COM组件 实现20行代码在线预览文档(word,excel,pdf,txt,png)
由于项目需要,需要一个在线预览office的功能,小编一开始使用的是微软提供的方法,简单快捷,但是不符合小编开发需求, 就另外用了:将文件转换成html文件然后预览html文件的方法.对微软提供的方法 ...
- C# 导出word文档及批量导出word文档(4)
接下来是批量导出word文档和批量打印word文件,批量导出word文档和批量打印word文件的思路差不多,只是批量打印不用打包压缩文件,而是把所有文件合成一个word,然后通过js来调用 ...
- C#在线预览文档(word,excel,pdf,txt,png)
C#在线预览文档(word,excel,pdf,txt,png) 1.预览方式:将word文件转换成html文件然后预览html文件2.预览word文件:需要引入Interop.Microsoft.O ...
随机推荐
- #提交答案题#LOJ 6467 'Zip' Quine
题目 一种比较巧妙的方式 print 1 print 1 print 1 print 1 print 1 print 1 repeat 3 2 print 2 repeat 3 2 print 2 r ...
- #SG函数,记忆化搜索#HDU 4111 Alice and Bob
题目 Alice和Bob两个好朋友又开始玩取石子了. 游戏开始时,有\(n\)堆石子排成一排,然后他们轮流操作(Alice先手),每次操作时从下面的规则中任选一个: ·从某堆石子中取走一个 ·合并任意 ...
- 使用 GitLab CI/CD 和阿里云 CLI 自动部署前端项目
一.什么是 CI/CD? CI(持续交付)是功能迭代后自动构建.打包.校验代码格式.跑单测.单测覆盖率,常见的就是 Webpack.Rollup.ESLint等. CD(持续部署)是经过 CI 后,代 ...
- zbar:Qt调用zbar做条码识别
编译: zbar Windows编译:https://gitee.com/vvvj/zbar-windows 下载下来后,直接使用vs来编译就可以了. zbar官网:https://zbar.sour ...
- centos环境tomcat配置SSL
环境: centos7.9 tomcat9 jdk1.8 一.阿里云申请 免费SSL 按照官网的方法并未成功启动! 443 80端口加入安全组 阿里云申请免费ssl 下载后解压将localhost-r ...
- arp 的概念解析
前言 这里基于arp的基础概念,请先看前面那一节. 正文 看图: 和前面一样去解析地址. 以太网目的地址:就是mac地址. 在发送arp包的时候呢,这个mac地址就是全部是1,因为不知道对方地址是啥. ...
- Python 生成带Logo的圆角带边框二维码
Python 生成二维码方式就不累述了,不会的自己百度吧 但python生成的二维码太难看了,要么没有logo,要么logo直接贴进去的,难看死了,有的也处理了一下,但没有圆角,也难看: 以下:是不是 ...
- 简单介绍 Vue 3.0 项目创建
一.前期转杯 确保电脑上已安装 node.js. 可通过命令 npm --version进行查询,如果展示了版本号,则说明已安装,若提示 npm 不是有内部或外部命令,也不是可运行的程序,则说明未安装 ...
- C#的窗体假关闭操作例子 - 开源研究系列文章
晚上编码的时候,想到了以前编写的窗体关闭的事情,就是带托盘图标的应用,有一个主显示操作窗体,但是主窗体点击关闭按钮的时候,实际上是窗体隐藏而非真正关闭,这个在其它的一些应用程序里有这个效果.于是就想到 ...
- 什么是token,为什么需要token
1.为什么需要token 随着互联网的发展,为了更安全,以及更好的用户体验,逐渐产生了token这个技术方案 之所以使用token是因为http/https协议本身是无状态的,不能进行信息的存储 (c ...