PyGTK2からPyGI GTK3への移行(6)

前回の続きですが, (IV)のコードの問題は分かったでしょうか.

気付くと簡単なことですが, 1ピクセルは4byteなのでピクセル値の置き換えは4byte毎に整列して行なう必要があります. しかし, 文字列型のreplaceメソッドはそんなことはお構い無しに1byte毎に検索と置き換えを行なってしまいます.

では, 何故ほとんどのゴーストでこのコードが正しく動くのでしょうか. ちゃんと理由があります.

  1. 元の画像がアルファチャンネルを持たないか, 全てのピクセルのアルファ値が同じである.
  2. 座標(0, 0)のピクセルのRGB値がそれぞれ全てアルファ値(アルファチャンネルを持たない画像の場合には255)と異なっている.

この2つの条件を満たせば良いのです. つまり画像には4byteおきに同じ値(アルファ値)が出て来てそれが座標(0, 0)のピクセルのアルファ値とだけ一致するので, 自動的に置き換えが4byte毎に整列される訳です.

シェルの画像を見てみるとかなり高い確率でこの条件が満たされています. そのためにほとんどのゴーストで(IV)のコードが正しく動くのです. しかし, やはりこの条件に当て嵌らない画像も処理出来なければ正しいプログラムとは言えません.(実際にこの条件に当て嵌らないゴーストが存在します.)

条件が満たされるかどうかを調べて満たされない場合には(III)のコードに切り替わるようにするというのも1つの方法ですが, 条件を調べるコストが発生するのでベストケースでも(IV)と同じ速さが維持出来るかどうかは分かりませんし, 処理が複雑になります. (IV)のコードを改変して使う方法は他にも色々考えられますが, ここでこのコードは捨ててしまいましょう. 全ての場合に対応出来て(IV)と同じくらい簡単で速いコードを作る方法はないでしょうか.

やはりここはNumpyを使います.

      ncalls  tottime  percall  cumtime  percall
(V)       10    0.005    0.000    0.005    0.000

(V) 変にコードを捻るよりも使うデータ型を変えましょう.

import numpy

def process_pnr_5(surface):
    buf = surface.get_data()
    ar = numpy.frombuffer(buf, numpy.uint32)
    argb = ar[0] # ARGBの並び順はエンディアンによって変わります.
    ar[ar == argb] = 0x00000000
    return surface

すっきりしていて悪くないですね. 😉

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です