PyQt で画像を扱う等するプログラムをfreezeするときの注意

"site-packages/PyQt4/plugins" 以下に配置されているファイルはQtのプラグインで、たとえば "plugins/imageformats" 配下に gif やら jpeg やらの codec が入ってる。
PyQtを使うアプリをpy2exeなどでfreezeすると、これらのcodecが利用不可能になり、JPEG画像を表示できなくなったりする。
この問題をググると qt.conf を作ってとかいうのがあるけど、qt.confの中にフルパスを書かないといけないのでせっかくバイナリを作ってもどこかに持っていって動かすのをどうするのかが問題になるのでお勧めできない。QApplication.setLibraryPath()がお勧め。以下、py2exe用のコード。

def main_is_frozen():
    return (hasattr(sys, "frozen") or # py2exe
           imp.is_frozen("__main__")) # tools/freeze

def get_main_dir():
    # mbcs エイリアスは site.py で設定されているので使えない可能性がある。
    # locale.getpreferredencoding() の方が良いか?
    if main_is_frozen():
        return os.path.dirname(sys.executable.decode('cp932'))
    return os.path.dirname(sys.argv[0].decode('cp932'))

if main_is_frozen():
    # py2exe を使うと Qt の plugin が動かなくなる対策。
    # これをしないとJPEG codec が動かない.
    import PyQt4.QtGui as gui
    library_paths = list(gui.QApplication.libraryPaths())
    library_paths.insert(0, os.path.join(get_main_dir(), u'PyQt4', u'plugins'))
    gui.QApplication.setLibraryPaths(library_paths)

あとは実行ファイルと同じディレクトリに PyQt4/plugins というディレクトリが配置されるようにすればいい。py2exeならdata_filesというオプションを使う。

このブログに乗せているコードは引用を除き CC0 1.0 で提供します。