目次||

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, 2020, Oracle and/or its affiliates. All rights reserved.