目次 | 前の項目 | 次の項目 JavaTM 2D API プログラマーズガイド

第 2 章   

Graphics2D を使ったレンダリング

java.awt.Graphics を継承する Graphics2D では、図形、テキスト、およびイメージの表示について制御できる内容が、一段と高度になっています。Java 2D™ のレンダリング処理は、Graphics2D オブジェクトとその状態属性を使って制御します。

Graphics2D の状態属性には線の形状や変換などがあり、グラフィックオブジェクトがレンダリングされるときに適用されます。Graphics2D に関する状態属性の集合を、Graphics2D 「コンテキスト」と呼びます。テキストや図形やイメージをレンダリングするには、Graphics2D コンテキストを設定してから、drawfill などの Graphics2D レンダリングメソッドの 1 つを呼び出します。

2.1 インタフェースとクラス

次の表は、Graphics2D コンテキストに関連して使うインタフェースとクラスの一覧です。 状態属性を表すクラスも含まれています。これらのほとんどのクラスは、java.awt パッケージに含まれています。

インタフェース
説明
Composite
基になるグラフィックス領域に描画プリミティブを合成するためのメソッドを定義します。AlphaComposite で実装されます。
CompositeContext
合成操作のためのカプセル化されて最適化された環境を定義します。プログラムで独自の合成規則を実装するときに使われます。
Paint
スーパークラス: Transparency
draw 操作または fill 操作での色を定義します。ColorGradientPaint、および TexturePaint で実装されます。
PaintContext
塗りつぶし操作のためのカプセル化されて最適化された環境を定義します。プログラムで独自の塗りつぶし操作を実装するときに使われます。
Stroke
レンダリングされる Shape の輪郭線を囲む Shape を生成します。BasicStroke で実装されます。
クラス
説明
AffineTransform
(java.awt.geom)
2 次元のアフィン変換を表します。 ある 2 次元座標から別の 2 次元座標への線形変換を行います。
AlphaComposite
インタフェース: Composite
図形、テキスト、イメージを合成するときの透過率に関する基本的な規則を実装します。
BasicStroke
インタフェース: Stroke
Shape の輪郭線に適用される「ペンのスタイル」を定義します。
Color
インタフェース: Paint
Shape に均一な塗りつぶしを定義します。
GradientPaint
インタフェース: Paint
Shape にグラデーションの塗りつぶしパターンを定義します。この塗りつぶしパターンは、点 P1 の色 C1 から点 P2 の色 C2 まで変化します。
Graphics2D
スーパークラス: Graphics
2 次元レンダリングの基本クラスです。元の java.awt.Graphics クラスを継承しています。
TexturePaint
インタフェース: Paint
テクスチャまたはパターンを使った Shape の塗りつぶしを定義します。テクスチャやパターンは、BufferedImage から生成されます。

2.2 レンダリングのコンセプト

Java 2D™ API を使ってグラフィックオブジェクトをレンダリングするには、Graphics2D コンテキストを設定してから、Graphics2D レンダリングメソッドの 1 つににグラフィックオブジェクトを渡します。

Graphics2D コンテキストを構成する状態属性を変更することで、次の操作が可能です。

Graphics2D では、グラフィックスコンテキストの属性を追加または変更するためのメソッドがいくつか定義されています。大部分のメソッドは、Paint オブジェクトや Stroke オブジェクトなど、特定の属性を表すオブジェクトを受け取ります。

Graphics2D コンテキストは、このような属性オブジェクトの「参照」を保持します。属性オブジェクトは複製されません。Graphics2D コンテキストに含まれる属性オブジェクトを変更する場合は、適切な set メソッドを呼び出して、コンテキストに通知する必要があります。レンダリング操作の間に属性オブジェクトを変更すると、予測できない動作をしたり、場合によっては動作が不安定になります。

2.2.1 レンダリング処理

グラフィックオブジェクトのレンダリングでは、幾何形状、イメージ、および属性の情報がまとめられて、ディスプレイ上で変更する必要のあるピクセル値が算出されます。

Shape のレンダリング処理は、4 つのステップに分けることができます。

  1. Shape でストロークの描画が必要な場合は、Graphics2D コンテキストの Stroke 属性を使って、描画されるパスを囲む新しい Shape を生成します。
  2. Graphics2D コンテキストの変換属性に従って、Shape のパスの座標をユーザ空間からデバイス空間に変換します。
  3. Graphics2D コンテキストのクリッピング属性を使って、Shape のパスをクリッピングします。
  4. Shape に描画される部分がある場合は、Graphics2D コンテキストの Paint 属性と Composite 属性を使って塗りつぶします。

テキストのレンダリングは、Shape のレンダリングとほぼ同じです。 テキストは個別のグリフとしてレンダリングされて、グリフはそれぞれが Shape です。唯一の違いは、レンダリングの前に、テキストに適用される Font を判別し、Font から適切なグリフを取得する必要があることです。

イメージの処理はテキストや図形とは異なり、変換操作とクリッピング操作はイメージのバウンディングボックスに対して行われます。色の情報はイメージ自体から取り出されて、イメージのピクセルがレンダリング面に合成される際は、色情報のアルファチャネルがそのときの Composite 属性とともに使われます。

2.2.2 レンダリング品質の制御

Java 2D API では、速度と品質のどちらを優先してオブジェクトをレンダリングするか指定できます。優先情報は、Graphics2D コンテキストの RenderingHints 属性を使ってヒントとして指定します。レンダリングモードの変更に対応していないプラットフォームもあるため、指定したレンダリングヒントが必ず使われるとは限りません。

RenderingHints クラスは、次の種類のヒントをサポートしています。

