访问Java2D中的字体字距调整信息

时间:2009-06-15 15:11:35

标签: java fonts java-2d freetype kerning

小背景..

我正在使用 Java LWJGL制作OpenGL游戏。我写了一个TextRenderer - 类,使用缓存的字形页面呈现文本。字形本身在Java2D中呈现为BufferedImage,并与字形测量一起打包到纹理页面中。 TextRenderer使用缓存的信息将字符绘制为纹理四边形。

所有这一切都运作良好,除了一件事:缺少字距。当然,没有必要让文本看起来很好,但如果我能够访问字体字距信息,它会提高质量。

问题是......

是否可以使用普通Java获取字距调整信息,以便可以跨Windows,Linux和MacOS X移植?回到我写TextRenderer的时候,我简短地环顾四周,但找不到这样的方式......

一种可能的解决方案

如果在纯Java中无法做到这一点,我正在考虑使用 Freetype 编写单独的工具。如其功能页面中所列:

  

FreeType 2提供的信息   通常无法从其他人那里获得   类似的字体引擎,如字距   距离,字形名称,垂直   指标等。

该工具会将常用字符的字距调整对存储到文本渲染器将加载并使用的文件中。所以如果你们没有提出更好的选择,这可能就是我要做的。 :)

3 个答案:

答案 0 :(得分:2)

从Java SE 6开始,Java可以在字体提供时提供字距调整信息。它默认是关闭的,可以像这样打开:

Map<TextAttribute, Object> textAttributes = new HashMap<TextAttribute, Object>();  

textAttributes.put(TextAttribute.FAMILY, "Arial");  
textAttributes.put(TextAttribute.SIZE, 25f);  
textAttributes.put(TextAttribute.KERNING, TextAttribute.KERNING_ON);  

Font font = Font.getFont(textAttributes);  

此论坛主题包含有关该主题的更详细讨论:

http://forums.sun.com/thread.jspa?threadID=5359127

答案 1 :(得分:1)

我所知道的唯一能够正确读取字距调整信息“somwhat”的库是来自Apache的iTextFOP

http://www.1t3xt.info/api/com/lowagie/text/pdf/BaseFont.html http://svn.apache.org/viewvc/xmlgraphics/fop/tags/fop-0_95/src/java/org/apache/fop/fonts/(链接到svn似乎没有在线api)

答案 2 :(得分:0)

在我查找字距调整信息并在我的javaScript中离线提供的过程中,我也在这里阅读了这个问题,因为没有答案,我进一步搜索,最后得到了这个:

两个javascript对象,可以通过字形的unicode索引:

GLYPHS = {};
KERNS  = {};

它们的设置如下:

// GLYPHS[ unicode ] = [ "name", width ];
// KERNS [ unicode ] = { "nextGlyphName"        : horizontalAdjustment };
//                   = { GLYPHS[ unicode ][ 0 ] : horizontalAdjustment };

所以,如果我有我的&#34; Text&#34;字符串,我逐字逐句地使用它,并使用他的unicode访问字形名称和宽度,如下所示:

glUnicode = "Text".charCodeAt( strIndex );            // "T" == 84
glName    = GLYPHS[ glUnicode ][ 0 ];
glWidth   = GLYPHS[ glUnicode ][ 1 ];

要访问字距调整值,我们必须查看下一个字符unicode值,即:

nextGlyphUnicode = "Text".charCodeAt( strIndex + 1 ); // "e" == 101

