Доступ к информации о кернинге шрифтов в Java2D - PullRequest
5 голосов
/ 15 июня 2009

Маленький фон ..

Я нахожусь в процессе создания игры OpenGL, используя Java и LWJGL . Я написал TextRenderer -класс, который отображает текст с использованием кэшированных страниц глифов. Сами глифы отображаются в Java2D на BufferedImage s и упаковываются в страницы текстуры вместе с измерениями глифов. TextRenderer рисует символы как текстурированные квадраты, используя кэшированную информацию.

Все это работает хорошо, за исключением одного: отсутствует кернинг. Конечно, это необязательно, так как текст выглядит нормально, как есть, но это улучшило бы качество, если бы у меня был доступ к информации о кернинге шрифтов.

И вопрос ...

Можно ли получить информацию о кернинге, используя простую Java, способом, который был бы переносим для Windows, Linux и MacOS X? Когда я писал TextRenderer, я кратко огляделся, но не смог найти такой способ ..

Одно из возможных решений

Если в чистой Java нет способа сделать это, я подумал о написании отдельного инструмента с использованием Freetype . Как указано на странице их функций:

FreeType 2 предоставляет информацию, которая часто недоступен от других похожие шрифтовые движки, такие как кернинг расстояния , имена глифов, вертикальные метрики и пр.

Инструмент будет хранить пары кернинга для общих символов в файле, который будет загружать и использовать мой текстовый рендерер. Так что это, вероятно, то, что я сделаю, если вы, ребята, не придумали лучшую альтернативу. :)

Ответы [ 3 ]

2 голосов
/ 15 июня 2009

Начиная с 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 голос
/ 15 июня 2009

Единственные известные мне библиотеки, которые правильно читают информацию о кернинге, - это iText и FOP из 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/ (ссылка на svn, так как, кажется, нет онлайн API)

0 голосов
/ 31 мая 2016

Находясь на пути поиска информации о кернинге и предоставления ее в автономном режиме в рамках моего javaScript, я тоже прочитал этот вопрос здесь, и поскольку ответа не было, я продолжил поиск и в конце получил:

Два объекта javascript, которые можно проиндексировать с помощью Юникода глифа:

GLYPHS = {};
KERNS  = {};

И они установлены так:

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

Так что, если у меня есть строка «Текст», я прохожу через нее символ за символом и использую его юникод для доступа к имени и ширине глифов следующим образом:

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

В этом примере kernWidth для «e», следующего за «T», будет

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

Вы можете скопировать содержимое каждого нужного вам файла в ваш исходный код или прочитать его во время выполнения, чтобы объекты были доступны.

И файлы могут быть созданы с помощью следующего скрипта, который отлично работает в «встроенном» интерпретаторе python 2.7 fontforge. Этот сценарий предназначен для 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()

Надеюсь, это может помочь. Большое спасибо за внимание,

Richard

...