イメージ処理
Googleのサービスの中に「Picasa」というアルバムアプリケーションがあります。このPicasaで使われているイメージ処理の機能も、GAE/Jから利用できます。では、今度はイメージを生成し出力するサーブレットを定義し、それを利用してみることにしましょう。「src」内に「ImageServlet.groovy」ファイルを作成し、次のようにソースコードを記述します。
import java.lang.Exception
import java.io.*
import javax.servlet.*
import javax.servlet.http.*
import com.google.appengine.api.images.*
import java.util.logging.Logger
class ImageServlet extends HttpServlet {
private static final Logger log = Logger.getLogger(ImageServlet.class.getName())
void doGet(HttpServletRequest request, HttpServletResponse response)
throws IOException {
ServletContext context = this.getServletContext()
response.contentType = "image/jpeg"
String fname = request.getParameter("image")
String fpath = "/WEB-INF/img/" + fname + ".jpg"
byte[] data2 = this.getImageByte(context,fpath)
Image img = this.getImage(data2)
if (img != null){
Image img2 = this.transformImage(request,img)
BufferedOutputStream bout = null
try {
ServletOutputStream out = response.getOutputStream()
bout = new BufferedOutputStream(out)
byte[] data = img2.getImageData()
int len = data.length;
for(int i = 0;i < data.length;i++){
bout.write(data[i])
}
out.flush()
out.close()
} catch(e){
log.warning(e.message)
}
}
}
// イメージファイルを読み込みbyte配列を返す
byte[] getImageByte(ServletContext context,String fpath){
BufferedInputStream bin = null
ByteArrayOutputStream bout = null
Image img = null
byte[] data = null;
try {
InputStream fin = context.getResourceAsStream(fpath)
bin = new BufferedInputStream(fin)
bout = new ByteArrayOutputStream()
while(true){
int n = bin.read()
if (n == -1) break
bout.write(n)
}
data = bout.toByteArray()
bout.close()
bin.close()
} catch(e){
log.warning(e.message)
}
return data
}
// byte配列からImageインスタンスを生成し返す
Image getImage(byte[] data){
int n = data.length
return ImagesServiceFactory.makeImage(data)
}
// イメージを指定した大きさに拡大縮小したものを返す
Image transformImage(HttpServletRequest request,Image img){
int w = 100
int h = 100
try {
w = Integer.parseInt(request.getParameter("w"))
} catch(e){
log.warning(e.message)
}
try {
h = Integer.parseInt(request.getParameter("h"))
} catch(e){
log.warning(e.message)
}
Transform resize = ImagesServiceFactory.makeResize(w, h)
ImagesService service = ImagesServiceFactory.getImagesService()
return service.applyTransform(resize, img)
}
}
作成したら、このサーブレットをweb.xmlに登録しておきます。<web-app>内に、次のようにタグを追記してください。これで「/image」というURIで登録されます。
<servlet>
<servlet-name>ImageServlet</servlet-name>
<servlet-class>ImageServlet</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>ImageServlet</servlet-name>
<url-pattern>/image</url-pattern>
</servlet-mapping>

これで完成です。このサーブレットは、img、w、hといったパラメータで表示するイメージの名前・横幅・縦幅を指定します。実際に試してみましょう。「WEB-INF」内に、新たに「img」というフォルダを作成し、その中に「image1.jpg」というイメージファイルを用意しておきます。そして、「ドメイン/image?image=image1&w=250&h=250」というようにURLを指定してアクセスしてください。「image1.jpg」が縦横250ドットの大きさ(いずれかが250ドットとなるように調整されたサイズ)に縮小されて表示されます。
ただし、実際にGoogleサイトにデプロイして動作を確認してみると、あまり実用的ではありません。表示する速度があまりに遅いのです。ソースコードを見てみれば分かるように、すべてのデータの出力部分を1バイトごとに行っていることが関係しているでしょう。GAE/JのAPIには、byte配列をまとめて出力するメソッドもサポートされているのですが、いろいろ試してみたところ、Groovyでこれを行おうとすると、ClassLoaderの取得部分でaccess deniedと言われてしまうようです。これは筆者の環境かバージョンによる問題なのかもしれませんが、もしGroovy固有の問題とすると、いずれ改善されることを期待するしかないでしょう。
