サーバサイドでProcessingを動かす
こちら Processing+POIをエクセルグラフウィザードの代替として使う - Object Design に触発されて、Webアプリケーションでも(サーバサイドで) Processing を使って情報視覚化ができないか試してみた。
まずは、Processing をJava Servlet上で動かして画像を生成するところまで*1。
とりあえず、Processing の本体であるアプレット(PApplet)の初期化、PAppletで直接サポートしていない生イメージの返却を行うユーティリティを作ってみる。
package example.processing; import java.awt.image.BufferedImage; import processing.core.PApplet; import processing.core.PConstants; import processing.core.PGraphics; public final class ProcessingUtils { /** * callback内で描画した内容をイメージとして返却します。 */ public static BufferedImage drawImage(ProcessingCallback callback) { PApplet applet = new PApplet(); applet.init(); // 初期化までタイムラグがあるので待つ // (PApplet.main メソッドのソース参照) while (applet.defaultSize && !applet.finished) { try { Thread.sleep(5); } catch (InterruptedException e) { throw new RuntimeException(e); } } // ユーザ指定の描画 callback.draw(applet); // BufferedImage に変換 // PImage#save メソッドのソース参照 PGraphics g = applet.g; g.loadPixels(); BufferedImage image = new BufferedImage(g.width, g.height, (g.format == PConstants.ARGB) ? BufferedImage.TYPE_INT_ARGB : BufferedImage.TYPE_INT_RGB); image.setRGB(0, 0, g.width, g.height, g.pixels, 0, g.width); // いちおう、グラフィックの廃棄 applet.destroy(); return image; } }
上の drawImage() の引数として使うコールバック用のインタフェース。Processing の機能を使いたいユーザは、このインタフェースを実装し、初期化や廃棄処理を除いた純粋な描画処理だけを draw() メソッドに定義する。
package example.processing; import processing.core.PApplet; public interface ProcessingCallback { void draw(PApplet pa); }
上のような機構を利用して、楕円描画サーブレットを作成してみる。
package example.processing; import java.awt.image.BufferedImage; import java.io.IOException; import javax.imageio.ImageIO; import javax.servlet.annotation.WebServlet; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import processing.core.PApplet; @SuppressWarnings("serial") @WebServlet(name="Ellipse", urlPatterns={"/ellipse.png"}) public class EllipseServlet extends HttpServlet { @Override public void doGet(HttpServletRequest req, HttpServletResponse res) { BufferedImage image = ProcessingUtils.drawImage(new ProcessingCallback() { /** * 具体的な描画内容のみを定義 */ @Override public void draw(PApplet pa) { pa.size(200, 100); pa.background(225); pa.smooth(); pa.fill(180, 230, 255); pa.ellipse(pa.width/2, pa.height/2, pa.width/2, pa.height/2); pa.fill(180, 0, 0); pa.text("テストです", 10, 10); } }); res.setContentType("image/png"); try { // PNGに変換して出力ストリームに流す ImageIO.write(image, "png", res.getOutputStream()); } catch (IOException e) { throw new RuntimeException(e); } } }
上記をWebアプリケーションとして、たとえばローカルホストの /processing にデプロイする。*2。
デプロイ後、http://localhost:8080/processing/ellipse.png にアクセスすると楕円画像が表示される。