使用OpenOffice无头方式将Docx转换为PDF太慢

8 投票
3 回答
5939 浏览
提问于 2025-04-16 14:50

我一直在使用PHPWord来生成docx文件,效果很好。

但现在我需要把这些文件也转成pdf格式。

经过一番研究,我发现了PyODConverter,它使用了OOo(OpenOffice)。这个选项看起来不错,因为我不想依赖第三方的网络服务。我在自己的电脑上试了一下,运行得很好,所以我也把它应用到了我的服务器上。虽然花了点时间,但我也成功让它在服务器上运行了。

不过,有一个(糟糕的)问题。在服务器上,这个过程大约需要21秒,而在我的电脑上最多只要2秒。:(这对我来说时间太长了,所以我一直在寻找可能导致这个延迟的原因。

在无头模式下启动OpenOffice并创建socket是没问题的。

所以我开始查看这个python脚本,想找出哪个指令可能导致了慢速。我把问题缩小到了这一行:

context = resolver.resolve("uno:socket,host=127.0.0.1,port=8100;urp;StarOffice.ComponentContext")

这个操作大约需要20秒才能执行。

它插入的代码如下:

localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext("com.sun.star.bridge.UnoUrlResolver", localContext)
try:
    context = resolver.resolve("uno:socket,host=127.0.0.1,port=8100;urp;StarOffice.ComponentContext")
except NoConnectException:
    raise DocumentConversionException, "failed to connect to OpenOffice.org on port %s" % port
self.desktop = context.ServiceManager.createInstanceWithContext("com.sun.star.frame.Desktop", context)

有没有什么线索可以帮助我找出导致这个延迟的原因?

我已经排除了我尝试转换的文档,因为这个操作发生在那之前。

可能是'uno'的问题吗?或者是缺少其他库,导致在resolve()操作时进行不必要的测试?

欢迎任何想法。:)

最好的祝福,Restless

3 个回答

2

也许服务器上的名字解析器不知道 localhost 是什么(这听起来很奇怪,但20秒的延迟确实像是DNS超时)。你可以试着把它换成 127.0.0.1

另外,可能它在查找时没问题,能同时获取到 localhost 的IPv6和IPv4地址,但在尝试通过IPv6连接时失败了(也就是说,可能这个组件不支持IPv6,或者默认不绑定到那个接口),然后才退回去用IPv4。在这种情况下,解决办法也是一样:把 localhost 换成 127.0.0.1

2

真可惜,OpenOffice 太占空间了。我之前也考虑过用它,但后来发现了一个更轻便的选择,就是 AbiWord。

我需要从上传的文档中生成前四页的预览。这是我做的:

abiword document.doc --to=ps --exp-props="pages:1-4"
gs -q -dNOPAUSE -dBATCH -dTextAlphaBits=4  -dGraphicsAlphaBits=4 -r72 -sDEVICE=pnggray -sOutputFile=preview%d.png document.ps

所以你可以去下载最新的 AbiWord,然后试试这样的做法:

abiword document.docx --to=pdf
6

我通过使用管道而不是套接字来消除延迟。

context = resolver.resolve("uno:pipe,name=myuser_OOffice;urp;StarOffice.ComponentContext")

不过我还有一个问题……执行这个Python脚本的用户必须和启动OOo的用户是同一个,才能让一切正常工作。通常这不是个大问题,但我现在想从我的网页应用程序中执行Python,结果还是没能搞定。
我尝试了类似这样的方式:

exec('sudo -u#1000 -s python path/to/DocumentConverter.py filename.docx filename.pdf');

但是我什么也没得到……我不明白为什么。可能是运行exec()的用户(www-data)没有权限执行sudo吧??

撰写回答