目次 | 前へ | 次へ

3.3 ImageReader

アプリケーションは、ImageIO クラスを使用してイメージのデコード処理全体を実行するのではなく、ImageIO クラスを使用して ImageReader オブジェクトを取得し (下のコード例を参照)、そのオブジェクトを使用して読み込みを実行することができます。
Iterator readers = ImageIO.getImageReadersByFormatName("gif");
ImageReader reader = (ImageReader)readers.next();
読み込みオブジェクトは、ファイルの内容、ファイルの拡張子、または MIME タイプに基づいて取得することもできます。読み込みオブジェクトを検索してインスタンス生成するメカニズムでは、javax.imageio.spi.ImageReaderSpi クラスを利用します。このクラスを使うと、プラグインを実際にインスタンス生成しなくても、読み込みプラグインについての情報を取得できます。「サービスプロバイダインタフェース」(service provider interface、SPI) の概念については、次の章で詳しく説明します。

読み込みプラグインを取得したあとは、そのオブジェクトに入力ソースを提供しなければなりません。大部分の読み込みオブジェクトは、ImageInputStream からデータを読み込めます。これは、Image I/O API によって定義されている特殊な入力ソースです。特殊な入力ソースを使用する目的は、読み込みオブジェクトや書き込みオブジェクトが、ファイル入出力とストリーム入出力の両方を簡単に処理できるようにすることです。

ImageInputStream を取得するのは簡単です。入力ソースが File または InputStream の形式である場合、ImageInputStream は、次のような呼び出しによって生成できます。

Object source; // File or InputStream
ImageInputStream iis = ImageIO.createImageInputStream(source);
ソースを取得したあとは、次の呼び出しによってそのソースを読み込みオブジェクトに接続できます。
reader.setInput(iis, true);
この 2 番目のパラメータは、ソースファイルに複数のイメージが含まれていて、アプリケーションがそれらのイメージを順番に読み込めるという保証がない場合には、false に設定する必要があります。1 つのファイルに 1 つのイメージしか格納できないファイル形式の場合には、このパラメータに常に true を設定するようにします。

読み込みオブジェクトに入力ソースを設定したあとは、必ずしもイメージデータをメモリー内に読み込まないでも、そのオブジェクトを利用してイメージについての情報を入手できます。たとえば、reader.getImageWidth(0) を呼び出せば、ファイルに格納されている最初のイメージの幅を入手できます。上手に作成されたプラグインであれば、イメージの幅を判別するのに必要なデータだけをデコードし、ピクセルは読み込まないようにするはずです。

イメージを読み込むには、アプリケーションから reader.read(imageIndex) を呼び出します (imageIndex は、ファイル内のイメージのインデックス)。この呼び出しの結果は、上で説明した ImageIO.read を呼び出したときの結果と同じです。


3.3.1 ImageReadParam

読み込み処理をさらに詳細に制御するには、read メソッドに ImageReadParam 型の追加パラメータを指定します。ImageReadParam を使用すると、デコードされたイメージを格納するデスティネーションイメージを指定できるので、メモリーの使用を効率よく制御できます。また、読み込みたい領域を指定することや、イメージの縮小版を取得するために利用できるサブサンプリング係数を指定することも可能です。

ソース領域が設定された場合は、ファイル形式が部分的なデコードを許しているかぎり、読み込みプラグインは、設定された領域だけをデコードしようとします。どんな場合にも、設定された領域の外側にあるピクセルは出力されません。この機能により、非常に大きいイメージをかぎられた量のメモリーで処理することが可能になります。

たとえば、イメージの左上の 4 分の 1 区画だけをデコードするには、まず、読み取りオブジェクトで使用するための ImageReadParam を次のようにして取得します。

ImageReadParam param = reader.getDefaultReadParam();
次に、読み込みたいソース領域を、次のようにして ImageReadParam に設定します。
import java.awt.Rectangle;
int imageIndex = 0;
int half_width = reader.getImageWidth(imageIndex)/2;
int half_height = reader.getImageHeight(imageIndex)/2;
Rectangle rect = new Rectangle(0, 0, half_width, half_height); 
param.setSourceRegion(rect);
そして最後に、この ImageReadParam を使用して、次のようにイメージを読み込みます。
BufferedImage bi = reader.read(imageIndex, param);
この結果として出力されるのは、幅と高さがそれぞれ元のイメージの半分になった BufferedImage です (イメージの幅や高さが奇数の場合、端数は切り捨てられます)。

