7839

雑草魂エンジニアブログ

【Python】Excel を PDF に変換する(Alpine Linux + LibreOffice )

最近は、全くブログを更新できておらず、反省しなければと思っている今日この頃。お陰様で、下書きは溜まりに溜まっているので、整理しながら順次公開していきたいと思う。

今回は、Docker の Alpine Linux 上で、Excel ファイルを PDF に変換する処理を実装したので、その実装方法を紹介する。

Excel ファイルを PDF に変換する方法

Excel ファイルを PDF に変換するには、まず Excel ファイルを開く必要がある。そこで、必要になるのが Excel ファイルを開くことができるソフトウェアである。実行環境が、Windows であり、MicrosoftExcel が入っているのであれば、 win32com というモジュールを使うことで、pythonから Excel ファイルを操作することができる。ただし、このモジュールはデフォルトで入っていないので、pip でインストールする必要がある。

$ pip install pywin32

以下のコードで、Excel ファイル全体を PDF に変換することができる。

import win32com.client # win32com ライブラリを読み込み
excel = win32com.client.Dsipatch("Excel.Application") # Excelを起動
book = excel.Workbooks.Open("input_file.xlsx") # Excelでファイルを読み込み
book.ExportAsFixedFormat(0, "output_file.pdf") # PDF形式で保存
excel.Quit() # Excelを終了

ただし、今回は Docker の Alpine Linux を想定しており、このモジュールを使うことができない。

そこで今回は、オープンソースソフトウェアである LibreOffice を使って、Excel ファイルを PDF に変換することとした。 ja.libreoffice.org

Excel と同様の表計算ソフトウェアとして、「Calc」が存在するので、それを使うこととする。LibreOffice は様々な機能をコマンドラインから起動できるので、とても便利である。 --headless オプションを指定することで、LibreOfficeGUI を表示せずに機能を利用することができる。Excel ファイルを PDF に変換するコマンドは以下の通りである。

LibreOffice:version 6.4.4.2

$ libreoffice --headless --nologo --nofirststartwizard --convert-to pdf --outdir <output_path> <input_file.xlsx>  

上記で設定しているオプションは以下の通りである。

  • headless:ヘッドレスモード(GUIを表示しないモード)
  • nologo:スプラッシュ画面(起動画面)を表示しない
  • nofirststartwizard:初回起動ウィザードを起動しない
  • convert-to [拡張子]:[フィルタ]:[エンコード]:変換ファイルと形式を指定する
  • outdir [出力先]:ファイルの出力先を指定する(出力ファイル名は設定できない。拡張子が変わるのみ。)

Dockerfile

参考までに作成した Dockerfile は以下の通りである。(Djangoのアプリケーションを開発していた Docker に、LibreOffice を追加しているので、実際には最小構成ではない。build-rundepsで不要な物が含まれていると思われる。)

|- Dockerfile
|- requirements.txt
|- fonts/
FROM python:3.9-alpine3.12
ENV PYTHONUNBUFFERED 1

RUN apk update \
    && apk add --no-cache --virtual .build-rundeps \
        linux-headers \
        build-base \
        mariadb-connector-c-dev \
        libxml2-dev \
        libxslt-dev \
    && apk add --upgrade --no-cache --virtual .libreoffice-rundeps \
        libreoffice \
        libreoffice-base \
        libreoffice-lang-ja \
        font-noto-cjk

RUN mkdir /code

WORKDIR /code
ADD ./requirements.txt /code/

RUN pip3 install -r requirements.txt
ADD . /code/

RUN mkdir -p /usr/share/fonts/
COPY fonts/ /usr/share/fonts/
RUN fc-cache -fv

EXPOSE 8000

日本語のフォントがない場合に、PDF に変換した際に、文字化けを起こすので、日本語のフォントをインストールする必要がある。 font-noto-cjk で最低限のフォント(noto)をインストールしているが、Excel内で指定しているフォントが使いたかったので、ローカルからコンテナ(/usr/share/fonts/)にフォントをコピーしている。

Pythonからの変換コマンドの実行(subprocess)

Pythonから他のアプリを起動する場合などには、標準ライブラリである subprocess を用いるのが一番簡単である。

docs.python.org

import subprocess
subprocess.run(["実行コマンド"], shell=True)

先ほど示した、Excel ファイルを PDF に変換するコマンドは、以下のようにして実行できるようにした。

def convertExcelToPdf(file_name, path):
    cmd = []
    cmd.append("libreoffice")
    cmd.append("--headless")
    cmd.append("--nologo")
    cmd.append("--nofirststartwizard")
    cmd.append("--convert-to")
    cmd.append("pdf")
    cmd.append("--outdir")
    cmd.append(path)
    cmd.append(file_name)

    subprocess.run(" ".join(cmd), shell=True)

(なぜか配列指定では、libreofficeのコマンドが適切に実行されなかったので、スペースを間に入れた文字列結合でコマンドが実行されるようにした。)

まとめ

LibreOffice というめちゃくちゃ便利なオープンソフトウェアのお陰様で、今回も Excel ファイルを PDF に変換することができた。本当に感謝である。LibreOffice は初めて使ってみたが、今後も様々な場面で使っていきたい。

ただ、Excel のヘッダーに画像を挿入していたが、それがなぜか消えている問題が先ほど発覚した。シートに挿入している画像はきちんと表示されているので、Excel のヘッダーの設定がうまく読み込まれていない可能性が高い。試行錯誤したが表示されなかったので、もし知見がある方がいたら、是非とも教えて欲しい。

それでは、ステキな開発ライフを。