Graphics2D コンテキストの RenderingHints 属性を設定または変更するには、setRenderingHints を呼び出します。ヒントをデフォルトに設定すると、プラットフォームでのレンダリングのデフォルト設定が使われます。

平滑化

グラフィックスプリミティブをラスタグラフィックスディスプレイ装置にレンダリングすると、「エイリアス化」のために縁がギザギザになる場合があります。弧や対角線の場合、直線や曲線の経路にもっとも近いピクセルをオンにして近似表現するので、ギザギザした表示になります。解像度の低い装置ではこの現象が特に顕著になるため、水平や垂直の線の滑らかな縁に対し、ぎざぎざの縁が際立って見えてしまいます。

「平滑化」は、オブジェクトの縁を滑らかにレンダリングするために使われる技法です。単純に直線や曲線にもっとも近いピクセルをオンにするのではなく、レンダリングされる形状によってカバーされる領域の大きさに比例して、周囲のピクセルの輝度が設定されます。これによって、オブジェクトの縁が鋭くなくなり、複数のピクセルにまたがってオンからオフへと移行するようになります。ただし、平滑化を行うと必要なリソースが増えるため、レンダリングの速度が遅くなる場合があります。

.

このグラフィックスは、前の文で説明したように、エイリアス化されたグラフィックスと平準化されたグラフィックスの例です。

2.2.3 ストローク属性

GeneralPath オブジェクトのような Shape のストロークを描画することは、GeneralPath のセグメントに沿って論理的なペンを走らせることに相当します。Graphics2DStroke 属性は、ペンによって描画される軌跡の特性を定義するものです。

Graphics2D コンテキストのストローク属性を定義するには、BasicStroke オブジェクトを使います。BasicStroke では、線の幅、線端のスタイル、セグメントの接合スタイル、破線パターンなどの特性が定義されています。Graphics2D コンテキストの Stroke 属性を設定または変更するには、setStroke メソッドを呼び出します。

このグラフィックスは、BasicStroke によってサポートされる、切り取り、丸め付き、または角付きの線端を含めた先端スタイルです。

図 2-1 BasicStroke によってサポートされる線端スタイル

このグラフィックスは、BasicStroke によってサポートされる、斜面、丸め、または角を付けた線端を含めた接続スタイルです。

図 2-2 BasicStroke によってサポートされる接続スタイル

たとえば、図 2-3 の最初のイメージは角を付けた接続スタイルを使っており、2 番目のイメージは丸めた接続スタイル、丸めた線端スタイル、および破線パターンを使っています。

前の文でのこのグラフィックスを説明しています。

図 2-3 ストロークのスタイル

Stroke 属性を使う Graphics2D レンダリングメソッドは、drawdrawArcdrawLinedrawOvaldrawPolygondrawPolylinedrawRect、および drawRoundRect です。これらのメソッドを呼び出すと、指定した Shape の輪郭がレンダリングされます。Stroke 属性は線の特性を定義し、Paint 属性はペンによって描画される軌跡の色とパターンを定義するものです。

たとえば、draw(myRectangle) を呼び出すと、次の処理が行われます。

  1. Stroke 属性を、矩形の輪郭線に適用する
  2. 描画する輪郭線を、Shape オブジェクトに変換する
  3. 輪郭線を表す Shape の外形の内側にあるピクセルに、Paint 属性を適用する

図 2-4 は、この処理を具体例で示したものです。

前の文で、このグラフィックスを説明しています。

図 2-4 Shape のストローク

2.2.4 塗りつぶし属性

Graphics2D コンテキストの塗りつぶし属性は、Paint オブジェクトで表されます。Graphics2D コンテキストに Paint オブジェクトを追加するには、setPaint メソッドを呼び出します。

Shape またはグリフを描画すると (Graphics2D.drawGraphics2D.drawString)、オブジェクトの輪郭線を描画する Shape の内側にあるすべてのピクセルに、Paint が適用されます。Shape を塗りつぶすと (Graphics2D.fill)、Shape の外形の内側にあるすべてのピクセルに、Paint が適用されます。

単純な均一の塗りつぶしは、setColor メソッドで設定できます。Color は、Paint インタフェースのもっとも簡単な実装です。

グラデーションやテクスチャのようなさらに複雑なスタイルで Shape を塗りつぶすには、Java 2D の Paint インタフェースの GradientPaint クラスと TexturePaint クラスを使います。単純な一色塗りで複雑な塗りつぶしを行おうとすると時間のかかる作業になりますが、これらのクラスを使うと手間のかかる作業は必要なくなります。図 2-5 に示す 2 種類の塗りつぶしは、GradientPaintTexturePaint で簡単に定義できます。

前の文で、このグラフィックスを説明しています。

図 2-5 複雑な塗りつぶしのスタイル

fill を呼び出して Shape をレンダリングすると、システムでは次の処理が行われます。

  1. Shape を構成するピクセルを特定する
  2. Paint オブジェクトから各ピクセルの色を取得する
  3. 色を出力装置の適切なピクセル値に変換する
  4. 出力装置にピクセルを書き出す
バッチ処理

ピクセルを効率よく処理するため、Java 2D API はバッチでピクセルを処理します。特定の走査線の連続したピクセル群またはピクセルのブロックをバッチ処理できます。このバッチ処理は、2 つのステップで行われます。

  1. Paint オブジェクトの createContext メソッドを呼び出し、PaintContext を作成します。PaintContext には、現在のレンダリング操作についてのコンテキスト情報と、色の生成に必要な情報が格納されます。createContext メソッドには、塗りつぶしの対象となっているグラフィックスオブジェクトのユーザ空間とデバイス空間におけるバウンディングボックス、色の生成に使われる ColorModel、およびユーザ空間からデバイス空間へのマッピングで使われる変換が渡されます。任意の ColorModel をサポートできない Paint オブジェクトもあるので、ColorModel はヒントとして扱われます。ColorModel の詳細については、「カラー」を参照してください。
  2. getColorModel メソッドを呼び出して、生成された塗りつぶし色の ColorModelPaintContext から取得します。