如果存在以下对象,则此语句将为您提供字距调整宽度(您必须首先检查是否存在:

if ( !( KERNS[ glUnicode ] == undefined ) ) {
  if ( !( KERNS[ glUnicode ][ GLYPHS[ nextGlyphUnicode ][ 0 ] ] == undefined ) ) {
  ...

):

kernWidth = KERNS[ glUnicode ][ GLYPHS[ nextGlyphUnicode ][ 0 ] ];

在这个例子中,&#34; e&#34;的kernWidth;遵循&#34; T&#34;会是

kernWidth == -143

我想,这就是你要找的,对吧? 所有信息都可通过字符的unicode值和后续字符的unicode值访问。 非常简单,非常好。

所以我为每种字体创建了一个文件,第一页看起来像这样:

// Family Name
// 'Times New Roman'
// EM size
// '2048'
// is_quadratic
// '1'
//
// GLYPHS[ unicode ] = [ "name", width ];
// KERNS [ unicode ] = { "nextGlyphName"        : horizontalAdjustment };
//                   = { GLYPHS[ unicode ][ 0 ] : horizontalAdjustment };
GLYPHS = {};
KERNS  = {};

GLYPHS[    32 ] = [ "space",  512 ];
KERNS [    32 ] = {
  "Upsilondieresis" :   -76,
  "Upsilon"         :   -76,
  "Tau"             :   -37,
  "Lambda"          :  -113,
  "Delta"           :  -113,
  "Alpha"           :  -113,
  "Alphatonos"      :  -113,
  "Y"               :   -76,
  "W"               :   -37,
  "V"               :   -37,
  "T"               :   -37,
  "A"               :  -113
};
GLYPHS[    33 ] = [ "exclam",  682 ];
GLYPHS[    34 ] = [ "quotedbl",  836 ];
GLYPHS[    35 ] = [ "numbersign", 1024 ];
GLYPHS[    36 ] = [ "dollar", 1024 ];
GLYPHS[    37 ] = [ "percent", 1706 ];
GLYPHS[    38 ] = [ "ampersand", 1593 ];
GLYPHS[    39 ] = [ "quotesingle",  369 ];
GLYPHS[    40 ] = [ "parenleft",  682 ];
GLYPHS[    41 ] = [ "parenright",  682 ];
GLYPHS[    42 ] = [ "asterisk", 1024 ];
GLYPHS[    43 ] = [ "plus", 1155 ];
GLYPHS[    44 ] = [ "comma",  512 ];
GLYPHS[    45 ] = [ "hyphen",  682 ];
GLYPHS[    46 ] = [ "period",  512 ];
GLYPHS[    47 ] = [ "slash",  569 ];
GLYPHS[    48 ] = [ "zero", 1024 ];
GLYPHS[    49 ] = [ "one", 1024 ];
KERNS [    49 ] = {
  "one"             :   -76
};
GLYPHS[    50 ] = [ "two", 1024 ];
GLYPHS[    51 ] = [ "three", 1024 ];
GLYPHS[    52 ] = [ "four", 1024 ];
GLYPHS[    53 ] = [ "five", 1024 ];
GLYPHS[    54 ] = [ "six", 1024 ];
GLYPHS[    55 ] = [ "seven", 1024 ];
GLYPHS[    56 ] = [ "eight", 1024 ];
GLYPHS[    57 ] = [ "nine", 1024 ];
GLYPHS[    58 ] = [ "colon",  569 ];
GLYPHS[    59 ] = [ "semicolon",  569 ];
GLYPHS[    60 ] = [ "less", 1155 ];
GLYPHS[    61 ] = [ "equal", 1155 ];
GLYPHS[    62 ] = [ "greater", 1155 ];
GLYPHS[    63 ] = [ "question",  909 ];
GLYPHS[    64 ] = [ "at", 1886 ];
GLYPHS[    65 ] = [ "A", 1479 ];
KERNS [    65 ] = {
  "quoteright"      :  -227,
  "y"               :  -188,
  "w"               :  -188,
  "v"               :  -152,
  "Y"               :  -188,
  "W"               :  -164,
  "V"               :  -264,
  "T"               :  -227,
  "space"           :  -113
};
GLYPHS[    66 ] = [ "B", 1366 ];
GLYPHS[    67 ] = [ "C", 1366 ];

您可以将所需的每个文件的内容复制到源代码中,或者在运行时将其读入以使对象可用。

可以使用以下脚本创建文件,该脚本在fontforge&#34;嵌入式&#34;内可以正常运行。 python 2.7解释器。 此脚本专为Windows机器设计,因此您必须首先调整路径!

#
# run these two commands in the fontforge "embedded" python interpreter (ffpython.exe)
# >>> script = open( "Scripts\\Kernings.py", "r" )
# >>> exec script

import fontforge

fontFilenames = [
  "arial.ttf",
  "arialbd.ttf",
  "ariali.ttf",
  "arialbi.ttf",
  "ARIALN.TTF",
  "ARIALNB.TTF",
  "ARIALNI.TTF",
  "ARIALNBI.TTF",
  "calibri.ttf",
  "calibrib.ttf",
  "calibrii.ttf",
  "calibriz.ttf",
  "cambria.ttc",
  "cambriab.ttf",
  "cambriai.ttf",
  "cambriaz.ttf",
  "times.ttf",
  "timesbd.ttf",
  "timesi.ttf",
  "timesbi.ttf",
  "verdana.ttf",
  "verdanab.ttf",
  "verdanai.ttf",
  "verdanaz.ttf"
  ]

for actFontFile in fontFilenames :
  print( "c:\\windows\\fonts\\" + actFontFile )
  out  = open( "Scripts\\Kern_" + actFontFile[ : len( actFontFile ) - 4 ] + "_json.txt", "w" )
  font = fontforge.open( "c:\\windows\\fonts\\" + actFontFile )
  out.write(
      "// Family Name\n// '"  + font.familyname          + "'\n"
    + "// EM size\n// '"      + str( font.em )           + "'\n"
    + "// is_quadratic\n// '" + str( font.is_quadratic ) + "'\n"
    + "//\n"
    + '// GLYPHS[ unicode ] = [ "name", width ];\n'
    + '// KERNS [ unicode ] = { "nextGlyphName"        : horizontalAdjustment };\n'
    + "//                   = { GLYPHS[ unicode ][ 0 ] : horizontalAdjustment };\n"
    + "GLYPHS = {};\n"
    + "KERNS  = {};\n\n"
    )
  glyphIdIterator = font.__iter__()
  for glyphName in glyphIdIterator :
    if font[ glyphName ].unicode >=0 :
      kerningStrings = []
      outstring = ( "GLYPHS[ "
        + str( font[ glyphName ].unicode ).rjust( 5 ) + " ] = [ \""
        + glyphName + "\"," 
        + str( font[ glyphName ].width ).rjust( 5 ) + " ];\n"
        )
      subs = font[ glyphName ].getPosSub("*")
      if len( subs ):
        for sub in subs:
          if len( sub ):
            for subsub in sub:
              if str( subsub ).lower().find( "'kern'" ) >=0:
                kerningStrings.append(
                  ("  \"" + str( sub[ 2 ] ) + "\"").ljust( 20 )
                + ":"     + str( sub[ 5 ] ).rjust( 6 )
                )
                break
      krnStrLen = len( kerningStrings )
      if ( krnStrLen ) :
        outstring = outstring + ( "KERNS [ "
          + str( font[ glyphName ].unicode ).rjust( 5 ) + " ] = {" )
        for kerningString in kerningStrings :
          outstring = outstring + "\n" + kerningString + ","
        outstring = outstring.rstrip( "," )
        outstring = outstring + "\n};\n"
      out.write( outstring )
  out.close()
  font.close()

我希望,这可以提供帮助。 非常感谢你的关注,

理查德