13 Java 2D
この章では、Java 2D APIで発生する可能性のあるもっとも一般的な問題のいくつかをトラブルシューティングするための情報とガイダンスを提供します。
この章の構成は、次のとおりです。
Java 2Dプロパティのサマリーについては、「Java 2Dのプロパティ」を参照してください。
一般的なパフォーマンス問題
レンダリング・パフォーマンスの低下には様々な原因が考えられます。次のトピックでは、アプリケーションのレンダリング・パフォーマンスの低下の原因を特定し、ソフトウェアのみのレンダリング・パフォーマンスを改善するためのアプローチを提案します。
このトピックでは、次の項目について説明します。
ハードウェア高速化レンダリング・プリミティブ
パフォーマンス問題の原因についての理解を深めるため、ハードウェア高速化の意味について考えてます。
一般に、ハードウェア高速化レンダリングは2つのカテゴリに分けられます。
-
「高速化対象」の宛先へのハードウェア高速化レンダリング。ハードウェア高速化が可能なレンダリングの宛先の例として、
VolatileImage、画面、およびBufferStrategyがあげられます。宛先が高速化対象である場合、表面に対するレンダリングはビデオ・ハードウェアによって実行される可能性があります。したがって、ユーザーがdrawRect呼出しを発行すると、Java 2Dはその呼出しを、ベースとなるネイティブAPI (GDI、DirectDraw、Direct3D、OpenGL、X11など)にリダイレクトし、そこでハードウェアを使用して操作が実行されます。 -
高速化メモリー(ビデオ・メモリーまたはピックスマップ)へのイメージのキャッシング。これにより、それらのイメージを別の高速化対象表面に非常に高速でコピーできるようになります。これらのイメージは管理対象イメージと呼ばれます。
理想的には、高速化対象表面で実行される操作はすべて、ハードウェアで高速化されます。この場合、アプリケーションはプラットフォームによって提供されるメリットを最大限に享受できます。
残念ながら多くの場合、デフォルト・パイプラインはレンダリングにハードウェアを使用できません。その原因は、パイプラインの制限やベースとなるネイティブAPIにあります。たとえば、ほとんどのXサーバーは、アンチエイリアス・プリミティブのレンダリングやアルファ合成をサポートしません。
パフォーマンス問題の原因の1つは、実行される操作がハードウェア高速化されない場合にあります。宛先表面が高速化される場合でも、その一部のプリミティブが高速化されない可能性があります。
ハードウェア高速化が使用されていない場合を検出する方法を知ることが重要です。それを知れば、パフォーマンスの改善が容易になる可能性があります。
非高速化レンダリングの検出および回避のためのプリミティブ・トレース
高速化されないレンダリングを検出するには、Java 2Dプリミティブ・トレースを使用できます。
アプリケーションの実行時に-Dsun.java2d.trace=countを指定します。アプリケーションが終了すると、プリミティブのリストとそれらのカウントがコンソールに出力されます。
MaskBlitプリミティブや任意のGeneral*プリミティブが表示された場合、それは通常、レンダリングの一部がソフトウェア・ループによって処理されていることを意味します。Linux上で、半透明のBufferedImageに対してdrawImageを実行してVolatileImageに書き込む場合の出力を、次に示します。
sun.java2d.loops.Blit$GeneralMaskBlit::Blit(IntArgb, SrcOverNoEa, "Integer BGR Pixmap")sun.java2d.loops.MaskBlit::MaskBlit(IntArgb, SrcOver, IntBgr)
ノート:
このトレースのほとんどはLinuxで行われたものです。使用しているプラットフォームや構成によっては多少の違いが生じる可能性があります。ソフトウェアのみのレンダリングのパフォーマンスの改善
アプリケーションが(BufferedImageへのレンダリングのみを行うかデフォルト・パイプラインを非高速化パイプラインに変更したために)ソフトウェア専用レンダリングに依存している場合、あるいはアプリケーションが混在されたレンダリングを行う場合でも、次に示す特定のアプローチによってパフォーマンスが改善します。
-
最適化されたサポートとイメージの種類または操作:
プラットフォーム全体のサイズ制約のために、あるイメージ形式を別の形式に変換するための最適化されたルーチンは、Java 2Dには限られた数しか含まれていません。最適化された直接ループが見つからない状況では、Java 2Dは中間イメージ形式(
IntArgb)を介して変換します。この場合、パフォーマンスが低下します。Java 2Dプリミティブ・トレースを使用すればそのような状況を検出できます。
各
drawImage呼出しに対して2つのプリミティブが存在します。1つ目はイメージをソース形式から中間IntArgb形式に変換し、2つ目は中間IntArgbから変換先の形式に変換します。そのような状況を回避する2つの方法を次に示します。
-
可能であれば別のイメージ形式を使用します。
-
イメージを、よりサポート・レベルの高い形式(
INT_RGBやINT_ARGBなど)の中間イメージに変換します。そうすれば、カスタム・イメージ形式からの変換が、コピーごとに発生する代わりに一度だけ発生するようになります。
-
-
透明と半透明:
できれば、完全な半透明(
INT_ARGBなど)のイメージではなく、1ビット透明(BITMASK)のイメージをスプライトとして使用することを検討してください。完全なアルファを持つイメージの処理では、CPUの負荷がより高くなります。
1ビット透明イメージを取得するには、GraphicsConfiguration.createCompatibleImage(w,h, Transparency.BITMASK)の呼出しを使用します。
テキスト関連の問題
この項では、テキストのレンダリングに関連して発生する可能性がある問題とクラッシュ、およびそのような問題を克服するためのヒントについて説明します。
この項には次のサブセクションが含まれます:
フォント・ロードのトレース
-Dsun.java2d.debugfonts=trueプロパティを設定すると、Java 2Dによってロードされたフォントに関する情報が生成されます。Java 2Dが検出したフォントを確認し、使用するフォントを推測し、拒否するフォントに関する情報を確認できます。このプロパティによって、次のような出力が生成されます:
INFO: Registered file C:\WINDOWS\Fonts\WINGDING.TTF as font ** TrueType Font: Family=Wingdings
Name=Wingdings style=0 fileName=C:\WINDOWS\Fonts\WINGDING.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Symbol, Font Symbol rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\SYMBOL.TTF as font ** TrueType Font: Family=Symbol
Name=Symbol style=0 fileName=C:\WINDOWS\Fonts\SYMBOL.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager findFont2D
INFO: Search for font: Dialog
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file ARIALBD.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Arial, Font Arial Bold rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\ARIALBD.TTF as font ** TrueType Font: Family=Arial
Name=Arial Bold style=1 fileName=C:\WINDOWS\Fonts\ARIALBD.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file WINGDING.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager findFont2D
INFO: Search for font: Dialog
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file ARIAL.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager addToFontList
INFO: Add to Family Arial, Font Arial rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager registerFontFile
INFO: Registered file C:\WINDOWS\Fonts\ARIAL.TTF as font ** TrueType Font: Family=Arial
Name=Arial style=0 fileName=C:\WINDOWS\Fonts\ARIAL.TTF rank=2
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file WINGDING.TTF
Aug 16, 2006 10:59:06 PM sun.font.FontManager initialiseDeferredFont
INFO: Opening deferred font file SYMBOL.TTF
テキストの外観の違い
Javaアプリケーションとネイティブ・アプリケーションのテキスト表示の違いは、使用されるフォント・ラスタライザが異なることが原因である可能性があります。Javaアプリケーションは通常、ネイティブ・アプリケーションが使用するのと同じ、オペレーティング・システムのフォント・ラスタライザを使用します。ただし、Javaアプリケーションでは、オペレーティング・システムにインストールまたは含まれている、フォント・レンダリング用ソフトウェア・ライブラリであるFreeTypeが使用される場合があります。たとえば、FreeTypeは、Windowsではグレースケール・テキストに、macOSではmacOSフォント・ラスタライザでサポートされていないType 1フォントに使用される場合があります。ただし、Windowsには複数のフォント・ラスタライザがあることに注意してください。その結果、ネイティブ・アプリケーションによってテキスト・レンダリングが異なる場合があります。さらに、すべてのプラットフォームでプラットフォームのラスタライズにある程度の構成可能性があり、テキストの外観にわずかな違いが生じる可能性があります。
その他の相違の原因としては次のようなものが挙げられます:
- サブピクセル位置決めが使用されているかどうか。これはグリフの正確な位置決めに影響します。「java.awt.RenderingHints.KEY_FRACTIONALMETRICS」を参照してください。
- Linuxでは、Swingは異なるアンチエイリアシング設定を選択する場合があります。
この動作には、考えられる理由がいくつかあります。
- リモートX11接続経由のアンチエイリアスは、パフォーマンス上の理由により、デフォルトでは有効になりません。
-
埋込みビットマップを使用するCJKフォントは、サブピクセル・テキストの代わりにビットマップを使ってレンダリングされる可能性があります。
-
サポートされていないデスクトップの中には、そのフォント・スムージング設定が適切に報告されないものがあります。たとえば、KDEはサポートされていませんが、たいていは動作するはずです。しかし、なんらかの問題によってJDKはその設定を検出できないようです。
Java言語のフォントのサイズは常に72 dpiで表現されます。ネイティブOSでは別の画面dpiを使用できるため、調整が必要になります。対応するJavaフォント・サイズを計算するには、Toolkit.getScreenResolution()を72で割り、その結果にネイティブ・フォントのサイズを掛けます。
WindowsルックアンドフィールやLinuxオペレーティング・システム用のGTKルックアンドフィールなど、すべてのネイティブSwingルックアンドフィールで、Swingコンポーネントによりこの調整が自動的に実行されます。
Windows以外のオペレーティング・システムでは通常、Type1フォントではなくTrueTypeフォントの使用をお薦めします。フォント・タイプを知る最も簡単な方法はファイル拡張子を調べることです。pfaおよびpfbという拡張子はType1フォント、ttf、ttcおよびtteという拡張子はTrueTypeフォントを表します。
フォント・メトリックス
テキストの境界が予想していたものと異なることに気づいた場合、境界の適切な計算方法を使用していることを確認してください。たとえば、FontMetricsから得られる高さは特定のテキストに固有のものではなく、stringWidthは論理的な有効幅を示し、幅と同じものではありません。詳細は、Java 2D FAQのフォントおよびテキストに関する質問を参照してください。