次に、getRaster メソッドを繰り返し呼び出して、各バッチの実際の色データを含む Raster を取得します。この情報はレンダリングパイプラインの次の段階に渡されて、そこでは、生成された色が現在の Composite オブジェクトを使って描画されます。

2.2.5 クリッピングパス

「クリッピングパス」は、Shape または Image の中のレンダリングが必要な部分を示すものです。Graphics2D コンテキストにクリッピングパスが含まれている場合、Shape または Image で実際にレンダリングされるのは、クリッピングパスの内側にある部分だけです。

Graphics2D コンテキストにクリッピングパスを追加するには、setClip メソッドを呼び出します。任意の Shape を使って、クリッピングパスを定義できます。

クリッピングパスを変更するには、setClip を呼び出して新しいパスを指定するか、あるいは clip を呼び出して、古いクリッピングパスと新しい Shape の交差している部分を新しいクリッピングパスにします。

2.2.6 変換

Graphics2D コンテキストに含まれている変換は、レンダリングでユーザ空間からデバイス空間にオブジェクトを変換するときに使われます。回転や拡大縮小など、これ以外の変換を行うには、その変換を Graphics2D コンテキストに追加します。追加した変換は、レンダリングの際に適用される変換のパイプラインの一部になります。

Graphics2D では、Graphics2D コンテキストの変換を変更する方法がいくつか提供されています。もっとも簡単な方法は、rotatescalesheartranslate などの Graphics2D 変換メソッドを呼び出すことです。レンダリングで適用する変換の特性を指定すると、Graphics2D が自動的に適切な変更を行います。

現在の Graphics2D の変換に、AffineTransform を明示的に「連結」することもできます。AffineTransform は、グラフィックスプリミティブのグループに対し、平行移動、拡大縮小、回転、変形などの線形変換を行います。既存の変換に新しい変換を連結すると、最後に指定した変換が「最初に」適用されます。現在の変換に新しい変換を連結するには、Graphics2D.transformAffineTransform を渡します。

Graphics2D クラスには setTransform メソッドも含まれますが、既存の変換に別の座標変換を連結するためにこのメソッドを使用しないでください。setTransform メソッドは Graphics2D オブジェクトの現行の変換を上書きします。この機能は、次のような操作を行う場合に必要です。

setTransform メソッドは、変換したグラフィックス、テキスト、またはイメージのレンダリング後に、Graphics2D オブジェクトを元の変換に戻す場合に使用します。

AffineTransform aT = g2d.getTransform(); 
g2d.transform(...);g2d.draw(...); 
g2d.setTransform(aT); 

Graphics2D では、パラメータとして AffineTransform を受け取る形式の drawImage メソッドも提供されています。このメソッドを使うと、変換のパイプラインを変更しなくても、イメージオブジェクトを描画するときに目的の変換を適用できます。イメージは、Graphics2D コンテキストの現在の変換に新しい変換を連結した場合と同じように描画されます。

アフィン変換

Java 2D API では、AffineTransform という変換クラスが提供されています。AffineTransform を使って、レンダリングの際のテキスト、図形、およびイメージの変換が行われます。Font オブジェクトに変換を適用し、新しいフォント派生を作ることもできます。 詳細については、「フォント派生の作成」を参照してください。

アフィン変換は、グラフィックスプリミティブのグループに対して線形の変換を行います。直線は直線に、平行線は平行線に、常に変換されますが、点の間の距離および平行ではない線の間の角度は変わります。

アフィン変換は、次の形式の 2 次元行列に基づいて行われます。

 

a、c および t のサブ x を含む先頭行を持つ 2 x 3 の配列。
2 番目の行は、b、d および t のサブ y を含んでいます。 ここでは、x プライム イコール a x プラス  c y プラス t サブ x および y プライム イコール b x プラス d y プラス t サブ y です。

 

変換を組み合わせることで、オブジェクトに適用できる一連の変換群、つまり変換の「パイプライン」を効果的に作成できます。この組み合わせのことを「連結」と呼びます。AffineTransform.concatenate などの既存の変換に新しい変換を連結すると、最後に指定した変換が「最初に」適用されます。既存の変換に、新しい変換を「前連結」することもできます。この場合は、最後に指定した変換が「最後」に適用されます。

前連結は、ユーザ空間ではなくデバイス空間に関係する変換を行うために使います。たとえば、絶対ピクセル空間に関係する変換を実行するには、AffineTransform.preConcatenate を使います。

2.2.6.1 AffineTransform の作成

AffineTransform では、AffineTransform オブジェクトを作成するための便利なメソッド群が提供されています。

これらのメソッドを使って作成する変換の特性を指定すると、AffineTransform が適切な変換行列を生成します。変換行列の要素を直接指定して、AffineTransform を作成することもできます。

2.2.7 重ね合わせ属性

2 つのグラフィックオブジェクトが重なる場合、重なった部分のピクセルをどのような色でレンダリングするかを決める必要があります。たとえば、赤い矩形と青い矩形を重ねる場合、2 つの図形が共有するピクセルは、赤、青、または 2 つの色の任意の組み合わせでレンダリングすることになります。重なる領域のピクセルの色により、どちらの矩形が上になっていて、どの程度透けて見えるかが決まります。重なるオブジェクトで共有されているピクセルをどのような色でレンダリングするか決める処理を、「重ね合わせ処理」と呼びます。

Java 2D の合成処理モデルの基礎になるのは、CompositeCompositeContext という 2 つのインタフェースです。

