Ubuntu Weekly Recipe

第437回 LibreOfficeはreOfficeのライブラリではありません 〜LibreOffice Onlineを支える技術

この記事を読むのに必要な時間:およそ 17 分

ファイルフォーマットを変換するプログラム

まずは指定したオフィスドキュメントを別のフォーマットに変換するプログラムを作ってみましょう。

lok_convert.cpp

#include <stdlib.h>
#include <unistd.h>
#include <iostream>
#include <LibreOfficeKit/LibreOfficeKit.hxx>

namespace lok_tools {
    const std::string LO_PATH = "/usr/lib/libreoffice/program";
}

void usage(const char *name)
{
    std::cerr << "Usage: " << name;
    std::cerr << " [-p path-of-libreoffice] FROM TO" << std::endl;
}

int main(int argc, char **argv)
{
    int opt;
    std::string lo_path = lok_tools::LO_PATH;
    while ((opt = getopt(argc, argv, "p:")) != -1) {
        switch (opt) {
        case 'p':
            lo_path = std::string(optarg);
            break;
        default:
            usage(argv[0]);
            exit(EXIT_FAILURE);
        }
    }

    if (argc - optind < 2) {
        usage(argv[0]);
        exit(EXIT_FAILURE);
    }
    const char *from_file = argv[optind++];
    const char *to_file = argv[optind];


    try {
        lok::Office *lo = lok::lok_cpp_init(lo_path.c_str());
        if (!lo) {
            std::cerr << "Error: Failed to initialise LibreOfficeKit";
            std::cerr << std::endl;
            exit(EXIT_FAILURE);
        }

        lok::Document *doc = lo->documentLoad(from_file);
        if (!doc) {
            std::cerr << "Error: Failed to load document: ";
            std::cerr << lo->getError() << std::endl;
            delete lo;
            exit(EXIT_FAILURE);
        }

        if (!doc->saveAs(to_file)) {
            std::cerr << "Error: Failed to save document: ";
            std::cerr << lo->getError() << std::endl;
            delete doc;
            delete lo;
            exit(EXIT_FAILURE);
        }

        delete doc;
        delete lo;
    } catch (const std::exception & e) {
        std::cerr << "Error: " << e.what() << std::endl;
        exit(EXIT_FAILURE);
    }

    return 0;
}

次のようにビルドします。

$ g++ lok_convert.cpp -Wall -Werror -ldl -o lok_convert

libdlを使うため,-ldlオプションが必要です。また使い方は次のとおりです。

$ ./lok_convert 変換元ファイル 変換先ファイル

LibreOfficeKitにはlok::Officeクラスとlok::Documentクラスが存在します。lok::OfficeクラスはLibreOffice本体の準備に使うクラスで,lok::Documentは読み込んだドキュメント本体のクラスです。

lok::Officeのインスタンスはlok::lok_cpp_init()を用いて作成します。このときの第一引数はLibreOfficeのプログラムがインストールされたパスであり,第二引数はユーザープロファイルのパスです。第二引数は省略できます。第一引数の「LibreOfficeのプログラム」は,Ubuntuの場合/usr/lib/libreoffice/programになります。このディレクトリ以下にLibreOfficeの本体となる各種共有ライブラリがインストールされているのです。LibreOfficeKitでは,初期化時にこのライブラリをdlopen()で開いた上で,その中のシンボルを呼び出していくことになります。本プログラムでは,プログラムのパスが異なる時のことを考慮して,-pオプションでパスを指定できるようにしてあります。

LibreOfficeのファイルを開くのは,lok::OfficeクラスのdocumentLoad()メソッドです。第一引数にファイルのパスを,第二引数にフィルタリングオプションを指定します。第二引数は省略可能です。

lok::DocumentクラスのsaveAs()はいわゆる「名前を付けて保存」です。これを使えば,開いたファイルを別形式で保存できるというわけです。

lok::lok_cpp_init()documentLoad()newで割り当てた結果を返すため,呼び出した側で不要になった段階でdeleteを呼んでいます。C++を使うならスマートポインタでもいいでしょう。ただしnewしたポインタをうまく処理する必要があります。ちなみに,LibreOffice Onlineの方はstd::shared_ptr化していますが,こちらはLibreOfficeKit.hxxの中でstd::make_sharedを呼ぶように改変しているようです。

ちなみに単純にコマンドから別名で保存したいだけであれば,libreofficeコマンドそのものを使えます。

$ libreoffice --headless --convert-to 変換先の拡張子 変換元ファイル

--headlessオプションは起動ロゴやUIを表示せず,ユーザーの操作なしにLibreOfficeを起動するオプションです。--convert-toで変換先の拡張子を指定します。--infilterオプションを使えば,入力データのフィルタリングもできます。オフィスファイルをPDFに変換したいという用途であれば,このコマンドを使うと良いでしょう。ちなみに,unoconvパッケージのunoconvコマンドも,同様の機能を持っています。

著者プロフィール

柴田充也(しばたみつや)

Ubuntu Japanese Team Member株式会社 創夢所属。数年前にLaunchpad上でStellariumの翻訳をしたことがきっかけで,Ubuntuの翻訳にも関わるようになりました。