使用libreofficekit操作Office文档

在C++中操作Office文档,有几种方法。

在Windows环境下面,可以使用COM调用,在Qt开发之中,通过QtActive的QAxObject来操作Microsoft Office的COM。

而在Linux等环境中,则可以使用libreoffice的libreofficekit。

libreoffice简介

根据libreoffice的官网介绍:

LibreOffice 是一款功能强大的办公软件,默认使用开放文档格式 (OpenDocument Format , ODF), 并支持 *.docx, *.xlsx, *.pptx 等其他格式。  

它包含了 Writer, Calc, Impress, Draw, Base 以及 Math 等组件,可用于处理文本文档、电子表格、演示文稿、绘图以及公式编辑。

它可以运行于 Windows, GNU/Linux 以及 macOS 等操作系统上,并具有一致的用户体验。

准备libreofficekit开发库

libreofficekit的二进制分发,默认没有开发需要的头文件以及库文件,需要单独安装。

Fedora等使用rpm软件包的系统可以通过:

sudo dnf install libreofficekit-devel

来安装,Ubuntu等使用deb软件包的系统,包名字则是libreofficekit-dev。

如:

sudo apt install libreofficekit-dev

libreofficekit的开发包文件比较简单,甚至没有提供一个pkg-config脚本文件,也没有cmake文件。

只是把需要的几个头文件,都放在了一个目录里。

在Fedora系统里,libreofficekit-devel安装完文件列表如下:

~/$ rpm -ql libreofficekit-devel  
/usr/include/LibreOfficeKit  
/usr/include/LibreOfficeKit/LibreOfficeKit.h  
/usr/include/LibreOfficeKit/LibreOfficeKit.hxx  
/usr/include/LibreOfficeKit/LibreOfficeKitEnums.h  
/usr/include/LibreOfficeKit/LibreOfficeKitGtk.h  
/usr/include/LibreOfficeKit/LibreOfficeKitInit.h  
/usr/include/LibreOfficeKit/LibreOfficeKitTypes.h  
/usr/lib64/gir-1.0/LOKDocView-0.1.gir

所以,我们开发程序的时候,直接把/usr/include/LibreOfficeKit目录加入头文件目录就好了,否则就需要多写一层目录。

目录里面的文件,主要是LibreOfficeKit.h和LibreOfficeKit.hxx,分别使用在C语言和C++语言中,其实LibreOfficeKit.hxx就是包装了一层LibreOfficeKit.h,使用起来大同小异。

下面我们以C++语言为例。

libreofficekit初始化

libreofficekit的C++类库,使用了名字空间lok。我们下面要使用的类,如lok::Office,可以直接使用,也可以通过using语句把lok引入我们的名字空间。

使用libreofficekit打开Office文件之前,需要初始化一个lok::Office类。

需要使用的函数是lok_cpp_init,在LibreOfficeKit.hxx中,这是一个inline函数,源代码为:

/// Factory method to create a lok::Office instance.
inline Office* lok_cpp_init(const char* pInstallPath, const char* pUserProfileUrl = NULL)
{
    LibreOfficeKit* pThis = lok_init_2(pInstallPath, pUserProfileUrl);
    if (pThis == NULL || pThis->pClass->nSize == 0)
        return NULL;
    return new ::lok::Office(pThis);
}

需要注意的是,这个初始化语句的pInstallPath参数,这个指的是libreoffice的二进制可执行程序路径。

对于默认安装的libreoffice的Fedora系统来说,这个路径是:

/usr/lib64/libreoffice/program,而Ubuntu则是:
/usr/lib/libreoffice/program

所以,我们可以在程序开头实现:

using namespace lok;

int
main (int argc, char *argv[])
{
    Office *office = lok_cpp_init ("/usr/lib64/libreoffice/program", nullptr);
}

加载Office文件

初始化lok::Office之后,就可以加载Office文档了,Office文档在libreofficekit中是类lok::Document。

值得注意的是,在libreoffice提供的文档LibreOfficeKit.hxx头文件中,初始化Document不能使用默认初始化方法,而要通过上文初始化的Office对象来加载,亦即使用Office的documentLoad方法。

