GAEで画像のピクセル操作をする方法

=前置き=

 無念番付関連の話題は、先のエントリで「GAEに画像データを格納する」ところまではできた。あとはGAE側で色計算まで行なっておけばページやゲームを開くたびに毎回色を計算するようなムダな処理をしなくて済む。

 というわけで、ここでは「GAEで画像のピクセル操作をする方法」をまとめる。

=概要=

 基本的な流れは以下の通り。

  • PyPngのインストール
  • PILのインストール
  • 画像処理

=PyPngのインストール=

 ピクセル単位での画像の処理はGAEではサポートされていないので、別ライブラリとしてここではPyPngを使うことにする。

 以下から一式をダウンロード。
 Google Code Archive - Long-term storage for Google Code Project Hosting.

 Pythonのお作法的にはちゃんとしたインストール手順があるんだろうけど、ここではcodeフォルダに入っていた「png.py」をGAEに上げるRoot部分にコピーした。

=PILのインストール=

 Amazonから返ってくる画像はjpgであり、さっきのPyPngで扱えるpngではない。というわけで、jpgをpngに変換する必要があるのだが、これはGAEでの画像処理(PIL)で実現できる。

 ただし、PILは本番環境のサーバでは動いているが、ローカルではデフォルトでは入っていない。つまり、自前でインストールする必要がある。
 これはhttps://developers.google.com/appengine/docs/python/images/installingPIL?hl=jaからインストールすればOK。あくまでローカルでの動作確認に必要なだけなので、上げる部分でどうこうする必要はない。

 ちなみにPILをインストールしないと「THREADSAFEがない」とかのエラーが出て変換ができない。

=画像処理=

 準備が完了したらようやく実際の画像処理を行う。(GAEのLauncherを起動中にインストールしたら再起動しておくこと)

 まず、コードはだいたい以下のような感じになる。(URLから画像を得てピクセル列を取得するところまで)

IMG_W = 63
IMG_H = 100

imgURL = "..."

result = urlfetch.Fetch(imgURL)
if result.status_code == 200:
	img_png = images.Image(result.content)	#バイナリ→Image化
	img_png.resize(IMG_W, IMG_H)			#png化ついでに事前にリサイズ
	png_data = img_png.execute_transforms() #jpg => png
	pr = png.Reader(bytes=png_data)			#Readerの設定
	x,y,pixels,meta = pr.asRGB8()			#実際に読み込む

 まずは「jpg→png」の操作を行う準備として、Image化している。

 「jpg→png」の変換にexecute_transformsを使う場合、それ以前にresizeなどの何かしらの操作をしないといけないので、ここではついでにresizeをして実際の表示サイズに変換している。ここらへんはもっと良い方法があるかもしれない。

 そしてその結果をバイト列としてpng.Readerに渡し、それを実際に読み込んでピクセル列(pixels)を得る。


 で、実際にピクセル列を操作するコードは以下のような感じ。

for ps in pixels:	#たぶん横列
	#iter
	rgb_iter = 0
	for p in ps:	#たぶん縦列
		#init
		if rgb_iter == 0:
			#RGB
			r = 0
			g = 0
			b = 0
		#RGB
		if rgb_iter == 0:
			r = p
		if rgb_iter == 1:
			g = p
		if rgb_iter == 2:
			b = p
		#iter
		rgb_iter += 1

		#Pixel
		if 3 <= rgb_iter:
			#rgbが求まったのでなんやかんやする

			#...
			#(1ピクセル分の処理)
			#...

			#iter
			rgb_iter = 0


 pixelsが縦横の2重配列になっているのは良いんだけど、RGBまでバラバラになっているため、1ピクセル分の処理を行う場合は上のようにやや汚い感じのコードになってしまう。ここはもうちょっと別な感じが良かったが、ともあれこれでピクセル操作はできた。