2015年7月2日木曜日

テキストからpngを生成する

メールアドレスをWebに載せるときにはpngにしてくれ、とかいうリクエストに応じるために必要に迫られて作ってみた。今どきメールアドレスなんてどこからでも漏れるし、SPAMフィルターは相当優秀だから、あんまり意味ないと思うのだけど。
  • pngのサイズを決めるのに、一度Graphics を作ってFontMetricsを取得している
  • 透明pngを生成するのに相当苦労したのだが、これはBufferedImageの型の問題で、TYPE_BRGにしていたのが問題だった。Alphaがないので透明にならないのだった。TYPE_ARGBが正解。
  • 気になるのは、相当遅いこと。2秒位かかる。AWTを使ってるので、ライブラリをごっそり読み込んでるのかな。。たくさん作るとボトルネックになるかも。バルクで変換するようにすればいいのだろうけど。
import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import javax.imageio.ImageIO;

public class TextImage {
  public static void main(String[] args) throws IOException {
    if (args.length < 1) 
      usage();
    OutputStream out =  System.out;
    if (args.length >= 2)
      out = new FileOutputStream(args[1]);
      render(args[0], out); 
  }

  private static void usage() {
    System.err.println("java TextImage INPUT_TEXT [output file]");
    System.exit(1);
  }

  private static void render(String txt, OutputStream os) 
    throws IOException {
    // サイズを決定するために一度Graphicsを作ってFontMetrics を取得する
    BufferedImage im = 
       new BufferedImage(1000, 1000,  BufferedImage.TYPE_INT_ARGB);
    Graphics g = im.getGraphics();
    g.setFont(new Font("Courie", Font.PLAIN, 30));
    FontMetrics fm = g.getFontMetrics();

    int width = fm.stringWidth(txt);
    int height = fm.getHeight();
    int ascent= fm.getAscent();
    im = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    g = im.getGraphics();
    g.setFont(new Font("Courie", Font.PLAIN, 30));
    paint(g, txt, ascent);
    ImageIO.write(im, "png", os);
  }

  public static void paint(Graphics g, String txt, int ascent){
    Graphics2D g2 = (Graphics2D)g;

    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0)); 
    g2.setPaint(Color.white);
    g2.fillRect(0, 0, 1000, 1000);

    g2.setComposite(AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 1));
    g2.setPaint(Color.black);
    g2.drawString(txt, 0, ascent); 
  }

}