使う合成のスタイルを指定するには、setComposite メソッドを呼び出して、Graphics2D コンテキストに AlphaComposite オブジェクトを追加します。Composite インタフェースの実装である AlphaComposite では、さまざまな合成スタイルがサポートされています。このクラスのインスタンスは、既存の色と新しい色を混合する方法を記述した合成の規則を具体的に表しています。

AlphaComposite クラスで使われるもっとも一般的な重ね合わせ規則の 1 つは SRC_OVER で、これは、新しい色 (ソース色) を既存の色 (デスティネーション色) の上に混合するように指定するものです。

AlphaComposite の合成規則
説明
CLEAR
クリア
 
DEST_IN
デスティネーションが内側
 
DEST_OUT
デスティネーションが外側
 
DEST_OVER
デスティネーションが上
 
SRC
ソース
 
SRC_IN
ソースが内側
 
SRC_OUT
ソースが外側
 
SRC_OVER
ソースが上
 

2.2.7.1 透明度の管理

色の「アルファ」値は透明度の単位で、色を重ねたときに前にレンダリングされている色がどの程度遮られるかを、パーセントで示します。 不透明な色 (alpha=1.0) は下になっている色をまったく通さず、透明な色 (alpha=0.0) は下の色を完全に通します。

テキストと Shape のレンダリングでは、アルファ値は Graphics2D コンテキストの Paint 属性から導出されます。Shape とテキストが平滑化される場合、Graphics2D コンテキストの Paint 属性から得られるアルファ値は、ラスタ化されたパスからのピクセルカバレージ情報と結合されます。イメージは独自のアルファ情報を保持しています。 詳細については、「透明度とイメージ」を参照してください。

AlphaComposite オブジェクトを作成する際に、アルファ値を追加指定できます。この AlphaComposite オブジェクトを Graphics2D コンテキストに追加すると、追加したアルファ値により、レンダリングされるグラフィックオブジェクトの透明度が大きくなります。 つまり、各グラフィックオブジェクトのアルファ値に、AlphaComposite のアルファ値が掛けられます。

2.2.7.2 透明度とイメージ

イメージには、イメージ内の各ピクセルに対する透明度の情報を持たせることができます。「アルファチャネル」と呼ばれるこの情報は、イメージと既存の描画結果を混合するために、Graphics2D コンテキストの Composite オブジェクトと組み合わせて使われます。

たとえば、図 2-6 は、異なる透明度情報を持つ 3 種類のイメージです。どの場合も、イメージは青い矩形に重ねて表示されます。この例では、Graphics2D コンテキストは、合成操作として SRC_OVER を使う AlphaComposite オブジェクトを含んでいるものとします。

次の文で、このグラフィックスを説明しています。

図 2-6 透明度とイメージ

最初のイメージでは、すべてのピクセルが完全に不透明 (犬の体) または完全に透明 (背景) になっています。このような効果は、Web ページでよく使われます。2 番目のイメージでは、犬の体の全ピクセルを不透明ではない一定のアルファ値でレンダリングすることにより、青い背景が透けて見えます。3 番目のイメージでは、犬の顔の周囲のピクセルは完全に不透明 (アルファ = 1.0) ですが、顔から離れるに従って、ピクセルのアルファ値は徐々に小さくなっています。

2.3 Graphics2D コンテキストの設定

レンダリングのための Graphics2D コンテキストを構成するには、Graphics2D の設定 (set) メソッドを使って、RenderingHintsStrokePaint、クリッピングパス、CompositeTransform などの属性を指定します。

2.3.1 レンダリングヒントの設定

RenderingHints オブジェクトは、オブジェクトをレンダリングする方法に関する設定をすべてカプセル化しています。Graphics2D コンテキストにレンダリングヒントを設定するには、RenderingHints オブジェクトを生成し、Graphics2D.setRenderingHints にそれを渡します。

レンダリングモードの変更をサポートしていないプラットフォームもあるので、レンダリングヒントを設定しても、特定のレンダリングアルゴリズムの使用が保証されるわけではありません。

次の例では、平滑化を有効にし、レンダリングのプリファレンスを quality に設定しています。

qualityHints = new               RenderingHints(RenderingHints.KEY_ANTIALIASING,               RenderingHints.VALUE_ANTIALIAS_ON); 
qualityHints.put(RenderingHints.KEY_RENDERING,               RenderingHints.VALUE_RENDER_QUALITY); 
g2.setRenderingHints(qualityHints); 

2.3.2 ストローク属性の指定

BasicStroke では、Shape の境界線に適用される特性が定義されています。 これには、線の幅と破線パターン、線のセグメントの接続方法、および線端に適用される形状が含まれます。Graphics2D コンテキストにストローク属性を設定するには、BasicStroke オブジェクトを生成し、それを setStroke メソッドに渡します。

2.3.2.1 ストロークの幅の設定

ストロークの幅を設定するには、目的の幅を指定して BasicStroke オブジェクトを生成し、setStroke メソッドを呼び出します。

次の例では、ストロークの幅は 12 ポイントに設定し、接続と線端の形状にはデフォルトの設定を使っています。

wideStroke = new BasicStroke(12.0f); 
g2.setStroke(wideStroke); 

2.3.2.2 接続スタイルと線端スタイルの指定

接続スタイルと線端スタイルを設定するには、目的の属性を指定して BasicStroke オブジェクトを生成します。

次の例では、ストロークの幅は 12 ポイントに設定し、接続部と線端の形状には、デフォルトの設定ではなく、丸みを付けたスタイルを指定しています。

roundStroke = new BasicStroke(4.0f, BasicStroke.CAP_ROUND,              BasicStroke.JOIN_ROUND); 
g2.setStroke(roundStroke); 

