📑

Python で poppler(pdf2image など)を使うアプリを Windows で pyinstaller でパッケージングメモ

2023/04/13に公開

PDF -> 画像変換を python でしたい.

https://qiita.com/Kanahiro/items/790d7cde084920dac575

ありがとうございます. pdf2image でいけました.
poppler 使ってました.

pypi では, python-poppler は source からビルドになってしまいます.

https://pypi.org/project/python-poppler/

conda であれば Windows での prebuilt をインストールしてくれます.

https://anaconda.org/conda-forge/poppler

> conda install -c conda-forge poppler

poppler 使う Python アプリを pyinstaller で .exe 化すると, 実行時 pdftocairo.exe とか .dll が見つからないとかエラーでてつらい...

方法

poppler では実行時に pdfinfo.exe で PDF 情報しゅとくしたり, pdftocairo.exe や などコマンド叩いて変換します.
そのため必要なファイルを手動リストアップが必要です.

なぜか libcurl あたりにも依存しているので, libcurl.dll あたりも頑張ってコピります...

解決

最終的には .spec はこんな感じ.

popper_files = []
if os.name == 'nt':
    # assume [0] = conda path
    conda_path = site.getsitepackages()[0]
    poppler_files = [
        (os.path.join(conda_path, "Library/bin/pdftocairo.exe"), "."),
        (os.path.join(conda_path, "Library/bin/pdfinfo.exe"), "."),
        (os.path.join(conda_path, "Library/bin/pdfimages.exe"), "."),
        (os.path.join(conda_path, "Library/bin/pdftoppm.exe"), "."),
        (os.path.join(conda_path, "Library/bin/poppler.dll"), "."),
        (os.path.join(conda_path, "Library/bin/poppler-cpp.dll"), "."),
        (os.path.join(conda_path, "Library/bin/poppler-glib.dll"), "."),
        (os.path.join(conda_path, "Library/bin/cairo.dll"), "."),
        (os.path.join(conda_path, "Library/bin/cairo-gobject.dll"), "."),
        (os.path.join(conda_path, "Library/bin/libcurl.dll"), "."),
        (os.path.join(conda_path, "Library/bin/lcms2.dll"), "."),
        (os.path.join(conda_path, "Library/bin/openjp2.dll"), "."),
        (os.path.join(conda_path, "Library/bin/zlib.dll"), "."),
        (os.path.join(conda_path, "Library/bin/freetype.dll"), "."),
        (os.path.join(conda_path, "Library/bin/libpng16.dll"), "."),
        (os.path.join(conda_path, "Library/bin/tiff.dll"), "."),
        (os.path.join(conda_path, "Library/bin/Lerc.dll"), "."),
        (os.path.join(conda_path, "Library/bin/libdeflate.dll"), "."),
        (os.path.join(conda_path, "Library/bin/liblzma.dll"), "."),
        (os.path.join(conda_path, "Library/bin/zstd.dll"), "."),
        (os.path.join(conda_path, "Library/bin/libssh2.dll"), "."),
    ]
    
a = Analysis(
    ['myapp.py'],
    pathex=[],
    binaries=[],
    datas=poppler_files,

実行時に dll 検索やりやすいように, pyinstaller での .exe の直下にファイルをコピーしていますが, 必要に応じてコピー先調整ください.

.dll, .exebinaries に追加が推奨かもしれません.

https://pyinstaller.org/en/stable/spec-files.html#adding-binary-files

poppler(cairo) 使うの嫌や...

ちなみに, poppler の利用している cairo は古めかしくてヤングな感じではないので,
Skia あたりでうまく扱えるといいのですけどね(現状 PDF import あたりが未整備で移行できず)

https://zenn.dev/syoyo/articles/e34ee63f9592ab

Discussion