2010/06/20

Java でサムネイル作成 その 1

このエントリーをはてなブックマークに追加

Java でイメージ処理、特にサムネイルを作成する需要があるらしいのです。で、書き始めてみたのですが、結構分量になりそう。で、何回かに分けて書くことにします。

ぶっちゃけ結論だけ書いてもいいんですけど、それだと応用がきかないので基本的なところから。

Java のイメージ

Java でイメージを扱うにはいくつかの方法があります。

  • java.awt.Image クラス
  • java.awt.VolatileImage クラス
  • java.image.BufferedImage クラス

Imageクラスは Java でのイメージ処理の基本となるクラスです。ところが、このクラスのインスタンスは OS のイメージ処理に依存しています。

Windows であれば Windows のイメージ、Linux であれば Linux のイメージになるわけです。

もともと AWT は、処理を OS に投げているだけなので、イメージもそういう扱いになります (後から Lightweight Component の概念が出てきましたが、当初は Heavyweight しかなかったんです)。

そして、よりプラットフォームに依存したのが VolatileImage です。このクラスは J2SE 1.4 で導入されたクラスで、VRAM をそのままマッピングしたクラスと考えることができます。

つまり、Direct X とか OpenGL が扱う VRAM に直結したクラスです。なので、ゲームなどを作る時はこのクラスを使うことが多いです。

最後の BufferedImage クラスが Java だけで閉じているクラスです。このクラスは Java 2D と Swing が導入された時に一緒に入ったクラスです。

ということは、グラフィックシステムがないサーバで使うのであれば、BufferedImage クラスしかないことが分りますね。

しかし、単純に BufferedImage クラスを使えばいいというわけではありません。

BufferedImage クラスを使う場合、色空間をどうするかを考える必要があります。へたな色空間を使ってしまうと、ヒープは食うし、処理は遅いしで、いいことは全然ありません。

色空間については、次回書きます。もったいぶっているわけではないのですが、ちょっと長くなるので。

イメージのロード

次に考えなくてはイメージのロードをどうやるかということです。イメージのロードには次の方法が考えられます。

  • java.awt.Toolkit クラスの getImage メソッド
  • Image I/O

JAI を使う方法もありますが、JAI の入出力は Image I/O と同じなので省略します (書き方は違うけど、内部の処理が同じということ)。また、以前は com.sun.image.codec.jpeg.JPEGImageDecoder クラスというのもありましたが、com.sun で始まるクラスは使えないと思った方がいいです。

Toolkit クラスを使うと、Image オブジェクトをえることができます。一方の Image I/O は BufferedImage オブジェクトになります。

また、Toolkit クラスでのイメージのロードは非同期、Image I/O のロードは同期という違いもあります。

なお、サーバーではヘッドレスの場合も多いので、Toolkit クラスが使えない場合もあります。

イメージファイルにはサムネイルも一緒に含まれている場合があります。そのような場合、Image I/O でサムネイルだけロードできるので、高速に読み込むことができます。

コードで書くと、こんな感じ。

    public void loadThumbnail(String imagefile) {
        try {
            Iterator<ImageReader> readers
                = ImageIO.getImageReadersBySuffix("jpg");
            ImageReader reader = null;
            if (readers.hasNext()) {
                reader = readers.next();
            } else {
                System.err.println("No ImageReader");
                return;
            }
            
            ImageInputStream stream
                = ImageIO.createImageInputStream(new File(imagefile));
            reader.setInput(stream);
            
            if (reader.hasThumbnails(0)) {
                System.out.println(imagefile + " has thumbnail.");
                BufferedImage image = reader.readThumbnail(0, 0);
                
                System.out.println("Thumbnail width: " + image.getWidth()
                                   + " height: " + image.getHeight());
            } else {
                System.out.println(imagefile + " doesn't have thumbnail.");
            }
        } catch (IOException ex) {
            ex.printStackTrace();
        }
    }

ただし、この方法だとサムネイルを持っていないイメージファイルには使えないし、サムネイルのサイズは任意に決められないという欠点もあります。

でも、条件にあうようなイメージファイルであれば、とても高速。

ということで、今日のまとめ

  • イメージを扱うクラスは 3 種類あるので、どれが最適なのか考えて使おう
  • イメージのロードには Toolkit クラスと Image I/O がある
  • イメージファイルにサムネイルが含まれている場合は、Image I/O でサムネイルだけロードする

次回はイメージの縮小について書きます。

0 件のコメント: