アンチエイリアス
図1 アンチエイリアス

「Swingの文字は汚い」と多くの方が思っているのではないでしょうか。では,なぜSwingの文字は汚い感じがするのでしょう。

その理由の一つがアンチエイリアスです。

アンチエイリアスは一種のぼかし処理です。例えば,線を描画する場合,ピクセルの大きさが有限であるため,ギザギザ(ジャギー)になります(これがエイリアスです)。このジャギーを解消させるのがアンチエイリアスです。具体的には,色の中心からの距離に応じて色を薄くするという処理を行います。

例えば,図1では,上の線はアンチエイリアス処理を行っておらず,下はアンチエイリアス処理を行っています。拡大すると,アンチエイリアスをしている線は,境界がぼやけています。

このように,アンチエイリアスを使用すると描画がなめらかになります。特に文字の描画では大きい効果が得られます。

アンチエイリアスはJ2SE 1.2のころから使用できました。ところが,Swingのコンポーネントでの文字描画ではアンチエイリアスを適用できませんでした注1

Java SE 6になって,ようやくSwingで文字描画にアンチエイリアスが使用されるようになりました。

この効果をさっそくサンプルで確かめてみましょう。

サンプルのソース:AntialiasFontSample1.java

このサンプルは,文字の大きさを変化させて表示を行っているだけです。

JPanel panel = new JPanel();
panel.setLayout(new BoxLayout(panel, BoxLayout.Y_AXIS));

for (int i = 12; i <= 32 ; i += 4) {
  Font font = new Font("SansSerif", Font.PLAIN, i);
  JLabel label = new JLabel(i + "pt: ABCあいう");
  label.setFont(font);

  panel.add(label);
}

Windowsの実行結果を図2,Linux(Fedora Core 5)での実行結果を図3に表示します。それぞれ右上が通常の表示で,それを2倍に拡大したものが左下の部分になります。Linuxはさざなみフォントを使用しています。

Windowsでの実行結果
図2 Windowsでの実行結果
Linuxでの実行結果
図3 Linuxでの実行結果

Windowsではある程度大きい文字にアンチエイリアスが適用されています。小さい文字にアンチエイリアスをかけると逆に見にくくなることがあるためです。Linuxでは小さい文字でもアンチエイリアスが適応されています。

皆さんも,自分のパソコンで試してみてください。もしかしたら,これらとは違う結果になっているかもしれません。

というのも,これらの実行結果は,今となってはめずらしいCRTディスプレイで出力したものだからです。図4は,同じサンプルをWindowsで液晶ディスプレイ(LCD)で出力したものです。ちょっとわかりにくいかもしれないので,こちらは4倍に拡大してあります。

Windowsでの実行結果(LCD)
図4 Windowsでの実行結果(LCD)

図4をよく見てみると,文字の色は黒なのに,文字の左側には赤,右側には青でぼかしがはいっています。

なぜ,もともとの色とは違う色でアンチエイリアスを適用するのでしょうか。それは,液晶の色の並び方が規則的であることを利用するためです。

液晶ではだいたいの場合,色の並びは左から赤,緑,青の順番で並んでいます。この色の並びを利用して,1ピクセルを構成する三つの色を分解して扱うのです。

例えば,左側の緑と青の部分は0にして赤だけセットすることにより,3色をまとめて扱うよりも細かくアンチエイリアスの制御を行うことができます。

このように,1ピクセルを構成する三つの色を分解したものをサブピクセルと呼びます。Windowsでは,サブピクセルを利用したアンチエイリアスをClearTypeと呼びます。

Java SE 6では,サブピクセルを利用したアンチエイリアスが可能になりました。このため,LCDでサンプルを動作させると,図4のように赤と青でアンチエイリアスされたのです。

LCDであっても上記のような表示にならない場合は,Clear Typeが有効になっていないと考えられます。

Windows XPのClearTypeの設定は,コントロールパネルの[画面]から行います。[デザイン]タブの[効果]ボタンをクリックすると,図5のようなダイアログが表示されます。「次の方法でスクリーン フォントの縁を滑らかにする(S)」では,[標準]が通常のアンチエイリアス,[ClearType]がClearTypeになります。

ClearTypeの設定
図5 ClearTypeの設定

Linuxはディストリビューションによって設定方法が異なります。Fedora Core 5の場合はタスクバーの[デスクトップ]-[設定]-[フォント]で行います(図6)。

サブピクセルアンチエイリアスの設定(Fedora Core5)
図6 サブピクセルアンチエイリアスの設定(Fedora Core5)

もし,システムの設定と異なる方法でアンチエイリアスを行いたい場合は,次のようにします。

>java -Dawt.useSystemAAFontSettings=on [クラス名]
	
