Доступ к информации о кернинге шрифтов в Java2D
Вопрос
Небольшая предыстория..
Я нахожусь в процессе создания игры на OpenGL, используя Java и LWJGL.Я написал книгу TextRenderer
-класс, который отображает текст с использованием кэшированных страниц глифов.Сами глифы отображаются в Java2D для BufferedImage
s и упакованы на страницы текстур вместе с измерениями глифов. TextRenderer
рисует символы в виде текстурированных квадратов, используя кэшированную информацию.
Все это работает хорошо, за исключением одной вещи:отсутствует кернинг.Конечно, в этом нет необходимости, поскольку текст и так выглядит нормально, но это улучшило бы качество, если бы у меня был доступ к информации о кернинге шрифтов.
И вот в чем вопрос..
Возможно ли получить информацию о кернинге, используя обычную Java, таким образом, чтобы она была переносима в Windows, Linux и macOS X ?Еще тогда, когда я писал TextRenderer
Я бегло огляделся по сторонам, но не смог найти такого выхода..
Одно из возможных решений
Если нет способа сделать это на чистой Java, я подумывал о написании отдельного инструмента с использованием Свободный Тип.Как указано на странице их функций:
FreeType 2 предоставляет информацию, которая часто недоступна в других похожих системах обработки шрифтов, таких как кернинг расстояния, имена глифов, вертикальная метрики и т. д.
Инструмент сохранит пары кернинга для общих символов в файл, который загрузит и будет использовать мой инструмент визуализации текста.Так что, вероятно, это то, что я сделаю, если вы, ребята, не придумаете лучшей альтернативы.:)
Решение
Единственными библиотеками, о которых я знаю, которые правильно считывают информацию о кернинге "somwhat", являются iText - Текст и ЩЕГОЛЬ из 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 не существует)
Другие советы
Начиная с 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);
Эта ветка форума содержит более подробное обсуждение этой темы:
по пути поиска информации о кернинге и предоставления ее в автономном режиме в моем JavaScript я также прочитал этот вопрос здесь, и поскольку ответа не было, я поискал дальше, и в конце я получил это:
Два объекта javascript, которые могут быть проиндексированы с помощью символа unicode:
GLYPHS = {};
KERNS = {};
И они расположены вот так:
// GLYPHS[ unicode ] = [ "name", width ];
// KERNS [ unicode ] = { "nextGlyphName" : horizontalAdjustment };
// = { GLYPHS[ unicode ][ 0 ] : horizontalAdjustment };
Итак, если у меня есть моя строка "Text", я просматриваю ее посимвольно и использую его unicode для доступа к имени и ширине глифа следующим образом:
glUnicode = "Text".charCodeAt( strIndex ); // "T" == 84
glName = GLYPHS[ glUnicode ][ 0 ];
glWidth = GLYPHS[ glUnicode ][ 1 ];
Чтобы получить доступ к значению кернинга, мы должны посмотреть на следующее значение символов в юникоде, которое является следующим:
nextGlyphUnicode = "Text".charCodeAt( strIndex + 1 ); // "e" == 101
И если следующий объект существует, то этот оператор предоставит вам ширину кернинга (сначала вы должны проверить наличие следующим образом:
if ( !( KERNS[ glUnicode ] == undefined ) ) {
if ( !( KERNS[ glUnicode ][ GLYPHS[ nextGlyphUnicode ][ 0 ] ] == undefined ) ) {
...
):
kernWidth = KERNS[ glUnicode ][ GLYPHS[ nextGlyphUnicode ][ 0 ] ];
В этом примере ширина ядра для буквы "e", следующей за буквой "T", будет равна
kernWidth == -143
Я думаю, это то, что вы искали, не так ли?Вся информация доступна через значение символа в юникоде и значение следующего символа в юникоде.Очень просто и очень приятно.
Итак, я создал файл для каждого шрифта, и первая страница выглядит следующим образом:
// 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
"встроенный" интерпретатор 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()
Я надеюсь, это может помочь.Большое вам спасибо за ваше внимание,
Ричард