2.3.2.3 破線パターンの設定

BasicStroke オブジェクトでは、複雑な破線パターンを簡単に定義できます。そのためには、BasicStroke オブジェクトを作るときに、破線パターンを制御する 2 つのパラメータを指定します。

次の例では、2 種類の破線パターンが線に適用されています。第 1 のパターンでは、ダッシュのサイズとダッシュ間の空白部のサイズは一定です。第 2 の破線パターンはさらに複雑で、6 つの要素を持つ配列を使って、破線パターンが定義されています。

float dash1[] = {10.0f}; 
BasicStroke bs = new BasicStroke(5.0f, BasicStroke.CAP_BUTT,  
                 BasicStroke.JOIN_MITER, 10.0f, dash1, 0.0f); 
g2.setStroke(bs); 
Line2D line = new Line2D.Float(20.0f, 10.0f, 100.0f, 10.0f); 
g2.draw(line); 
 
float[] dash2 = {6.0f, 4.0f, 2.0f, 4.0f, 2.0f, 4.0f}; 
bs = new BasicStroke(5.0f, BasicStroke.CAP_BUTT,  
     BasicStroke.JOIN_MITER, 10.0f, dash2, 0.0f); 
g2.setStroke(bs); 
g2.draw(line); 

どちらの破線パターンも破線のオフセットは 0 で、破線の描画は破線パターンの先頭から始まっています。この 2 種類の破線パターンを図 2-7 に示します。

前の文で、このグラフィックスを説明しています。

図 2-7 破線パターン

2.3.3 塗りつぶし属性の指定

Graphics2D コンテキストの Paint 属性により、テキストと Shapes のレンダリング時に使われる塗りつぶしの色とパターンが決まります。

2.3.3.1 グラデーションを使った Shape の塗りつぶし

GradientPaint クラスは、ある色から別の色へのグラデーションで図形を塗りつぶす簡単な方法を提供しています。GradientPaint を作るときに、開始の位置と色および終了の位置と色を指定します。塗りつぶしの色は、2 つの位置を結ぶ線に沿って、1 つの色から別の色まで、一定の比率で段階的に変化します。図 2-8 は、グラデーションを使った塗りつぶしの例です。

前の文で、このグラフィックスを説明しています。

図 2-8 グラデーションによる塗りつぶしの作成

図 2-8 の第 3 の星型では、開始位置と終了位置が両方とも図形の内部にあります。グラデーションの向きを示す線を P1 より先に延長した部分にある点は、すべて開始位置の色で描画されて、グラデーション線を P2 より先に延長した部分にある点は、すべて終了位置の色で描画されます。

ある色から別の色へのグラデーションで図形を塗りつぶす場合は、次の手順で行います。

  1. GradientPaint オブジェクトを生成する
  2. Graphics2D.setPaint を呼び出す
  3. Shape を作成する
  4. Graphics2D.fill(shape) を呼び出す

次の例では、青と緑のグラデーションで矩形を塗りつぶしています。

GradientPaint gp = new GradientPaint(50.0f, 50.0f, Color.blue 
                   50.0f, 250.0f, Color.green); 
g2.setPaint(gp); 
g2.fillRect(50, 50, 200, 200); 

2.3.3.2 テクスチャを使った Shape の塗りつぶし

TexturePaint クラスでは、繰り返しパターンで図形を塗りつぶす簡単な方法が提供されています。TexturePaint を作るときは、パターンとして使う BufferedImage を指定します。コンストラクタには、パターンの繰り返し単位を定義する矩形も渡します。 図 2-9 はこの塗りつぶしの例です。

前の文で、このグラフィックスを説明しています。

図 2-9 テクスチャを使った塗りつぶしの作成

テクスチャによる図形の塗りつぶしは、次の手順で行います。

  1. TexturePaint オブジェクトを生成する
  2. Graphics2D.setPaint を呼び出す
  3. Shape を作成する
  4. Graphics2D.fill(shape) を呼び出す

次の例では、バッファリングされたイメージから作られた簡単なテクスチャで、矩形を塗りつぶしています。

// Create a buffered image texture patch of size 5x5 
BufferedImage bi = new BufferedImage(5, 5,    
                       BufferedImage.TYPE_INT_RGB); 
Graphics2D big = bi.createGraphics(); 
// Render into the BufferedImage graphics to create the texture 
big.setColor(Color.green); 
big.fillRect(0,0,5,5); 
big.setColor(Color.lightGray); 
big.fillOval(0,0,5,5); 
 
// Create a texture paint from the buffered image 
Rectangle r = new Rectangle(0,0,5,5); 
TexturePaint tp = new TexturePaint(bi,r,TexturePaint.NEAREST_NEIGHBOR); 
 
// Add the texture paint to the graphics context. 
g2.setPaint(tp); 
 
// Create and render a rectangle filled with the texture. 
g2.fillRect(0,0,200,200); 
} 

2.3.4 クリッピングパスの設定

クリッピングパスの定義は、次の手順で行います。

  1. レンダリングする領域を示す Shape を作成する
  2. Graphics2D.setClip を呼び出し、作成した ShapeGraphics2D コンテキストのクリッピングパスとして設定する

クリッピングパスの縮小は、次の手順で行います。

  1. 現在のクリッピングパスと共通部分を持つ Shape を作成する
  2. clip を呼び出し、クリッピングパスを、現在のクリッピングパスと新しい Shape の共通部分に変更する

次の例では、まず楕円形でクリッピングパスを作成し、次に clip を呼び出してクリッピングパスを変更しています。

