JRubyでFilthyRichClients その6

Filthy Rich Clientsの第五章はパフォーマンスに関する話題です。
アプリの速度向上のために気をつけることが書かれています。

クリッピング

与えられたクリッピングの中だけで描画を行うようにする。

# クリッピングを使わないコード
def paintComponent(g)
  g.setColor(Color::BLACK)
  g.fillRect(0, 0, getWidth, getHeight)
end

# クリッピングを使ったコード
def paintComponent(g)
  g.setColor(Color::BLACK)
  clip = g.getClipBounds
  g.fillRect(clip.x, clip.y, clip.width, clip.height)
end

でも、クリッピングを簡単に使えないときは、無理に使う必要は無いみたい。

中間画像

画像に何度も同じ加工をしなければいけない時は、最初に画像を加工したら、加工した画像を取っておく。2回目以降は、取っておいた画像をdrawImageでコピーして使う。毎回画像を加工するより、コピーするほうが速い。

互換画像

実行している環境に最適化された画像を内部でもっておけば速い。画像を互換画像に変換して、互換画像のほうを使うようにする。
画像を互換画像に変換するmoduleをJRubyで書いてみた。

require 'java'

module MakeCompatibleImage
  import 'java.awt.GraphicsEnvironment'
  
  module_function
  
  def get_configuration
    GraphicsEnvironment.getLocalGraphicsEnvironment.getDefaultScreenDevice.getDefaultConfiguration
  end
  
  # 与えられた幅、高さ、透明度を持つ互換画像を作成する。
  # transparencyは、BufferedImage#getTransparencyで取得するか、以下の定数を指定できる。
  #   java.awt.Transparency::BITMASK
  #   java.awt.Transparency::OPAQUE
  #   java.awt.Transparency::TRANSLUCENT
  #   http://java.sun.com/j2se/1.5.0/ja/docs/ja/api/java/awt/Transparency.html
  def create_compatible_image(width, height, transparency)
    get_configuration.createCompatibleImage(width, height, transparency)
  end
  
  # 与えられた画像が、互換画像であるか調べる。
  def compatible_image?(image)
    image.getColorModel.equals(get_configuration.getColorModel)
  end
  
  # ソース画像をコピーした、新しい互換画像を作成する。
  # 既にソース画像が互換の場合は、ソース画像を返す。
  def to_compatible_image(image)
    return image if compatible_image?(image)
    
    compatible_image = create_compatible_image(image.getWidth, image.getHeight, image.getTransparency)
    g = compatible_image.getGraphics
    g.drawImage(image, 0, 0, nil)
    g.dispose
    compatible_image
  end
  
  # 引数で指定された画像へのパスから、互換画像を作成する。
  # パスはURLかファイル名を指定する。
  # ex:
  #   MakeCompatibleImage.load_compatible_image("http://sample.com/foo.png")
  #   MakeCompatibleImage.load_compatible_image("foo.png")
  def load_compatible_image(path)
    klass = fetch_resource_class(path)
    image = javax.imageio.ImageIO.read(klass.new(path))
    to_compatible_image(image)
  end
  
  def fetch_resource_class(path)
    return java.net.URL if path =~ %r!^http://!
    java.io.File
  end
end

if __FILE__ == $0
  include_class 'java.awt.image.BufferedImage'
  
  p MakeCompatibleImage.get_configuration
  
  img = BufferedImage.new(100, 50, BufferedImage::TYPE_INT_ARGB)
  p MakeCompatibleImage.create_compatible_image(img.getWidth, img.getHeight, img.getTransparency)
  
  [BufferedImage::TYPE_INT_ARGB, BufferedImage::TYPE_INT_RGB].each do |type|
    image = BufferedImage.new(100, 50, type)
    print "compatible_image?:"
    p MakeCompatibleImage.compatible_image?(image)
    p image
    p MakeCompatibleImage.to_compatible_image(image)
    p ""
  end
  
end

書いたんだけど、JavaのImageIOで、URLオブジェクトからimageを作ろうとすると例外が飛ぶ。
Fileだと上手くいくんだけど。。。↓のように単純化してもエラーになるんだけど、なんでだろ。。

  image = javax.imageio.ImageIO.read java.net.URL.new("http://www.google.co.jp/images/srpr/nav_logo13.png")
javax.imageio.ImageIO:-1:in `createImageInputStream': javax.imageio.IIOException: Can't create cache file! (NativeException)
	from javax.imageio.ImageIO:-1:in `read'