Pergunta

Little fundo ..

Eu estou no processo de fazer um jogo OpenGL usando Java e LWJGL . Eu escrevi um TextRenderer de classe que presta texto usando páginas em cache de glifos. Os glifos em si são prestados em Java2D para BufferedImages e embalados em páginas textura, juntamente com as medidas de glifo. TextRenderer desenha os personagens como quads texturizados, utilizando as informações armazenadas em cache.

Tudo isso funciona bem, exceto por uma coisa: falta kerning. Concedido, não é necessário ter como a aparência de texto bem como está, mas seria melhorar a qualidade se eu tivesse acesso à informação kerning fonte.

E a pergunta é ..

É possível obter as informações kerning usando plain Java, de uma forma que seria portável para Windows, Linux e MacOS X? Voltar quando eu escrevi o TextRenderer I brevemente olhou em volta, mas não conseguiu encontrar uma forma ..

Uma possível solução

Se não há nenhuma maneira de fazer isso em Java puro, eu estava pensando em escrever uma ferramenta separada usando Freetype . Como listado em sua página de recursos:

FreeType 2 fornece informações que muitas vezes não é disponível a partir de outra motores de fonte semelhante, como kerning distâncias , nomes de glifos, vertical métricas, etc.

A ferramenta seria armazenar os pares de kerning para personagens comuns em um arquivo que o meu processador de texto iria carregar e fazer uso. Portanto, este é provavelmente o que vou fazer se vocês não vêm-se com uma alternativa melhor. :)

Foi útil?

Solução

As únicas bibliotecas que eu conheço que leia a informação kerning "somwhat" corretamente são iText FOP de Apache.

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/ (um link para o svn como parece haver nenhuma API on-line)

Outras dicas

A partir do Java SE 6, Java pode fornecer informações kerning quando a fonte fornece. É desativado por padrão e pode ser ligado assim:

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

Este tópico do fórum contém uma discussão mais detalhada sobre o tema:

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

no meu caminho para encontrar as informações de ajuste de espaço e fornecendo-lo offline dentro do meu JavaScript, eu li esta pergunta aqui, também e desde que não havia nenhuma resposta, eu procurei mais adiante e no final eu tenho esse:

Dois javascript objetos que podem ser indexados pelo unicode do glifo:

GLYPHS = {};
KERNS  = {};

E eles são definidos como este:

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

Então, se eu tenho a minha string "Texto", eu passar por isso caractere por caractere e usar sua unicode para acessar o nome e largura de glifos como esta:

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

Para acessar o valor kerning, temos de olhar para os próximos caracteres Unicode valor que é o seguinte:

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

E se existe o seguinte objeto, então esta afirmação vai lhe dar a largura kerning (você tem que verificar para a existência primeira como esta:

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

):

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

Neste exemplo, kernWidth para o "e" após o "T" seria

kernWidth == -143

Eu acho, isso é o que você estava procurando, certo? Todas as informações acessíveis através do valor Unicode do caractere eo valor Unicode do caractere seguinte. Muito simples e muito agradável.

Então, eu criei um arquivo para cada fonte e os primeiros olhares página como esta:

// 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 ];

Você pode copiar o conteúdo de cada arquivo que você precisa em seu código fonte ou lê-lo em em tempo de execução para ter os objetos availlable.

e os arquivos podem ser criados com o seguinte script que funciona muito bem dentro de "embedded" 2,7 interpretador Python da fontforge. Este script é projetado para uma máquina Windows, então você tem que adaptar os seus caminhos em primeiro lugar!

#
# 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()

Espero, isso pode ajudar. Muito obrigado pela sua atenção,

Richard

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top