イメージ処理
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固有の問題とすると、いずれ改善されることを期待するしかないでしょう。