AWT イメージスケーリング API


最終更新日: 1996 年 10 月 30 日

問題

Java は、drawImage() が呼び出されたときに自動的にイメージを拡大縮小する多くの機構を提供します。これらの機構は、正確な動作に関して明確にドキュメント化されておらず、参照ポート用に選択する特定の実装が、プログラマの期待と異なる動作をするために混乱を生じています。

特に、イメージが画面に表示されるとき、Image データは画面の配色機能に合う形式に変換されます。元のイメージデータは持続的に格納されず、変換された画面データだけが画面表示によって格納されます。イメージのデータが他の目的 (新しいイメージのためのデータのフィルタリングなど) で必要な場合、raw データを元のソースから再ロードする必要があります。

元のデータは、最初にロードした直後に 2 つ目の目的のために必要になる場合に備えて、キャッシュに格納されています。単一のイメージがいくつかのフィルタを通して実行される場合、後続のフィルタをかけたイメージは、イメージファイルをソースから再ロードせずに、キャッシュされた変換データを使用できる可能性があります。 しかし、このキャッシュされたデータは一般的に信頼できません。
幅と高さを指定できる drawImage メソッドの変異形の 1 つを使用してイメージを拡大縮小するとき、別個の画面表示が、描画されたサイズに対して作成されます。さらに、8 ビット画面上の出力用にディザリングされたあとイメージを拡大縮小すると、出力品質が非常に低下するため、スケーリングは常に元のイメージデータから行います。たとえ、画面が 24 ビットの深さで、画面表示に元のイメージデータが変換損失なしで含まれるとしても、この実装ではローカルコピーを使用することはあまり賢明ではありません。 イメージのソースデータを使うことをお勧めします。

描画された各サイズに対して別個のイメージ表示を格納することのもう 1 つの欠点は、消費するメモリの量です。描画された各サイズに対して別個の表示を格納する方法は、すべてのデータが画面にバイト単位でコピーされるため、レンダリング速度を最小にします。 しかし、この方法は結果的に逆効果になります。拡大縮小されたサイズを事前に計算することによって速度を短縮しても、拡大縮小された変異形がロードされ変換される間の待ち時間があるために短縮した意味がなくなります。 イメージデータを遅いネットワーク上で再ロードする必要がある場合は特にそうです。また、イメージが繰り返されず多数の異なるサイズで描画されている場合、拡大縮小された表示をキャッシュするために使用するメモリが浪費されます。

つまり、イメージの拡大縮小されたバージョンが後続のレンダリングにキャッシュされるかどうか、イメージスケーリングがただちに行われるかまたはバックグラウンドで行われるかを、プログラマは制御することができません。

これ以外に開発者にとって問題となるのは、既存のイメージの拡大縮小されたビューを表わす新しいオブジェクトを作成する方法がないことです。Image オブジェクトは、新しい幅と高さのパラメータを drawImage の呼び出しに与えることで拡大縮小できますが、その情報を Image オブジェクトにカプセル化し、その Image オブジェクトを渡すことによって希望するサイズのイメージを描画する方法はありません。

新しいイメージスケーリング API とその動作

この問題を解決するために、イメージを拡大縮小する drawImage メソッドに新しい方法を適用します。1.1 以降は、drawImage によるすべてのスケーリングは、レンダリングの際に、フルサイズ画面表示から瞬時に行われます。

この変更には 2 つの主な欠点があります。

  1. イメージを拡大縮小するために新しい drawImage を使用すると、ピクセルの再順番付けをレンダリング時に実行する必要があるため、以前より若干時間がかかります。
  2. 拡大縮小されたイメージの質は、ピクセルの再順番付けがディザリングプロセスのあとで行われるため、8 ビットでは低下します。

あとに明らかになったことですが、1 つ目の問題は当初予想していたほどは大きなものではありません。過去 2、3 年で、プロセッサは、特にメモリシステムと比較して非常に速くなっています。結果として、イメージスケーリングのパフォーマンスは、ほとんどがメモリアクセス速度によって制限され、希望する特定のスケーリングのために、画面にコピーする次のピクセルがどれかを決定するために必要な計算は、データを画面に移動する作業に比べてさほど問題にはなりません。

品質については大きな問題になる可能性がありました。1.1 より前の JDK 実装に使用された 8 ビット色変換コードでは、ディザリングのあとに拡大縮小された場合、イメージが大幅に劣化しました。新しい色変換アルゴリズムが 1.1 用に開発され、結果のディザイメージの品質が向上しました。 ディザ表示のスケーリングの結果は、スケーリングのあとにディザリングされる 1.0.2 イメージの結果より良くはないとしても、通常同じくらいになりました。

イメージスケーリングの実装は 1.1 で強化され、レンダリング時に瞬時にスケーリングすることが可能になりました。 しかし、拡大縮小されたイメージの品質を向上させるために、可能なあらゆる手段をとることを希望する場合もあります。レンダリング時にではなく、プログラマが明示的なスケーリングをいつ実行するかを選択できるように、2 つの新しいフィルタクラスが使用可能になり、新しい便利なメソッドが 1.1 の AWT Image クラスに追加されます。この同じ API をプログラマが使用して、自分自身の Image オブジェクトにカプセル化されるイメージの拡大縮小されたバージョンを表す新しい Image オブジェクトを作成することできます。新しいイメージスケーリングクラスには、次のものがあります。

	java.awt.image.ReplicateScaleFilter
	java.awt.image.AreaAveragingScaleFilter
Image クラスの新しいメソッドは次のとおりです。
	getScaledInstance(int width, int height, int hints)
hints パラメータは、イメージを拡大縮小するためにどの種類のアルゴリズムを使用するかを制御します。hints には、使用する特定のアルゴリズムを参照する指定や、速度や品質のために操作を最適化するかどうかを指示するさらに抽象的な指定があります。現在 hints パラメータに設定できる適正な値は、次のとおりです。
Image.SCALE_DEFAULT
デフォルトスケーリングアルゴリズムを使用する (ユーザ構成に基づき選択可能)
Image.SCALE_FAST
拡大縮小されたイメージの滑らかさよりも速度を最適化するスケーリングアルゴリズムを選択する
Image.SCALE_SMOOTH
速度よりも拡大縮小されたイメージの滑らかさを最適化するスケーリングアルゴリズムを選択する
Image.SCALE_REPLICATE
ReplicateScaleFilter によって実装されたアルゴリズムを使用する
Image.SCALE_AREA_AVERAGING
AreaAveragingScaleFilter によって実装されたアルゴリズムを使用する

サンプルコード

イメージを拡大縮小するための新しい API の使用方法を示すサンプルコードを次に示します。

    import java.awt.*;
    import java.applet.*;

    public class ImgScaleExample extends Applet {
	Image img, img2;
    	public void init() {
	    img = getImage(getDocumentBase(), "foo.gif");
	    img2 = img.getScaledInstance(100, 100, Image.SCALE_DEFAULT);
	}

	public void paint(Graphics g) {
	    // Draw the full size image
	    g.drawImage(img, 0, 0, this);
	    // Draw the scaled version of the image
	    g.drawImage(img2, 10, 10, this);
	    // Now draw a scaled version of the scaled image
	    g.drawImage(img2, 110, 10, 50, 50, this);
	}
    }


コメントの送付先: java-awt@java.sun.com
Copyright © 1996, Sun Microsystems, Inc. All rights reserved.