如果文本中有阿拉伯文或波斯文字符,通过fontmetrics计算的字符串宽度非常慢 [英] String width via fontmetrics calculation is very slow if there are arabic or persian letters in text

查看:222
本文介绍了如果文本中有阿拉伯文或波斯文字符,通过fontmetrics计算的字符串宽度非常慢的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个问题。如果我在那里使用东方语言,我的应用程序界面工作速度会慢很多特别是我觉得它在组件,如JList,JCombobox,JTable。

如果在文本中至少有一个字母是阿拉伯语或波斯语,我发现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(波斯计算时间:+(System.currentTimeMillis() - start)+ms);
start = System.currentTimeMillis();
for(int i = 0; i< size; i ++)
{
fm.stringWidth(english);

System.out.println(英语计算时间:+(System.currentTimeMillis() - start)+ms);

private static FontMetrics createFontMetrics(font font)
{
BufferedImage bi = new BufferedImage(1,1,BufferedImage.TYPE_INT_ARGB_PRE);
图形g = bi.getGraphics();
FontMetrics fm = g.getFontMetrics(font);
g.dispose();
bi = null;
return fm;




$ b $ p
$ b

对于我来说,它给出了下一个输出:



波斯语的计算时间:5482 ms

英语的计算时间:11 ms



从FontDesignMetrics的源代码中,我们可以看到主要操作序列

  public int stringWidth(String str){
float width = 0;
if(font.hasLayoutAttributes()){
/ * TextLayout抛出IAE为null,所以抛出NPE * /
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); (ch <0x100){
width + = getLatinCharWidth(ch);
if
} 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的性能。



如果有人对这里感兴趣,关于各种字体和文本布局细微差别的文章是
< a href =http://download.oracle.com/javase/1.4.2/docs/guide/2d/spec/j2d-fonts.html =nofollow> http://download.oracle.com/ javase / 1.4.2 / docs / guide / 2d / spec / j2d-fonts.html


I have a problem. My application interface works much slower if i use eastern languages there. Especially i felt it in components such as JList, JCombobox, JTable.

How i found the performance of FontMetrics.stringWidth method is very slow (500+ times) if in the text at least one letter is arabic or persian. How i know it is commonly used method in various swing components.

Is there a way to boost this method performance?

Here is the example class which demonstrates the problem:

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

For me it gives next output:

Calculation time for persian: 5482 ms

Calculation time for english: 11 ms

解决方案

I've dug for a little and found next:

From the source of the FontDesignMetrics we can see the main actions sequence

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

}

For latin characters method getLatinCharWidth(ch) is used. It caches all the characters widths. But for persian and arabic characters TextLayout is used instead of. The main purpose is because eastern characters may have varios shape and width depend on context. It is possible to add method which will cache characters width but it will not give exact values such as it will ignore nuances of different characters widths. Also it will ignore various ligatures.

I've tested TextLayout separately and it is slow for both languages english and persian. So the real cause of the slow performance is the slow work of the sun.font.TextLayout class. It is used to determine string width in case characters in the string are not simple. Unfortunately i don't know how to boost TextLayout performance for a now.

If somebody is interested here the article about various font and text layout nuances is http://download.oracle.com/javase/1.4.2/docs/guide/2d/spec/j2d-fonts.html

这篇关于如果文本中有阿拉伯文或波斯文字符,通过fontmetrics计算的字符串宽度非常慢的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