LibreOfficeKit for document conversion

In the previous blog post, I provided a brief introduction to LibreOfficeKit API which one can use for accessing LibreOffice functionalities in an external application. Here I discuss in detail how to use LibreOfficeKit for converting an ODT to PDF, or from/to virtually any other format that LibreOffice supports.

LibreOfficeKit C++ Headers

For this example, you only need one header: LibreOfficeKit/LibreOfficeKit.hxx. Include it, and that is enough. This header will be available in the future versions of LibreOffice community. But for now, you may need to download LibreOfficeKit headers folder from LibreOffice core source code, and put it alongside your source code.

C++ Example

The example is relatively short. Here it is:

#include <iostream>
#include <LibreOfficeKit/LibreOfficeKit.hxx>
int main(int argc, char *argv[])
{
    if(argc < 2)
    {
        std::cout << "Usage: lokconvert  \n";
        return 1;
    }
    const char *input = argv[1];
    const char *output = argv[2];

    lok::Office * llo = NULL;
    try
    {
        const char lo_path[] = LOROOT "/program/";
        llo = lok::lok_cpp_init(lo_path);
        if (!llo) {
            std::cerr << "Error: could not initialize LibreOfficeKit\n";
            return 1;
        }

        lok::Document * lodoc = llo->documentLoad(input, NULL /* options */);
        if (!lodoc) {
            std::cerr << "Error: could not load document: " << llo->getError() << "\n";
            return 1;
        }

        if (!lodoc->saveAs(output, "pdf", NULL /* options */))
        {
            std::cerr << "Error: could not export document: " << llo->getError() << "\n";
            return 1;
        }
    }
    catch (const std::exception & e)
    {
        std::cerr << "Error: LibreOfficeKit exception: " << e.what() << "\n";
        return 1;
    }

    std::cerr << "Success!\n";
    return 0;
}

The example is simple. Input and output file names are passed via command line arguments, and are received via argv[1] and argv[2], if argument count, argc, is at least 3. First one is the program name itself, which we don’t use here.

LibreOffice binary folder is needed here, so you should set OO_SDK_URE_BIN_DIR environment variable, or you may even set that in your program itself.

This part of the code is for LibreOfficeKit initialization:

llo = lok::lok_cpp_init(lo_bin_dir);

And after that, it is the time to load the document:

lok::Document* lodoc = llo->documentLoad(input, NULL /* options */);

Having the lodoc pointer is necessary for converting the document using saveAs function:

lodoc->saveAs(output, "pdf", NULL /* options */)

As you can see, relevant code is inside a try/catch block. In case some exception occur, you will see relevant error information on the console. Also, in each step, from initializing LibreOfficeKit, to loading and in the end generating the output, there are error handling mechanisms to make sure that the work goes forward smoothly.

In the end, if everything is successful, you will see this message on the screen:

Success!

Build with cmake

You can use cmake to build this example. Here is an example CMakeLists.txt which also provides LO_ROOT and LO_SDK_ROOT to be used inside C++ file, as an alternative to setting it via an environment variable, or putting it manually in the code.

cmake_minimum_required(VERSION 3.5)

project(lokconv LANGUAGES CXX)

set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

add_executable(lokconv main.cpp)

include(GNUInstallDirs)

set(LOVERSION 24.2)

if(WIN32)
    set(LOROOT C:/Progra~1/LibreOffice)
    set(LOSDKROOT ${LOROOT}/sdk)
    add_definitions(-DWIN32)
elseif(APPLE)
    set(LOROOT /Application/LibreOffice.app/Contents/Frameworks)
    set(LOSDKROOT /Application/LibreOffice${LOVERSION}_SDK)
    add_definitions(-DMACOSX)
else()
    set(LOROOT /opt/libreoffice${LOVERSION})
    set(LOSDKROOT ${LOROOT}/sdk)
    add_definitions(-DLINUX)
endif()

add_compile_definitions(LOK_USE_UNSTABLE_API)

target_compile_definitions(lokconv PRIVATE LOROOT="${LOROOT}")

include_directories(lokconv PRIVATE
    ${LOSDKROOT}/include
)

Final Words

There are many nice things that can be done with LibreOfficeKit, but you may have to enable LOK_USE_UNSTABLE_API to be able to use those functionalities. This symbol is visible in the above cmake file. But, in the C++ example I did not use any of such functions. I will discuss about these functionalities in later blog posts.