docmentLoad方法的定义为:

   Document* documentLoad(const char* pUrl, const char* pFilterOptions = NULL)  
   {                          
       LibreOfficeKitDocument* pDoc = NULL;  
          
       if (LIBREOFFICEKIT_HAS(mpThis, documentLoadWithOptions))  
           pDoc = mpThis->pClass->documentLoadWithOptions(mpThis, pUrl, pFilterOptions);  
       else  
           pDoc = mpThis->pClass->documentLoad(mpThis, pUrl);  
  
       if (pDoc == NULL)  
           return NULL;  
  
       return new Document(pDoc);  
   }

而对照头文件开头:

/// The lok::Document class represents one loaded document instance.
class Document
{
private:
    LibreOfficeKitDocument* mpDoc;

public:
    /// A lok::Document is typically created by the lok::Office::documentLoad() method.
    Document(LibreOfficeKitDocument* pDoc) :
        mpDoc(pDoc)
    {}

    ~Document()
    {
        mpDoc->pClass->destroy(mpDoc);
    }
……

则不能看出,C++的头文件LibreOfficeKit.hxx中的lok::Document就是完全包装的LibreOfficeKit.h。

加载完Document以后,需要调用initializeForRendering方法,完成文档的渲染初始化。

Office文档的属性

加载完lok::Document以后,就可以通过它来查询或者控制文档了。

以下是Document主要支持的一些方法:

  • int getParts() 获取文档的页数。对于word文档,这个getParts返回的是页数,对于工作表来说,这个返回的是子表。
  • void setPart(int nPart) 设置当前的页数。
  • void getPart() 获取当前的页数。
  • char* getPartName(int nPart) 获取当前页的名称
  • void getDocumentSize(long* pWidth, long* pHeight) 获取整个文档的大小
  • void paintTile(unsigned char* pBuffer,
    const int nCanvasWidth,
    const int nCanvasHeight,
    const int nTilePosX,
    const int nTilePosY,
    const int nTileWidth,
    const int nTileHeight) 渲染文档。其中,nCanvasWidth、nCanvasHeight是画布大小,nTileWidth、nTileHeight是文档的右下角的坐标值,即后4个参数是原始文档被选择的区块,要区分一下。以下函数同理。
  • void paintPartTile(unsigned char* pBuffer,
    const int nPart,
    const int nMode,
    const int nCanvasWidth,
    const int nCanvasHeight,
    const int nTilePosX,
    const int nTilePosY,
    const int nTileWidth,
    const int nTileHeight) 渲染指定页数的文档

比如,以下代码便是把整个文档,按照指定的大小,渲染到内存地址里去:

bool
renderToImage(Document *doc, int pn, int width, int height, unsiged char **buffer)
{
  auto size = width * height * 4;
  *buffer = new (size);
  if (*buffer == nullptr)
    {
       cerr << "memory error: " << strerror (errno);
       return false;
    }
  doc->paintPartTile (*buffer, pn, 0, width, height, 0, 0, width, height);
  return true;
}

Office文档转换

Document有一个SaveAs方法,亦即“另存为”。

这个方法的原型为:

bool saveAs(const char* pUrl, const char* pFormat = NULL, const char* pFilterOptions = NULL);

第一个参数pUrl是文件路径。

第二个是pFormat是文件格式,默认为NULL,如果为NULL的时候,libreofficekit将通过pUrl的后缀名来确定文件格式。

比如,以下代码,可以把Office文档的指定页数,转成一个文本文档,只包含文档中的文字。

void 
toTextFile (Document *doc, int pn, const char *txt_name)  
{  
  doc->setPart (pn);  
  doc->saveAs (txt_name, "txt");  
}  

而以下代码,则可以把Office的指定页数,保存成一个png格式的图片,对于预览文档非常使用。

void 
toPngFile (Document *doc, int pn, const char *png_file)  
{  
  doc->setPart (pn);
  doc->saveAs (png_file, "png"); 
}
  • 28
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值