Go to Contents Go to Java Page

実験室

 
 

画像ファイルのロード

 
 

画像ファイルをロードするには

 
 

デジカメがこれだけ普及してくると、普通の人でも JPEG などのファイルを扱うことが増えてきていると思います。

もちろん、Java でも画像を扱うことができます。Java が登場した頃は Applet でアニメーションというのが非常にもてはやされました。そのほとんどが複数の画像ファイルをロードして、それをとっかえひっかえ描画するというものでした。

さて、Java 2 もバージョンが 1.4 までくると、画像の扱いもずいぶん変化しました。例えば、画像ファイルのロードだけでも次の 4 種類ぐらいあります。

クラス or ライブラリ 画像フォーマット 備考
java.awt.Toolkit JPEG, GIF, PNG Applet, IconImage などでもこのクラスを使用している
com.sun.image.codec.jpeg.JPEGImageDecoder JPEG いつ使えなくなるか不明
とりあえず、J2SE v1.4 ではまだ使える
Image I/O

(デフォルト) JPEG, GIF, PNG
(オプション) BMP, JPEG2000, PNM, Raw, TIFF, WBMP

デフォルトは J2SE v1.4 に含まれるもの
オプションは JAI の Web ページからダウンロード可能

Java Advanced Imaging API JPEG, GIF, PNG, BMP, PNM, TIFF コアには入っていないので、別途インストールが必要
JAI の Web ページ

ここにはあげていないのですが、JIMI というライブラリもあります。しかし、これは JDK 1.1 の頃のオプショナルライブラリで、現在はサポートされていないため、入れていません。

それぞれの方法のパフォーマンスや使い方などをまとめてみましょう。

 

 
 

java.awt.Toolkit

 
 

まずは JDK 1.0 の頃から使われている java.awt.Toolkit クラスを利用した画像ファイルのロードです。

このクラスを利用した場合の特徴は次の通りです。

特徴

  • どのバージョンの Java でも使用できる
  • 読み込めるのは JPEG, GIF, PNG
  • Applet#getImage メソッド (実際は AppletContext#getImage メソッド) や ImageIcon クラスでも内部的にこの方法を使用している。
  • 画像のロードが終了していなくても、メソッドからは抜けてしまう。したがって、ロードが終了したことを知るには java.awt.MediaTracker クラスを使用する。
  • ImageIcon クラスは内部で MediaTracker クラスを使用しているので、ロードの終了までブロックする。

使用法

    // ファイル名を指定する場合
    String filename = "foo.jpg";
    Image image = Toolkit.getDefaultToolkit().getImage(filename);


    // URL を指定する場合
    URL url = new URL("http://www.foo.bar.xx/foo.jpg");  // URL は適当です
    Image image = Toolkit.getDefaultToolkit().getImage(url);

Applet のサンプル

Applet の HTML ToolkitImageLoader1.html
Applet のソース ToolkitImageLoader1.java

