Google App Engineで画像処理とか変換とか

お久しぶりです、竹内(stakeuchi)です。
ブログは久々に書いてます。


このところmobyletの実装にやっきになっていたのですが
特に最近mobyletに搭載していた機能は
・色々な画像変換パターン
Google App Engineでのキャッシュ機能
というところでした。


今日は特に新機能(0.7.0搭載機能)のお話と
Google App Engineでの実装内容を書いてみます。


まず、新機能が画像変換パターンの追加になります。
今までは、特にブラウザ幅に合わせてリサイズできます。
というものだったのですが
身近なところから
「横長の画像と縦長の画像で出来上がりの画像の面積が違うのが嫌だ」とか
「正方形のサムネイル(画像の真ん中をくり抜いた)は出来ないの?」とか
そんなリクエストがあったので追加しました。


カスタムタグでやろうとすると

みたいにやっていたところを

とすると正方形のサムネイルが作れるようになりました。

とすると、縦長画像でも同サイズの画像になります。
(横幅ベースの正方形におさまる画像サイズに変換するという意味です)


これをやろうとしたとき、特に正方形くり抜き画像の作り方なのですが
Google App EngineのImage APIの仕様があまり公開されていないので
実際にEclipseでメソッドを検索しつつ、実装してみました。


JavaのImageAPIを利用した場合は
BufferedImage#getSubimage()
メソッドを使えば切り抜き画像を取得するのは簡単なのですが
Google App EngineのImageAPIを利用する場合は
ImagesServiceFactory#makeCrop()
メソッドを使用して実現出来ます。


さらにこのmakeCrop()メソッドは
double leftX, double topY, double rightX, double bottomY
の4つの引数を持っていて
何でdouble型?と思っていたのですが普通にpixel単位での座標を入れるとOUT!
実は縦横の幅を「1」とした0〜1の間の相対値を指定するというユニークなメソッドということが判明。


例えば画像を均等に十字に切った、右下の画像を取りたい場合は
makeCrop(0.5, 0.5, 1.0, 1.0)
となります。
なかなか面白い関数だなぁと個人的にはヒットしました。



また、Google App Engine用のmobylet-extensionライブラリに画像のキャッシュ機能も追加して
Memcachedを利用するようにして実装しました。


#試験的にJDOを使ってBigtable上にキャッシュするパターンも試してみたのですが
#見事に粉砕されました。(最近これに悩まされてブログもかけなかったのです)
#画像のリクエストで処理する形になるのでサーバ上ではマルチスレッドでBigtableにアクセスする形となり
#そのあたりとdetachableにしたりしなかったりとか、ごちゃごちゃしちゃって
#上手くいかず(1パターンしかコミットされない)、迷宮入りです。。。


Memcachedは使ったことあるのですがGAE/Jだと簡単に使えすぎて怖いくらいです。

        • -

//キャッシュクライアントを生成
Cache cache = CacheManager.getInstance().getCacheFactory().createCache(Collections.emptyMap());

//キャッシュにデータ投入
Object key = "key";
Object data = "data";
cache.put(key, data);

//キャッシュからデータ取得
data = cache.get(key);

        • -


うーん。非常に簡単ですね。
JavaのMapくらい簡単に使えます。


実際の速度面に関して
mobyletの標準実装ではHTTPで画像の最終更新日時をHEADで叩いてから処理するので
どうもそこのコストがちょっと高いのか
そもそもの通信コスト(サーバまでの距離とか間のルータの数とか)が高いのかで
あんまり早くないなぁというのが実感です。
#逆にGAE/JのImageAPIは結構処理が速い気がする。


とはいえ、GAE/Jで設定されている無料で使える範囲で考えると
ImageAPIを毎回叩いているとすぐ有料になっちゃいそうなので
Memcachedでcacheした方が良さそうな気はします。
Memcachedへのアクセス回数も多くなると有料モードに突入します)




まもなく0.7.0はリリースできると思いますが、
このバージョンでやっと実用出来るものになってきたかな
という感じはあります。

今だとちょっとJSP依存になっている部分がある(taglibありきな感じ)ので
ここを0.7.0で切り離すか0.8.0でやるかで迷っているところです。

あとはslim3+mobyletとか、Ymir+mobyletとか
ちょっとやってみたいですね。