目次 | 前の項目 | 次の項目 | JavaTM Image I/O API ガイド |
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
を呼び出したときの結果と同じです。
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);
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
メソッドから戻る前にすべて一度に実行するかのどちらかです。
ImageReader
クラスのメソッドのうち、イメージを処理するメソッドはすべて、imageIndex
パラメータをとります。このパラメータを使用して、マルチイメージファイル内の任意のイメージにアクセスできます。
ImageReader.getNumImages
メソッドは、入力ファイルに格納されているイメージの数を返します。このメソッドは、boolean 型のパラメータallowSearch
をとります。一部のイメージ形式 (特に GIF) では、ファイル全体を読み込まずにイメージの数を判別する手段が提供されていません。これでは負荷が掛かりすぎることがあるので、allowSearch
にfalse
を設定することができます。その場合、読み込みオブジェクトは戻り値として実際のイメージ数ではなく、-1
を返します。このパラメータがtrue
の場合、読み込みオブジェクトは常に実際のイメージ数を返します。アプリケーションがイメージの数を識別できない場合でも、
read(imageIndex)
を呼び出すことは可能です。インデックスが大きすぎると、このメソッドは例外IndexOutOfBoundsException
をスローします。したがって、アプリケーションは、例外を受け取るまで、インデックスを増やしながらイメージを要求することができます。
一部のイメージ形式では、1 つの小さいプレビューイメージ (または複数のプレビューイメージ) を、メインのイメージと一緒に格納できます。この「サムネール」イメージは、イメージ全体を復号化する必要なしに、イメージファイルをすばやく識別できて便利です。アプリケーションは、次の呼び出しによって、特定のイメージに関連付けられているサムネールの数を判別できます。
reader.getNumThumbnails(imageIndex);
サムネールイメージが存在する場合は、次のような呼び出しによって取得できます。
int thumbailIndex = 0; BufferedImage bi; bi = reader.readThumbnail(imageIndex, thumbnailIndex);