OpenPyXLで「ファイル内のイメージを圧縮しない」を設定したファイルを保存したい


はじめに

OpenPyXLを利用して保存したxlsxファイルをデスクトップ版のExcelで開くと、「ファイル内のイメージを圧縮しない」のチェックボックスがオフになっています。
チェックボックスをオンにしているファイルを開いて保存した場合も、問答無用でオフとなります。
Excelで開いたときに詳細設定からチェックすれば済みますが、せっかくPythonで自動生成するので手動作業は省略したいですね。
しましょう。

確認した環境

バージョン
Python 3.8.1
openpyxl 3.0.5

とりあえず対応方法

次のように記載をすることで、圧縮なし設定のxlsxファイルを作成できます。

create_xlsx.py
#!/usr/bin/env python

import openpyxl

from openpyxl.workbook.properties import WorkbookProperties
from openpyxl.utils.datetime import CALENDAR_MAC_1904
from openpyxl.workbook._writer import WorkbookWriter

def write_properties_custom(self):
    props = WorkbookProperties()
    if self.wb.code_name is not None:
        props.codeName = self.wb.code_name
    if self.wb.excel_base_date == CALENDAR_MAC_1904:
        props.date1904 = True
    props.autoCompressPictures = False
    self.package.workbookPr = props

WorkbookWriter.write_properties = write_properties_custom


wb = openpyxl.Workbook()
wb.save("Sample.xlsx")

大事なのはprops.autoCompressPictures = Falseの箇所になります。
このコードで作成したxlsxファイルの詳細設定をみると、ちゃんとチェックされていることが確認できます。

無理やりライブラリを書き換えているので、もしかしたら予期せぬ動作をするかもしれません。
念の為、注意してご利用ください。

調査結果備忘録

以下、調査した内容や詳細をダラダラと書きます。
特に読まなくても問題ないです。

そもそもとして

OpnePyXLにはWorkbookPropertiesというモジュールがあります。
ここにautoCompressPicturesという変数があったので、これにTrue/Falseを設定して保存すれば反映されると思いました。
しかし、workbookオブジェクトのプロパティには設定がありません。
とはいえ先程のモジュールには存在していたので、考慮されていないわけではないと考え色々見てみました。

OpenPyXLの保存動作について

保存はWorkbookクラスのsaveメソッドを使いますが、

  • writer/excel.py
  • workbook/_writer.py

の2つのファイルを経由してWorkbookPropertiesクラスのwrite()を呼び出しています。
このwrite()から呼び出すwrite_properties()でプロパティを設定しています。
今回はこのメソッドに処理を追加してます。
WorkbookProperties()の初期値に設定するのでもいいかと思います。

xlsxファイルについて

ワークブックプロパティの詳細についてはこちらに記載があります。
autoCompressPicturesは1またはTrueの時に圧縮する(デフォルトはTrue)のため、Flaseを設定しています。
ちなみにOpenPyXLのWorkbookPropertiesにある他の項目についても詳細が書いてあります。

ライブラリの上書きについて

こちらの記事を参考にしました。
Pythonでライブラリの処理を上書きする

ただ本来あるべき形としては、記載されている2種類の項目のように、self.wb.***で確認後に設定する形にするのかなぁと思っています。
今回は面倒だったので強制的にTrueとしてしまっていますけども。