awt.useSystemAAFontSettingsの取りうる値
  off      アンチエイリアスを行わない
  on       アンチエイリアスを行う
  gasp     小さい文字ではアンチエイリアスを行わない
  lcd      サブピクセルのアンチエイリアス
  lcd_hrgb サブピクセルのアンチエイリアス 横方向RGB
  lcd_hbgr サブピクセルのアンチエイリアス 横方向BGR
  lcd_vrgb サブピクセルのアンチエイリアス 縦方向RGB
  lcd_vbgr サブピクセルのアンチエイリアス 縦方向BGR
 

lcd_hrgb以下の四つは後で説明します。

アンチエイリアスな文字を描画する

さて,自作のコンポーネントではサブピクセルのアンチエイリアスはどのように行えばいいのでしょうか。

アンチエイリアスはjava.awt.RenderingHintsクラスで表します。Java SE 6ではこのRenderingHintsクラスにLCDのアンチエイリアスの定義が加わりました注2

サンプルのソース:AntialiasFontSample2.java

LCD用のアンチエイリアスの定義はVALUE_TEXT_ANTIALIAS_LCDで始まる4種類です。Hが頭に付いているのは水平方向に並んでいるもの,Vは垂直方向です。RGBとBGRは色の並び方の違いを表しています。

これらの値はawt.useSystemAAFontSettingsの値であるlcd_hrgb,lcd_hbgr,lcd_vrgb,lcd_bgrに相当します。

ヒントの設定には,Graphics2D#setRenderingHintメソッド,もしくは,複数のヒントをまとめて設定するGraphics2D#addRenderingHintsメソッドを使用します。

ヒントのキーはKEY_TEXT_ANTIALIASINGです。

public void paintComponent(Graphics g) {
  Graphics2D g2d = (Graphics2D)g;

  Font font = new Font("SansSerif", Font.PLAIN, 32);
  g2d.setFont(font);

  // HRGB
  g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                       RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HRGB);
  g2d.drawString("HRGB:" + text, 10, 40);

  // HBGR
  g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                       RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_HBGR);
  g2d.drawString("HBGR:" + text, 10, 80);

  // VRGB
  g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                       RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VRGB);
  g2d.drawString("VRGB:" + text, 10, 120);

  // VBGR
  g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING,
                       RenderingHints.VALUE_TEXT_ANTIALIAS_LCD_VBGR);
  g2d.drawString("VBGR:" + text, 10, 160);
}

実行してみると,先ほどの結果と同じように左に赤,右に青が出力されるのはHRBGだということがわかります(図7)。つまり,-Dawt.useSystemAAFontSettings=lcdとして実行したときには,常にHRGBになります。

実をいうと,Javaからはピクセルの色のパターンはわからないことがあるので,このような決め打ちになっているようです。

例えば,LCDを90度回転させて縦長の状態で使用していたら,正しくアンチエイリアスできません。こうしたときには,-Dawt.useSystemAAFontSettings=lcd_vrgbといったように指定しなくてはなりません。

ヒントを変化させて描画
図7 ヒントを変化させて描画

ここで示したように,Java SE 6ではサブピクセルを使用したアンチエイリアスが可能になりました。ただ,効果が薄いと感じられることも多いので,使うか使わないかはユーザーに委ねるのがよさそうです。

例えば,前述したawt.useSystemAAFontSettingsの値を使用するのがいいかもしれません。この場合はSystem#getPropertyメソッドを使用すればawt.useSystemAAFontSettingsの値を取得できます。

とはいうものの,アンチエイリアスは効果が高いので,デフォルトではヒントをRenderingHints.VALUE_TEXT_ANTIALIAS_GASPにしておき,awt.useSystemAAFontSettingsに値が設定してあればそれを使用するのがいいと思います。

注1 J2SE 5.0では,非標準ですが下記のような起動時のオプションでアンチエイリアスを使用することもできました。

>java -Dswing.aatext=true [クラス名]

注2 これ以外に,VALUE_TEXT_ANTIALIAS_GASPやKEY_TEXT_LCD_CONSTRASTなども追加されました。

著者紹介 櫻庭祐一

横河電機 ネットワーク開発センタ所属。Java in the Box 主筆

今月の櫻庭

サン・マイクロシステムズとリクルートがタイアップして行っているMash up Award 2ndが開催されています。

昨年行われたMash up AwardではリクルートのWeb APIだけが対象でした。ところが,今回はサンとリクルート以外に,Skypeやシックスアパート,テクノラティなど協賛企業が17社もあります。使用できるWeb APIもバラエティに富んでいます。ということは,Mash upする材料がいろいろあるということ。アイデアしだいで,クールなアプリケーションが思いのままです。

締め切りは3月12日。何かおもしろいことをやってみたい方,ぜひトライしてみてくださいね。