public void paint(Graphics g) { 
  Graphics2D g2 = (Graphics2D) g; 
 
// The width and height of the canvas 
  int w = getSize().width; 
  int h = getSize().height; 
  // Create an ellipse and use it as the clipping path 
  Ellipse2D e = new Ellipse2D.Float(w/4.0f,h/4.0f, 
                                    w/2.0f,h/2.0f); 
  g2.setClip(e); 
 
  // Fill the canvas. Only the area within the clip is rendered 
  g2.setColor(Color.cyan); 
  g2.fillRect(0,0,w,h); 
 
  // Change the clipping path, setting it to the intersection of  
  // the current clip and a new rectangle. 
  Rectangle r = new Rectangle(w/4+10,h/4+10,w/2-20,h/2-20); 
  g2.clip(r); 
 
  // Fill the canvas. Only the area within the new clip  
  // is rendered 
  g2.setColor(Color.magenta); 
  g2.fillRect(0,0,w,h); 
} 

2.3.5 Graphics2D の変換の設定

Shape、テキスト文字列、または Image を変換するには、レンダリングする前に、Graphics2D コンテキストの変換パイプラインに新しい AffineTransform を追加します。グラフィックオブジェクトをレンダリングすると、変換が適用されます。

たとえば、次は、矩形を 45 度回転させて描画する手順です。

  1. 変換を実行する前に、現在の Graphics2D 変換を取得する。変換をグラフィックスコンテキストに追加する前に、Graphics2D に対して getTransform を常に呼び出す (グラフィックスコンテキストが、ウィンドウ内で Swing コンポーネントや軽量コンポーネントの位置指定など、他の理由で必要な変換を保持する場合があるため)
  2. AffineTransform.getRotateInstance を呼び出し、回転変換を取得する
  3. Graphics2D.transform を呼び出し、変換パイプラインに新しい変換を追加するsetTransform を実行すると、グラフィックスコンテキスト内の現在の変換が上書きされてしまうため、新しい座標変換を追加するのに setTransform は使用しない
  4. Rectangle2D.Float オブジェクトを生成する
  5. Graphics2D.draw を呼び出し、矩形をレンダリングする
  6. 変換した矩形の描画後に、元の変換を使って setTransform を呼び出すことにより、Graphics2D の変換をステップ 1 で保存した元の変換に戻す

次の例では、矩形をレンダリングするときに、AffineTransform のインスタンスを使って矩形を 45 度回転させています。

AffineTransform aT = g2.getTransform();Rectangle2D rect = new Rectangle2D.Float(1.0,1.0,2.0,3.0); 
AffineTransform rotate45 =    
  AffineTransform.getRotateInstance(Math.PI/4.0,0.0,0.0) 
g2.transform(rotate45); 
g2.draw(rect);g2.setTransform(aT); 

次の例では、AffineTransform を使って、中心点を軸にテキスト文字列を回転させています。

// Define the rendering transform 
AffineTransform at = new AffineTransform(); 
// Apply a translation transform to make room for the 
// rotated text. 
at.setToTranslation(400.0, 400.0); 
g2.transform(at); 
// Create a rotation transform to rotate the text 
at.setToRotation(Math.PI / 2.0); 
// Render four copies of the string “Java” at 90 degree angles 
for (int i = 0; i < 4; i++) { 
    g2.drawString(“Java”, 0.0f, 0.0f); 
    g2.transform(at); 
} 

イメージも同じ方法で変換できます。 レンダリングされるグラフィックオブジェクトの種類に関係なく、レンダリングの際には Graphics2D コンテキストの変換が適用されます。

Graphics2D コンテキストで定義されている変換を変更しないで、イメージに変換を適用するには、drawImage メソッドに AffineTransform を渡します。

AffineTransform rotate45 =    
  AffineTransform.getRotateInstance(Math.PI/4.0,0.0,0.0) 
g2.drawImage(myImage, rotate45); 

Font に変換を適用して、見た目の異なる Font を作ることもできます。 詳細については、「フォント派生の作成」を参照してください。

2.3.6 重ね合わせのスタイルの指定

AlphaComposite は、あるオブジェクトが別のオブジェクトと重なるときの色のレンダリング方法を決める、合成規則をカプセル化しています。Graphics2D コンテキストに合成スタイルを指定するには、AlphaComposite を作成し、それを setComposite メソッドに渡します。もっとも一般的に使われる合成スタイルは SRC_OVER です。

2.3.6.1 合成規則 SRC_OVER の使用方法

SRC_OVER の合成規則は、デスティネーションピクセルの上にソースピクセルを合成するもので、共有されるピクセルはソースピクセルの色になります。たとえば、青い矩形をレンダリングしてから、それと一部が重なる赤い矩形をレンダリングした場合、重なり合う部分の色は赤になります。つまり、最後にレンダリングされたオブジェクトが、いちばん上に表示されます。

次は、合成規則 SRC_OVER の使用方法です。

  1. 規則に SRC_OVER を指定して getInstance メソッドを呼び出し、AlphaComposite オブジェクトを生成する
  2. AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER); 
    
  3. setComposite メソッドを呼び出し、Graphics2D コンテキストに AlphaComposite オブジェクトを追加する

    g2.setComposite(ac);

合成オブジェクトがいったん設定されると、重なりを持つオブジェクトは指定されている重ね合わせ規則に従ってレンダリングされます。

2.3.6.2 合成オブジェクトの透明度の変更

AlphaComposite を使うと、アルファ値の定数を追加して指定できます。 この値は、ソースピクセルのアルファ値に掛けられて、ソースピクセルの透明度が高くなります。

たとえば、50% の透過率でソースオブジェクトをレンダリングする AlphaComposite オブジェクトを作るには、アルファに .5 を指定します。

AlphaComposite ac = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, .5f); 

次の例では、ソースを上に重ねるアルファ合成オブジェクトをアルファ値 .5 で作成し、グラフィックスコンテキストに追加しています。その結果、それ以降の図形は 50% の透明度でレンダリングされます。