このあと、イメージの右下の 4 分の 1 区画を、左上の 4 分の 1 区画を保持するために作成した同じ BufferedImage に読み込むには、次のようにして以前のピクセルデータを上書きします。

param.setDestination(bi);
rect = new Rectangle(half_width, half_height, half_width, half_height); 
param.setSourceRegion(rect);
BufferedImage bi2 = reader.read(0, param);
if (bi == bi2) {
        System.out.println("The same BufferedImage was used!");
} else {
        System.out.println("This can't happen!");
}
実際には、結果をどこに割り当てるかを指定せずに、単に reader.read(0, param) を呼び出すこともできます。ピクセルは既存の BufferedImage である bi に書き込まれるということがわかっているからです。

別の例としては、イメージのピクセルを 3 つに 1 つの割合で読み込み、元のサイズの 9 分の 1 のイメージを生成するため、次のようにして、ImageReadParam にサブサンプリング係数を設定することもあります。

param = reader.getDefaultImageParam();
param.setSourceSubsampling(3, 3, 0, 0);
BufferedImage bi3 = reader.read(0, param);


3.3.2 IIOParamController

プラグインは、オプションとして、IIOParamController オブジェクトを提供することができます。このオブジェクトは、IIOReadParam (または IIOWriteParam) を、グラフィカルユーザーインタフェース (GUI) やその他のインタフェースを利用してセットアップするために使用されます。読み込みプラグインでは、作成した任意の ImageReadParam オブジェクトに対して、次のようにして IIOParamController を付加できます。
ImageReadParam param = reader.getDefaultImageParam();
IIOParamController controller = param.getController();
if (controller != null) {
        controller.activate(param);
}
コントローラの activate メソッドを呼び出すと、GUI が表示され、ユーザーがスライダを動かしたり、ボタンをクリックしたりするイベントが処理されます。通常、このインタフェースには「OK」または「適用」ボタンがあって、そのボタンがクリックされると、activate メソッドから戻ります。コントローラには、結び付けられた ImageReadParam の状態を更新するためのメソッドを呼び出す責任があります。メソッドの呼び出しは、各 GUI イベントが発生するたびに実行するか、activate メソッドから戻る前にすべて一度に実行するかのどちらかです。

3.3.3 マルチイメージファイルからの読み込み

ImageReader クラスのメソッドのうち、イメージを処理するメソッドはすべて、imageIndex パラメータをとります。このパラメータを使用して、マルチイメージファイル内の任意のイメージにアクセスできます。

ImageReader.getNumImages メソッドは、入力ファイルに格納されているイメージの数を返します。このメソッドは、boolean 型のパラメータ allowSearch をとります。一部のイメージ形式 (特に GIF) では、ファイル全体を読み込まずにイメージの数を判別する手段が提供されていません。これでは負荷が掛かりすぎることがあるので、allowSearchfalse を設定することができます。その場合、読み込みオブジェクトは戻り値として実際のイメージ数ではなく、-1 を返します。このパラメータが true の場合、読み込みオブジェクトは常に実際のイメージ数を返します。

アプリケーションがイメージの数を識別できない場合でも、read(imageIndex) を呼び出すことは可能です。インデックスが大きすぎると、このメソッドは例外 IndexOutOfBoundsException をスローします。したがって、アプリケーションは、例外を受け取るまで、インデックスを増やしながらイメージを要求することができます。


3.3.4「サムネール」イメージの読み込み

一部のイメージ形式では、1 つの小さいプレビューイメージ (または複数のプレビューイメージ) を、メインのイメージと一緒に格納できます。この「サムネール」イメージは、イメージ全体をデコードする必要なしに、イメージファイルをすばやく識別できて便利です。

アプリケーションは、次の呼び出しによって、特定のイメージに関連付けられているサムネールの数を判別できます。

reader.getNumThumbnails(imageIndex);
サムネールイメージが存在する場合は、次のような呼び出しによって取得できます。
int thumbailIndex = 0;
BufferedImage bi;
bi = reader.readThumbnail(imageIndex, thumbnailIndex);


目次 | 前へ | 次へ

Copyright © 1993, 2013, Oracle and/or its affiliates. All rights reserved.
連絡先