如何使用 Python 调用 LibreOffice API 创建文件、保存为不同的格式、导出为PDF、并添加密码保护

发表于

分类:

这两天研究了一下 LibreOffice 的 API 用法,在 Python 下做了一些实验,分享如下。

首先,从您的 LibreOffice 安装位置带参数运行 soffice.bin,如下(注意该命令会一直保持运行,可通过Ctrl+C结束运行):

$ /opt/libreofficedev7.1/program/soffice.bin "--accept=socket,host=localhost,port=2002;urp;"

然后,将如下Python代码保存到某个位置,假设文件名为hello_world.py:

import uno
from com.sun.star.beans import PropertyValue

localContext = uno.getComponentContext()
resolver = localContext.ServiceManager.createInstanceWithContext(
    "com.sun.star.bridge.UnoUrlResolver", localContext)
ctx = resolver.resolve( "uno:socket,host=localhost,port=2002;urp;StarOffice.ComponentContext")
smgr = ctx.ServiceManager
desktop = smgr.createInstanceWithContext( "com.sun.star.frame.Desktop", ctx)

''' 1. 创建空白文档
'''

model = desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, ())
text = model.Text
cursor = text.createTextCursor()

# 参考:https://api.libreoffice.org/docs/idl/ref/interfacecom_1_1sun_1_1star_1_1text_1_1XSimpleText.html
text.insertString( cursor, "Hello World", 0)
text.insertControlCharacter(cursor, uno.getConstantByName("com.sun.star.text.ControlCharacter.PARAGRAPH_BREAK"), 0)
text.insertString( cursor, "Hello World 2", 0)

''' 2. 通过 PropertyValue 之 FilterName 设置要保存的文档类型

若没有指定,则采用默认文档类型(不会根据文件名后缀判断)
PropertyValue的参数和属性,请参考:https://api.libreoffice.org/docs/idl/ref/structcom_1_1sun_1_1star_1_1beans_1_1PropertyValue.html

也可以通过这个选项来将文档导出为PDF或者图像。
完整的FilterName名称,可在LibreOffice源代码的 filter/source/config/fragments/filters 目录下找到。
比如:writer8.xcu中为 node oor:name="writer8",则ODF Text Document格式的API名称为 writer8
常见的:
    writer8.xcu            -> "writer8"
    writer_pdf_Export.xcu  -> "writer_pdf_Export"
    MS_Word_2007_XML.xcu   -> "MS Word 2007 XML"
'''
    
arg_odt = PropertyValue()
arg_odt.Name = "FilterName"
arg_odt.Value = "writer8"

arg_docx = PropertyValue()
arg_docx.Name = "FilterName"
arg_docx.Value = "MS Word 2007 XML"

arg_pdf = PropertyValue()
arg_pdf.Name = "FilterName"
arg_pdf.Value = "writer_pdf_Export"

''' 3. 通过 PropertyValue 设置其他保存选项
'''

# 比如,可以指定保存再打开后显示在文件 -> 属性中的文档标题:
arg_title = PropertyValue()
arg_title.Name = "DocumentTitle"
arg_title.Value = "Hello World"

# 再比如,可以给文档设置密码:
arg_pw = PropertyValue()
arg_pw.Name = "Password"
arg_pw.Value = "123456"

# 可以设置哪些PropertyValue,取决于你要将这些参数传递给谁。
# 如下面所示,我们需要传递给model.storeToURL。storeToURL可以接受的PropertyValue范围,请参考:
# https://api.libreoffice.org/docs/idl/ref/servicecom_1_1sun_1_1star_1_1document_1_1MediaDescriptor.html

''' 4. 保存文件
'''

# 首先需要将各个选项参数连接成一个 tuple.此处我们分四个不同的组合:
#    第一个用于保存为开放文档格式ODT,
#    第二个用于保存为微软的OOXML格式DOCX,
#    第三个用于导出为PDF,
#    第四个用于保存为带密码的开放文档格式ODT。
args_odt = (arg_odt, arg_title)
args_docx = (arg_docx, arg_title)
args_pdf = (arg_pdf, )
args_odt_protected = (arg_odt, arg_title, arg_pw)