public void paint(Graphics g) { 
  Graphics2D g2 = (Graphics2D) g; 
 
  g2.setColor(Color.red); 
  g2.translate(100,50); 
  // radians=degree * pie / 180 
  g2.rotate((45*java.lang.Math.PI)/180);  
  g2.fillRect(0,0,100,100); 
  g2.setTransform(new AffineTransform());  // set to identity 
  // Create a new alpha composite 
  AlphaComposite ac = 
      AlphaComposite.getInstance(AlphaComposite.SRC_OVER,0.5f); 
  g2.setComposite(ac); 
  g2.setColor(Color.green); 
  g2.fillRect(50,0,100,100); 
  g2.setColor(Color.blue); 
  g2.fillRect(125,75,100,100); 
  g2.setColor(Color.yellow); 
  g2.fillRect(50,125,100,100); 
  g2.setColor(Color.pink); 
  g2.fillRect(-25,75,100,100); 
} 

2.4 グラフィックスプリミティブのレンダリング

Graphics2D では、Shape、テキスト文字列、および Image のレンダリング用に、次のメソッドが提供されています。

図形のストロークを描画して塗りつぶすには、draw メソッドと fill メソッドの両方を呼び出す必要があります。

Graphics2D は、drawOval や、fillRect など、旧バージョンの JDK で提供されていた描画用と塗りつぶし用のメソッドもサポートしています。

2.4.1 Shape の描画

Shape の輪郭線は、Graphics2D.draw メソッドでレンダリングできます。旧バージョンの JDK で提供されていた次の描画メソッドもサポートされています。drawLinedrawRectdrawRoundRectdrawOvaldrawArcdrawPolylinedrawPolygondraw3DRect

Shape を描画すると、Graphics2D コンテキストの Stroke オブジェクトでパスが描画されます。詳細については、「ストローク属性」を参照してください。Graphics2D コンテキストに適切な BasicStroke オブジェクトを設定することで、どのような幅とパターンの線でも描画できます。BasicStroke オブジェクトでは、線の先端部と接合部の属性も定義されています。

図形の輪郭線は、次の手順でレンダリングします。

  1. BasicStroke オブジェクトを生成する
  2. Graphics2D.setStroke を呼び出す
  3. Shape を作成する
  4. Graphics2D.draw(shape) を呼び出す

次の例では、GeneralPath オブジェクトを使って星型を定義し、BasicStroke オブジェクトを Graphics2D コンテキストに追加して、星型の輪郭線の幅と接合部の属性を定義しています。

public void paint(Graphics g) { 
  Graphics2D g2 = (Graphics2D) g; 
 
  // create and set the stroke 
  g2.setStroke(new BasicStroke(4.0f)); 
 
  // Create a star using a general path object 
  GeneralPath p = new GeneralPath(GeneralPath.NON_ZERO); 
  p.moveTo(- 100.0f, - 25.0f); 
  p.lineTo(+ 100.0f, - 25.0f); 
  p.lineTo(- 50.0f, + 100.0f); 
  p.lineTo(+ 0.0f, - 100.0f); 
  p.lineTo(+ 50.0f, + 100.0f); 
  p.closePath(); 
 
  // translate origin towards center of canvas 
  g2.translate(100.0f, 100.0f); 
   
  // render the star's path 
  g2.draw(p); 
} 

2.4.2 Shape の塗りつぶし

Graphics2D.fill メソッドを使って、任意の Shape を塗りつぶすことができます。Shape を塗りつぶすと、そのパスの内側の領域が、ColorTexturePaintGradientPaint など、Graphics2D コンテキストの現在の Paint 属性でレンダリングされます。

旧バージョンの JDK で提供されていた次の塗りつぶしメソッドもサポートされています。fillRectfill3DRectfillRoundRectfillOvalfillArcfillPolygonclearRect

Shape を塗りつぶすには、次のようにします。

  1. Graphics2D.setColor または Graphics2D.setPaint を使って、グラフィックスコンテキストの塗りつぶしの色またはパターンを設定する
  2. Shape を作成する
  3. Graphics2D.fill を呼び出し、Shape をレンダリングする

次の例では、setColor を呼び出し、緑色での塗りつぶしを Rectangle2D に定義しています。

public void paint(Graphics g) { 
  Graphics2D g2 = (Graphics2D) g; 
 
  g2.setPaint(Color.green); 
  Rectangle2D r2 = new Rectangle2D.Float(25,25,150,150); 
 
   g2.fill(r2); 
} 

2.4.3 テキストのレンダリング

テキスト文字列をレンダリングするには、Graphics2D.drawString を呼び出して、レンダリングする文字列を渡します。テキストのレンダリングとフォントの選択についての詳細は、「フォントとテキストレイアウト」を参照してください。

2.4.4 イメージのレンダリング

Image をレンダリングするには、Image を作成し、Graphics2D.drawImage を呼び出します。イメージの処理とレンダリングの詳細については、「イメージング」を参照してください。

2.5 独自の合成規則の定義

Composite インタフェースと CompositeContext インタフェースを実装することで、まったく新しい種類の合成操作を作成できます。Composite オブジェクトでは、実際に状態を保持して合成の作業を行う CompositeContext オブジェクトが提供されます。1 つの Composite オブジェクトから複数の CompositeContext オブジェクトを生成し、マルチスレッド環境の異なる状態を維持できます。

2.6 マルチスクリーン環境でのレンダリング

JavaTM 2 SDK のバージョン 1.3 のリリースにより、Java 2DTM API は、ネイティブプラットフォームで構成可能な 3 つの異なるマルチスクリーン構成をサポートします。

