14

私は問題があります。そこで東方言語を使用すると、アプリケーション インターフェイスの動作が大幅に遅くなります。特にJList、JCombobox、JTableなどのコンポーネントでそれを感じました。

テキスト内の少なくとも 1 つの文字がアラビア語またはペルシア語の場合、FontMetrics.stringWidth メソッドのパフォーマンスが非常に遅い (500 回以上) ことがわかりました。どのように私はそれがさまざまなスイングコンポーネントで一般的に使用されている方法であることを知っています.

このメソッドのパフォーマンスを向上させる方法はありますか?

問題を示すクラスの例を次に示します。

import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics;
import java.awt.image.BufferedImage;

public class FontMetricsSpeedTest
{

 public static void main( String args[] ) {
  String persian="صصصصصصصصصصصصصصصصصصصصص";
  String english="abcde()agjklj;lkjelwk";
  FontMetrics fm=createFontMetrics(new Font("dialog",Font.PLAIN,12));
  int size=50000;
  long start=System.currentTimeMillis();
  for(int i=0;i<size;i++)
  {
   fm.stringWidth(persian);
  }
  System.out.println("Calculation time for persian: "+(System.currentTimeMillis()-start)+" ms");
  start=System.currentTimeMillis();
  for(int i=0;i<size;i++)
  {
   fm.stringWidth(english);
  }
  System.out.println("Calculation time for english: "+(System.currentTimeMillis()-start)+" ms");
 }
 private static FontMetrics createFontMetrics(Font font)
 {
  BufferedImage bi = new BufferedImage(1, 1, BufferedImage.TYPE_INT_ARGB_PRE);
  Graphics g = bi.getGraphics();
  FontMetrics fm = g.getFontMetrics(font);
  g.dispose();
  bi = null;
  return fm;
 }
}

私にとっては、次の出力が得られます。

ペルシア語の計算時間: 5482 ミリ秒

英語の計算時間: 11 ms

4

4 に答える 4

4

私は少し掘り下げて、次を見つけました:

FontDesignMetrics のソースから、主なアクション シーケンスを見ることができます。

public int stringWidth(String str) {
float width = 0;
if (font.hasLayoutAttributes()) {
    /* TextLayout throws IAE for null, so throw NPE explicitly */
    if (str == null) {
        throw new NullPointerException("str is null");
    }
    if (str.length() == 0) {
        return 0;
    }
    width = new TextLayout(str, font, frc).getAdvance();
} else {
    int length = str.length();
    for (int i = 0; i < length; i++) {
        char ch = str.charAt(i);
        if (ch < 0x100) {
            width += getLatinCharWidth(ch);
        } else if (FontManager.isNonSimpleChar(ch)) {
            width = new TextLayout(str, font, frc).getAdvance();
            break;
        } else {
            width += handleCharWidth(ch);
        }
    }
}
return (int) (0.5 + width);

}

ラテン文字のメソッド getLatinCharWidth(ch) が使用されます。すべての文字幅をキャッシュします。ただし、ペルシア語とアラビア語の文字の場合は、代わりに TextLayout が使用されます。主な目的は、東洋文字は文脈によってさまざまな形と幅を持つ可能性があるためです。文字幅をキャッシュするメソッドを追加することは可能ですが、異なる文字幅のニュアンスを無視するなど、正確な値は得られません。また、さまざまな合字を無視します。

私は TextLayout を個別にテストしましたが、英語とペルシア語の両方の言語で遅いです。したがって、パフォーマンスが低下する本当の原因は、sun.font.TextLayout クラスの動作が遅いことです。文字列内の文字が単純でない場合に、文字列幅を決定するために使用されます。残念ながら、今のところ TextLayout のパフォーマンスを向上させる方法がわかりません。

ここで誰かが興味を持っている場合は、さまざまなフォントとテキスト レイアウトのニュアンスに関する記事が http://download.oracle.com/javase/1.4.2/docs/guide/2d/spec/j2d-fonts.htmlにあります。

于 2010-12-07T17:42:55.753 に答える
2

あなたのコードを使用して、他の言語でいくつかのテストを実行しました。まず、あなたの言うとおりです。ペルシャ文字列の計算には多くの時間がかかりました。

フォントの種類とサイズを試してみましたが、大きな違いは見られませんでした。ただし、結果は使用しているスクリプトによって異なります。これが私のマシンで得た結果です。

Calculation time for Persian: 2877 ms
Calculation time for English: 8 ms
Calculation time for Russian: 47 ms
Calculation time for Hebrew:  16815 ms

ご覧のとおり、ロシア語は英語より 6 倍遅いです。文字列の内部表現がユニコードだからだと思います。UTF-8 では、英語の文字は 1 バイト、その他はすべて 2 バイトです。

それがあなたを満足させるかどうかはわかりません:)しかし、ヘブライ語のテストはペルシア語の4倍遅いです. どちらも遅いので、右から左への計算がそれを殺すと思います。

私たちはこれとは何の関係もないようです。

于 2010-12-02T10:11:51.617 に答える
0

Font クラスのメソッドを使用してみてください。public GlyphVector layoutGlyphVector(FontRenderContext frc, char[] text, int start, int limit, int flags)

そして、GlyphVector を使用して文字列を測定しますか?

または TextLayout public TextLayout(String string, Font font, FontRenderContext frc)

于 2010-12-02T14:46:47.410 に答える