# 文件的保存路径。注意是file:///形式的路径
file_path_odt = "file:///home/suokunlong/tmp/hello_world.odt"
file_path_docx = "file:///home/suokunlong/tmp/hello_world.docx"
file_path_pdf = "file:///home/suokunlong/tmp/hello_world.pdf"
file_path_odt_protected = "file:///home/suokunlong/tmp/hello_world_protected.odt"

# 保存
model.storeToURL(file_path_odt, args_odt)
model.storeToURL(file_path_docx, args_docx)
model.storeToURL(file_path_pdf, args_pdf)
model.storeToURL(file_path_odt_protected, args_odt_protected)

# 关闭文档(注意此时您通过命令行运行的 libreoffice 管道进程并不会通过以下代码关闭)
model.dispose()

最后,新建一个命令行窗口,通过以下命令用位于 LibreOffice 安装路径下的python解释器(注意不是您系统自身安装的python)来运行这段 hello_world.py 代码:

$ /opt/libreofficedev7.1/program/python ./hello_world.py

此时,你定义的保存路径下会生成四个文件:一个ODT文件,一个DOCX文件,一个PDF文件,还有一个受密码保护的ODT文件。

以上代码在Fedora 32下测试通过,使用的是最新的 LibreOffice 7.1分支构建版本。

以上示例是通过创建空白文档,然后对该空白文档进行操作的。当然,您可以修改代码,从而先读入现有的文档,然后进行后续操作。读文档时,只需要将上述完整代码中的以下代码:

model = desktop.loadComponentFromURL("private:factory/swriter", "_blank", 0, ())

修改为:(注意尖括号里的内容)

model = desktop.loadComponentFromURL(<文件路径>, "_blank", 0, <通过PropertyValue构造的打开文件的参数选项,比如FilterName, Password等>)

有任何问题,欢迎留言探讨。


评论:

《 “如何使用 Python 调用 LibreOffice API 创建文件、保存为不同的格式、导出为PDF、并添加密码保护” 》 有 10 条评论

  1. LWY

    发布于

    您好,我想问一下有windows下C++版本的示例代码吗?简单地打开指定文档的就行

    1. 见:
      https://api.libreoffice.org/examples/examples.html
      c++ examples中的DocumentLoader就是一个例子。

  2. xiu

    发布于

    我读取了一个excel文件,保存为pdf时要如何设置导出整页工作表这个选项

  3. moment

    发布于

    我想问下 支持pdf转ppt吗

  4. larry

    发布于

    请问java调用提示“Office process died with exit code 81; restarting it”是什么问题呢?

    1. Kevin Suo

      发布于

      能否在论坛发帖提供示例调用代码,让其他人看看?我不懂java,没试过。

  5. lsjweiyi

    发布于

    win10下运行有权限问题,不知如何解决:
    Traceback (most recent call last):
    File “./test.py”, line 86, in
    model.storeToURL(file_path_odt, args_odt)
    __main__.IOException: SfxBaseModel::impl_store failed: 0x507(Error Area:Io Class:Access Code:7)

    1. 运行该脚本的用户是否有file_path_odt指定的路径的写入权限?file_path_odt指向了哪里?

  6. 高原之狼

    发布于

    > 用位于 LibreOffice 安装路径下的python解释器(注意不是您系统自身安装的python)来运行

    关于这点我想补充一句:并不是必须使用 LO 安装路径下的 Python,确切地说是要使用编译 LO 时指定的 Python 来运行。对于 Windows 系统中,或像 Kevin 这样 Linux 系统中从官方下载 RPM 并装在 /opt 目录下的 LO,编译时指定了自带的 Python,所以要使用安装路径下的 Python。但是也有些情况,比如 Linux 发行版打包的 LO(Debian 肯定是这样,Fedora 很可能也是),会在编译时指定使用系统的 Python 而不是自带 Python,这时安装路径下也不会有 Python 解释器,直接用系统的 /usr/bin/python 就可以正常和 LO 通信了。

    具体编译时是靠一个选项指定用哪里的 Python 的,好像是叫 –with-system-python。

    1. Kevin Suo

      发布于

      --enable-python=no/auto/system/internal/fully-internal

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注