Java 2D API を利用することにより、GraphicsConfiguration を使って FrameJFrameWindow、または JWindow オブジェクトを作成し、レンダリング用の画面デバイスをターゲットにできます。

これら 3 つの設定で、各画面デバイスは GraphicsDevice で表されます。GraphicsDevice は、関連付けられた複数の GraphicsConfiguration オブジェクトを保持できます。

仮想デバイスの構成に複数の画面が使用される場合、物理画面外に存在する仮想座標系が、仮想デバイスの表現に使用されます。マルチスクリーン構成での各 GraphicsConfiguration の座標は、仮想座標系に対する相対座標になります。この環境下で 1 つの画面がメイン画面として認識され、仮想座標系の (0, 0) に配置されます。図 2-10 に示すように、メイン画面の位置によっては、仮想デバイスが負の座標になる場合があります。

仮想デバイス環境の例

図 2-10 仮想デバイス環境の例

Window または Frame が複数の物理画面にまたがる現在の環境が仮想デバイス環境であるかどうかを判別するには、システムの GraphicsConfiguration ごとに getBounds を呼び出して、原点が (0, 0) 以外に位置しているかどうかを調べます。GraphicsConfigurationgetBounds メソッドは、仮想座標系内の Rectangle を返します。このため、原点が (0, 0) 以外の場合には、仮想デバイス環境です。

仮想デバイス環境では、GraphicsConfiguration オブジェクトの座標は仮想座標系に対する相対座標になります。このため、Frame または WindowsetLocation メソッドを呼び出す場合には、仮想座標を使用する必要があります。たとえば、以下のコードは、GraphicsConfiguration の境界を取得し、その境界を使って、対応する GraphicsConfiguration の物理画面の原点に対し (10, 10) の位置に Frame を配置します。

Frame f = new Frame(GraphicsConfiguration gc); 
Rectangle bounds = gc.getBounds(); 
f.setLocation(10 + bounds.x, 10 + bounds.y); 
 

GraphicsConfiguration の境界が考慮されていない場合、Frame はメインの物理画面の (10, 10) に表示されます。この位置は、指定された GraphicsConfiguration の物理画面とは異なる場合があります。

仮想デバイスの境界判定に、getBounds メソッドを使用することもできます。システムの各 GraphicsConfiguration に対し、getBounds を呼び出します。仮想デバイスの境界を決定するには、すべての境界の和集合を計算します。以下の例に、その具体的な方法を示します。

Rectangle virtualBounds = new Rectangle(); 
GraphicsEnvironment ge = 
   GraphicsEnvironment.getLocalGraphicsEnvironment(); 
GraphicsDevice[] gs = ge.getScreenDevices(); 
for (int j = 0; j < gs.length; j++) { 
   GraphicsDevice gd = gs[j]; 
   GraphicsConfiguration[] gc = gd.getConfigurations(); 
   for (int i = 0; i < gc.length; i++) { 
      virtualBounds = virtualBounds.union(gc[i].getBounds()); 
   } 
} 
 

次のアプレットは、GraphicsEnvironment の各 GraphicsDeviceGraphicsConfiguration を使って JFrame を作成します。各 JFrame は、赤、緑、青のストライプセット、画面番号、GraphicsConfigurationGraphicsConfiguration 番号および境界を表示します。このコード例は、JavaTM 2 SDK バージョン 1.3 以降で動作します。

 
import java.applet.Applet; 
import java.awt.*; 
import javax.swing.*; 
 
public class MultiFrameApplet extends Applet { 
     
    public MultiFrameApplet() { 
        main(null); 
    } 
 
    public static void main(String[] argv) { 
        GraphicsEnvironment ge =  
           GraphicsEnvironment.getLocalGraphicsEnvironment(); 
        GraphicsDevice[] gs = ge.getScreenDevices(); 
        for (int j = 0; j < gs.length; j++) { 
          GraphicsDevice gd = gs[j]; 
          GraphicsConfiguration[] gc =  
             gd.getConfigurations(); 
             for (int i=0; i < gc.length; i++) { 
               JFrame f =  
                  new JFrame(gs[j].getDefaultConfiguration()); 
               GCCanvas c = new GCCanvas(gc[i]); 
               Rectangle gcBounds = gc[i].getBounds(); 
               int xoffs = gcBounds.x; 
               int yoffs = gcBounds.y; 
               f.getContentPane().add(c); 
               f.setTitle("Screen# "+Integer.toString(j)+",  
                  GC# "+Integer.toString(i)); 
               f.setSize(300, 150); 
               f.setLocation((i*50)+xoffs, (i*60)+yoffs); 
               f.show(); 
             } 
        } 
    } 
} 
 
class GCCanvas extends Canvas { 
 
    GraphicsConfiguration gc; 
    Rectangle bounds; 
 
    public GCCanvas(GraphicsConfiguration gc) { 
        super(gc); 
        this.gc = gc; 
        bounds = gc.getBounds(); 
    } 
 
    public Dimension getPreferredSize() { 
        return new Dimension(300, 150); 
    } 
 
    public void paint(Graphics g) { 
        g.setColor(Color.red); 
        g.fillRect(0, 0, 100, 150); 
        g.setColor(Color.green); 
        g.fillRect(100, 0, 100, 150); 
        g.setColor(Color.blue); 
        g.fillRect(200, 0, 100, 150); 
        g.setColor(Color.black); 
        g.drawString("ScreenSize="+ 
           Integer.toString(bounds.width)+ 
           "X"+ Integer.toString(bounds.height), 10, 15); 
        g.drawString(gc.toString(), 10, 30); 
    } 
} 
 

 


目次 | 前の項目 | 次の項目 JavaTM 2D API プログラマーズガイド
JavaTM 2 SDK, Standard Edition, 1.4 Version