このサンプルは Applet なので、画像ファイルの URL には CodeBase を利用しています。

    public void init() {
        try {
            URL url = new URL(getCodeBase(), "sample.jpg");
            image = Toolkit.getDefaultToolkit().getImage(url);
        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
    }

Toolkit#getImage はイメージのロードが終了しなくてもメソッドから抜けてしまいます。ようするにロードは別のスレッドで行っているわけです。これはこれでいいのですが、いざ描画するときになって画像がない場合には困ってしまいます。

こんなときに一緒に使用するのが java.awt.MediaTracker クラスです。サンプルは ToolkitImageLoader2 クラスです。

Applet の HTML ToolkitImageLoader2.html
Applet のソース ToolkitImageLoader2.java

MediaTracker クラスは読み込む画像ファイルに ID をつけて、ロードが終わっているかどうかを調べたり、ロードが終わるまで wait したりできます。ToolkitImageLoader2 クラスでは init メソッドで MediaTracker オブジェクトにロードする画像を ID つきで登録します。

    private Image image;
    private MediaTracker tracker;
    private int id = 0;
 
    public void init() {
        try {
            URL url = new URL(getCodeBase(), "sample.jpg");
            image = Toolkit.getDefaultToolkit().getImage(url);
 
            tracker = new MediaTracker(this);
            tracker.addImage(image, id);

        } catch (MalformedURLException ex) {
            ex.printStackTrace();
        }
    }

MediaTracker クラスのコンストラクタの引数は java.awt.Component オブジェクトです。Applet の場合は Applet 自体が Component の派生クラスなので、Applet オブジェクト自身を引数にしてしまいます。

もし、Component オブジェクトがなければ、ダミーの Component オブジェクトを使います。Component クラスは abstract クラスなので、そのままでは new できないので、Component クラスを派生させた無名クラスを使用します。

GUI はないけど、イメージだけ扱いたい場合などにこの方法が使えます。

    // Component オブジェクトがないとき
    // ダミーの Component オブジェクトを使用する
    MediaTracker tracker = new MediaTracker(new Component(){});

javax.swing.ImageIcon クラスも Toolkit クラスと MediaTracker クラスを使用して画像ファイルをロードしています。ImageIcon クラスも上述の方法と同じ方法で MeiaTracker オブジェクトを生成しています。

 

 
 

JPEGImageDecoder

 
 

JPEGImageDecoder クラスはコアライブラリとは異なり、Sun 独自のクラスになります。その特徴は次のとおりです。

特徴

  • パッケージは com.sun.image.codec.jpeg
  • Java 2 であれば今のところ使用可。
  • コアライブラリではないため、いつ使えなくなるか分からない。いきなり、次のバージョンで使えなくなったとしても不思議はない。少なくとも、J2SE v1.4 の JavaDoc には記述がなくなった。
  • 読み込めるのは JPEG のみ
  • 画像のロードが終了するまでブロックされる
  • ネイティブメソッドで記述されているため、高速

使用法

    String filename = "foo.jpg";
    InputStream stream = new FileInputStream(filename);
    
    JPEGImageDecoder decoder = JPEGCodec.createJPEGDecoder(stream);
    BufferedImage image = decoder.decodeAsBufferedImage();

JPEGCodec の static メソッドの createJPEGDecoder を使用してオブジェクトを生成し、decodeAsBufferedImage メソッドでロードします。ロードが終了するまで、ブロックされるので Toolkit クラスを使用したときのように MediaTracker クラスなどを使用した wait を行う必要はありません。

逆にいえば、ロード中に他のこと (例えば、ロード中であることをしめすプログレスバーを表示するとか) は別スレッドにする必要があります。

 

 
 

Image I/O

 
 

Image I/O は J2SE 1.4 からコアに含まれるようになりました。もともとは Java Advanced Imaging の一部だったのですが、独立して画像のロード・セーブに特化したものです。

特徴

  • J2SE v1.4 からコアライブラリ
  • パッケージは javax.imageio
  • もともとは Java Advanced Imaging API (JAI) の一部だったが、独立したパッケージとなったもの
  • 読み込めるのはデフォルト (J2SE v1.4 のみ) で JPEG、GIF、PNG
  • デフォルト以外に Java Advanced Imaging Image I/O Tools というのが JAI の Web ページで公開されている。
  • Image I/O Tools を使うと JPEG2000, BMP, TIFF などが読み込める
  • いろいろな読み込みパラメータなどを指定することも可能。詳しくはJ2SE 1.4 の新機能紹介のImage I/O を見てください
  • 読み込むためのライブラリは自分で拡張することも可能

使用法

ここでは一番基本的な方法だけを示しておきます。詳しい使用法は J2SE 1.4 の新機能紹介の Image I/O を見てください。

    File f = new File(filename);
    BufferedImage image = ImageIO.read(f);
 
      or
 
    BufferedImage image = ImageIO.read(new URL(url));
 
      or
    
    InputStream stream = new FileInputStream(filename); 
    BufferedImage image = ImageIO.read(stream);

 

 
 

Java Advanced Imaging API (JAI)

 
 

JAI は画像処理のためのライブラリで、フィルタリングやコンボリューションなど画像処理に欠かせない機能を提供しています。また、Java 2D のプッシュ型のイメージングではなく、プル型であることも特徴です。

JAI の画像ファイルのロードは Image I/O を呼び出す形になりますが、それをそのまま使っているわけではないようです。また、使い方はかなり違います。

特徴

  • プルモデルのイメージングのための API
  • パッケージは javax.media.jai
  • create メソッドの戻り値は RenderedOp なので、直接 Image としては扱えない
  • GUI に表示する場合は Graphics2D#drawRenderedImage メソッドを使用する
  • Image or BufferedImage にするには
    • BufferedImage を new して、Graphics2D を取り出し drawRenderedImage で RenderedOp を書き出す
    • RenderedOp から ColorModel と Raster を取り出し、それらをコンストラクタの引数にして BufferedImage を生成する
  • 読み込めるのは JPEG, GIF, PNG, BMP, PNM, TIFF
  • JAI の Web ページ

使用法

RenderedOp オブジェクトを生成する部分まで示して起きます。この後は、アプリケーションによって扱いがかなり異なると思うので。

RenderedOp op = JAI.create("fileload", filename);

 

 
 

実験、実験

 
 

上述した 4 種類の方法を使用してパフォーマンスを測定してみました。

JAI は画像のロードだけではあまり意味がないので、読み込んでそれを表示するまでの時間で計測しました。計測に使用したテスト用プログラムは ImageLoadingTest.java。測定条件は J2SDK, SE, v1.4.1_01, Athron 800MHz, RAM 512MB, Win 2000 です。

結果

手法 約 1 MB の画像ファイル (200万画素のデジカメの画像) を読み込む時間 [ms] 約 2.5 MB の画像ファイル (600万画素のデジカメの画像) を読み込む時間 [ms]
Toolkit
901
1883
sun.com.image.codec.jpeg
661
1622
Image I/O
811
2013
JAI
2694
4346

sun.com.image.codec.jpeg はネイティブで記述されているためか、高速です。ただ、いつ使えなくなるか分からないところが困りもの。

Toolkit と Image I/O はほぼ同じようなパフォーマンス。私だったら、J2SE v1.4 以上であれば Image I/O、v1.4 以下だったら Toolkit を使用すると思います。Image I/O はサムネイルや複数イメージ (例えばアニメーション GIF など) も扱えるなど、高機能であるのがその理由です。

JAI は画像の読み込みのためのAPI ではないので、遅いのは当然かもしれません。JAI で画像ロードだけを使うという使い方はかなり邪道なので、イメージングの一環として使うにはいいと思います。

ここでは、ロードの時間だけを測定しましたが、メモリの使用量も重要になると思います。

(Apr. 2003)

 
 
Go to Contents Go to Java Page