2010-12-02 5 views
13

問題があります。そこに東洋言語を使用すると、私のアプリケーションインターフェイスはかなり遅く動作します。特に私はJList、JCombobox、JTableなどのコンポーネントでそれを感じました。テキストにアラビア語またはペルシア語の文字がある場合、fontmetrics計算による文字列の幅が非常に遅い

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

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

計算時間:5482ミリ英語

計算時間:11ミリ秒、それは次の出力を与える私にとって

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; 
} 
} 

:ここ

は、問題を示すサンプルクラスです

答えて

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倍遅いです。どちらも遅いので、右から左への計算はそれを殺すと思います。

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

+0

しかし、最小500倍遅くキル性能:( – httpdispatch

+0

はあなたが本当に何千ものメトリックを計算する必要がある場合にのみ。あなたは10を持っている場合は同意します画面上の行は重要ではありません:UIコントロールの描画にも時間がかかります。ソリューションが見つかったらここに投稿してください... – AlexR

+0

解決策は太陽を書き換えてさらに置き換えることだと思います。 – httpdispatch

0

Fontクラスのメソッドを使用できませんか。 公共GlyphVectorのlayoutGlyphVector(されたFontRenderContext FRC、 のchar []テキスト、 int型開始、 int型の制限、 int型のフラグ)

し、あなたの文字列を測定するためにされたGlyphVectorを使うのか?

それともTextLayoutの 公共のTextLayout(文字列、フォント、フォント、されたFontRenderContextのFRC)は

+0

問題は、標準スイングコンポーネントがsun.font.FontDesignMetrics.stringWidth()を呼び出していることです。方法。また、数千もの英語以外の文字列があれば、標準のスイングコンポーネントは遅くなります。 – httpdispatch

+0

興味深いもの。どちらの場合でもテキストレイアウトが遅くなります。しかし、FontDesignMetricsのstringWidthには、ラテン文字のキャッシュがあります。 – httpdispatch

+0

if(ch <0x100){ \t \t \t \t \t width + = getLatinCharWidth(ch); \t \t \t \t} – httpdispatch

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

+0

+1いいDIG :-) – kleopatra

0

です。 javasのクラスが行う内部呼び出しを解決するのではなく、ペルシア語の文字でパフォーマンスの問題を解決しました(私は多くのレンダリングを使用します)。ペアクラスは二つのオブジェクトだけの型指定されたBeanです...

public class GuiUtils { 
private static final Map<Pair<Boolean, Pair<FontMetrics, String>>, Integer> stringWidthCache = new HashMap<Pair<Boolean, Pair<FontMetrics, String>>, Integer>(); 

public static int getStringWidth(FontMetrics fm, String text){ 
    return getStringWidth(null, fm, text); 
} 

public static int getStringWidth(Graphics g, FontMetrics fm, String text){ 
    if(text == null || text.equals("")) { 
     return 0; 
    } 
    Pair<Boolean, Pair<FontMetrics, String>> cacheKey = 
      new Pair<Boolean, Pair<FontMetrics, String>>(g != null, new Pair<FontMetrics, String>(fm, text)); 
    if (!stringWidthCache.containsKey(cacheKey)) { 
     stringWidthCache.put(
       cacheKey, 
       g != null ? 
         (int)Math.ceil(fm.getStringBounds(text, g).getWidth()) : 
          fm.stringWidth(text)); 
    } 
    return stringWidthCache.get(cacheKey); 
} 

}

関連する問題