Python3でFreeImage

あんまりPythonの世界のことは詳しくないんですが,いまのPythonってレガシーな2系を維持しつつ,3系に注力している,って感じなんですかね.

自分の作ってるプログラムの一部の挙動を,Pythonでスクリプト化したかったんですが,まぁどうせなら未来のあるPython3を使ってみようかと.

で,そのなかでFreeImageをPythonからたたく必要があったのですが,Python3で動かそうと思ったら若干大変でした.

FreeImageのサイトの説明には,

Thanks to it’s ANSI C interface, FreeImage is usable in many languages including C, C++, VB, C#, Delphi, Java and also in common scripting languages such as Perl, Python, PHP, TCL or Ruby.

って書いてあるんですが,これ要するに「Cインターフェース持ってるから~の言語から使用可能だよ!」ってだけでライブラリのメンテナが全ての言語へのバインドを提供しているわけじゃないんですね.なんか詐欺くさい書き方だなぁ.

FreeImageのソースに含まれているバインドはC++とC#だけです. だれかPython用のバインドを書いてないかなー,と思ったら一応あるようです → FreeImagePy

ただしこれはPython2用なので一部書き換えの必要がありました. やったことは,

  • 2to3で変換
  • タイプチェックtype(x) == ctypes.IntTypeisinstance(x, int)に書き換え
  • PyString_FromStringAndSizePyUnicode_FromStringAndSizeに書き換え

くらい.一応パッチと,パッチ当て済みのものを置いておきます.

もちろん,パスにFreeImage.dllが入ってないと動きません.

サンプルコード

色深度32bit,縦横512ピクセルの画像を作って白く塗りつぶしてPNG形式で保存するサンプルです.

import ctypes as C
import FreeImagePy as FIP

fi = FIP.freeimage()

fi.Initialise(True)

width = 512
height = 512
dib = fi.Allocate(width, height, 32)

for y in range(height):
    for x in range(width):
        rgbq = FIP.RGBQUAD()
        rgbq.rgbRed = 255
        rgbq.rgbGreen = 255
        rgbq.rgbBlue = 255
        rgbq.rgbReserved = 255
        fi.SetPixelColor(dib,x,y,C.pointer(rgbq))

fi.FlipVertical(dib)
fi.Save(FIP.FIF_PNG, dib, "test.png")
fi.Unload(dib)

fi.DeInitialise()

いまいちPythonの作法を知らないので戸惑いましたが,ポインタをとる場面ではctypes.POINTERというファクトリメソッドを使うようですね.

バインドされていない関数

どうもこのFreeImagePyってモジュール,あんまりメンテされているモノではないらしく いくつかFreeImageの関数が抜けてることもあるようです(まぁ,サイトに”A lot of function bound, but not all, sorry!”って書いてあるしね).

見つけた限りではFreeImage_FlipVerticalとかFreeImage_FlipHorizontalが抜けていました.不足している関数を補うには,以下の手順が必要です.

  • FreeImagePy.pyにインターフェースメソッドを追加
  • function_list.pyにDLL関数名を追加

たとえば,FreeImage_FlipVertical/FreeImage_FlipHorizontalの場合なら, FreeImagePy.pyのFreeImageクラスにメソッドを追加して…

    # Flip
    def FlipHorizontal(self, dib):
        return self.__lib.FlipHorizontal(dib)    
    def FlipVertical(self, dib):
        return self.__lib.FlipVertical(dib)

function_list.pyFUNCTION_LISTリストに以下を追加します.

    ('FreeImage_FlipHorizontal',    '@4'),
    ('FreeImage_FlipVertical',    '@4')    

各エントリの二個目はdumpbin /exports FreeImage.dllで出てくるシンボル名の後ろに付いているやつのようです.3つめ以降は戻り値型のようですが詳細はよくわかりません.

Leave a Reply