如何使用Opentype字体从GPOS表中使用字距调整对并从中提取字距调整对,以在Java中将字形正确显示为Path2D? [英] How can I use and extract kerning pairs from from GPOS table in Opentype fonts to correctly show glyphs as Path2D in Java?

查看:76
本文介绍了如何使用Opentype字体从GPOS表中使用字距调整对并从中提取字距调整对,以在Java中将字形正确显示为Path2D?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这个问题与很久以前问过的几个问题有关.我看到有评论说Java不支持 Opentype 字体,但这是11年前的事情了.如今,它们已经成为现实.唯一的问题是紧缩对仅在 GPOS 表中给出.我已经看到它们在那里,但是很难确保代码正确.

我目前正在转储 GPOS 表,以尝试按照指针操作,直到字距调整对为止.

下面是到目前为止的代码,其中 GPOS 表先前已复制到数组 gpos 中.转储表的功能是 dumpGPOS().我需要帮助来确定我的操作是否正确以及如何对 TODO 部分进行编码:

  byte [] gpos;char [] hexasc(char [] hex,byte num){int up = num>>4;int down = num&15;hex [0] =(char)((up< 10)?'0'+ up:'A'+ up-10);hex [1] =(char)((down< 10)?'0'+ down:'A'+ down-10);返回十六进制;}char [] hex = {'0','0'};无效printHex(字节b){hexasc(hex,b);System.out.print(hex [0]);System.out.print(hex [1]);}void dumpGPOS(){int i,j;System.out.println("GPOS标头");System.out.print(版本:");对于(i = 0; i <4; i ++)printHex(gpos [i]);System.out.println((" +(gpos [0]< 8 | gpos [1])+." +(gpos [2]< <8 | gpos [3])+)");j = i;System.out.print(" TheScriptList:);对于(i = 4; i <6; i ++)printHex(gpos [i]);System.out.println((" +(gpos [j] <8 | gpos [j + 1])+")"));j = i;System.out.print("TheFeatureList:");对于(i = 6; i <8; i ++)printHex(gpos [i]);System.out.println((" +(gpos [j] <8 | gpos [j + 1])+")"));j = i;System.out.print("TheLookupList:");对于(i = 8; i <10; i ++)printHex(gpos [i]);int查找=(gpos [j]<< 8 | gpos [j + 1]);System.out.println((" +"+ lookup",)");j = i;System.out.println(查找列表表");System.out.print(" lookupCount:");对于(i = lookup; i< = lookup + 1; i ++)printHex(gpos [i]);System.out.print('\ n');int count =(gpos [lookup]<< 8 | gpos [lookup + 1]);int选项卡=查找+ 2;int [] LookupList = new int [count];for(j = 0; j< count; j ++){System.out.print("lookup [" + j +] =");printHex(gpos [tab]);printHex(gpos [tab + 1]);System.out.println((" +(LookupList [j] =(gpos [tab]<< 8 | gpos [tab + 1]))+")"));制表符+ = 2;}整数项,子项,大小;for(j = 0; j< count; j ++){item =查找+ LookupList [j];System.out.println("Lookup [" + j +]");System.out.println(查找类型:" +(gpos [item]<< 8 | gpos [item + 1])));System.out.print("Lookup flag:");printHex(gpos [item + 2]);printHex(gpos [item + 3]);size =(gpos [item + 4]<< 8 | gpos [item + 5]));System.out.println("\ n子表数:" +大小);子=项目+ 6;int [] subTable = new int [size];System.out.println(子表偏移量");对于(i = 0; i< size; i ++){subTable [i] =(gpos [sub]<< 8 | gpos [sub +1]);子+ = 2;System.out.println("+" subTable [i]);}对于(i = 0; i< size; i ++){System.out.println("Subtable [" + i +"+"]));sub =项目+ subTable [i];printSubtable(sub);}}}void printSubtable(int sub){int格式= gpos [sub]<<8 |gpos [sub +1];System.out.println(" Format:" + format);如果(格式== 1){/* TODO格式1 */返回;}/* TODO格式2 */} 

此问题还与问题

下面的JavaScript代码将GPOS字距调整表转储到字符串 text 中,显示了每行中包含第二个字符和kern值的一组集合,而该对中的第一个字符出现了作为该行开头的Java字符.请注意,通过使用字符的ASCII码可以避免字形索引.

这只会将''(space)转储到'}',这对于英语非常有用.要扩展为其他字符,只需使用Unicode.

 <!-indoc:true->在此页上以HTML格式写->const indoc = true;const nl =(indoc)?< br>":"\ n";var chars = font.tables.cmap.glyphIndexMap;var g1,g2;var i,j,kern;var text =";对于(i = 32; i< 126; i ++){g1 = font.glyphs.get(chars [i]);文字+ ='''+(((i == 39 || i == 92)?"\\" + String.fromCharCode(i):String.fromCharCode(i))+'";对于(j = 32; j< 126; j ++){g2 = font.glyphs.get(chars [j]);如果((kern = font.getKerningValue(g1,g2))!== 0){文字+ =,{'";+((j == 39 || j == 92)?"\\" + String.fromCharCode(j):String.fromCharCode(j))+"',"+ kern +"}";}}文字+ = nl;} 

This question is related to a few questions that have been asked long time ago. I saw comments that Opentype fonts were not supported in Java, but this was 11 years ago. Nowadays they are. The only problem is that kerning pairs are only given in the GPOS table. I have seen that they are there but it is hard to make sure the code is correct.

I am currently dumping the GPOS table trying to follow the pointers until the kerning pairs.

The code so far is below, where GPOS table has been previously copied to the array gpos. The function to dump the table is dumpGPOS(). I need help to determine if what I am doing is correct and how to code the TODO parts:

byte[] gpos;

char[] hexasc( char[] hex, byte num ) {
    int up = num >> 4;
    int down = num & 15;
    hex[0] = (char) ((up < 10)? '0' + up : 'A' + up - 10);
    hex[1] = (char) ((down < 10)? '0' + down : 'A' + down - 10);
    return hex;
}

char[] hex = { '0', '0' };
void printHex(byte b) {
    hexasc(hex, b);
    System.out.print(hex[0]);
    System.out.print(hex[1]);
}

void dumpGPOS() {
    int i, j;
    System.out.println("GPOS header");
    System.out.print("Version:        ");
    for ( i = 0; i < 4; i++ ) printHex(gpos[i]);
    System.out.println("    (" + (gpos[0] << 8 | gpos[1]) + "." + (gpos[2] << 8 | gpos[3]) + ")" );
    j = i;
    System.out.print("TheScriptList:        ");
    for ( i = 4; i < 6; i++ ) printHex(gpos[i]);
    System.out.println("        (" + (gpos[j] << 8 | gpos[j+1]) + ")" );
    j = i;
    System.out.print("TheFeatureList:        ");
    for ( i = 6; i < 8; i++ ) printHex(gpos[i]);
    System.out.println("        (" + (gpos[j] << 8 | gpos[j+1]) + ")" );
    j = i;
    System.out.print("TheLookupList:        ");
    for ( i = 8; i < 10; i++ ) printHex(gpos[i]);
    int lookup = (gpos[j] << 8 | gpos[j+1]);
    System.out.println("        (" + lookup + ")" );
    j = i;

    System.out.println("Lookup List Table");
    System.out.print("lookupCount:        ");
    for ( i = lookup; i <= lookup+1; i++ ) printHex(gpos[i]);
    System.out.print('\n');
    int count = (gpos[lookup] << 8 | gpos[lookup+1]);
    int tab = lookup + 2;
    int[] LookupList = new int[count];
    for ( j = 0; j < count; j++ ) {
        System.out.print("lookup[" + j + "] =         ");
        printHex(gpos[tab]);
        printHex(gpos[tab + 1]);
        System.out.println("        (" + ( LookupList[j] = (gpos[tab] << 8 | gpos[tab+1]) ) + ")" );
        tab += 2;
    }
    int item, sub, size;
    for ( j = 0; j < count; j++ ) {
        item = lookup + LookupList[j];
        System.out.println("Lookup [" + j + "]");
        System.out.println("Lookup Type:        " + (gpos[item] << 8 | gpos[item + 1]) );
        System.out.print("Lookup flag:        ");
        printHex(gpos[item + 2]);
        printHex(gpos[item + 3]);
        size = (gpos[item + 4] << 8 | gpos[item + 5]);
        System.out.println("\nNumber of subtables:    "  + size);
        sub = item + 6;
        int[] subTable = new int[size];
        System.out.println("Subtable offsets");
        for ( i = 0; i < size; i++ ) {
            subTable[i] = (gpos[sub] << 8 | gpos[sub +1 ]);
            sub += 2;
            System.out.println( "    " + subTable[i] );
        }
        for ( i = 0; i < size; i++ ) {
            System.out.println("Subtable [" + i + "]");
            sub = item + subTable[i];
            printSubtable(sub);
        }
    }
}

void printSubtable(int sub) {
    int format = gpos[sub] << 8 | gpos[sub + 1];
    System.out.println("Format:        " + format );
    if (format == 1) {
        /* TODO format 1*/
        return;
    }
    /* TODO format 2*/
}

This problem is also related to the question How to use kerning pairs extracted from a TTF file to correctly show glyphs as Path2D in Java?.

The context is the same, but since Apache FOP doesn't read Opentype fonts and that Opentype fonts use only the kerning information from GPOS table, it is being much harder.

I am using the Microsoft Opentype reference, but it is way over the top (too vague, no drawings, no example code, and not enough examples). What could be more hints, some drawings, code snippets, more examples (especially for extracting kerning tables from GPOS table)?

How can I make 100% sure this code is really doing what it is supposed to do?

解决方案

Problem solved!

An advice: if you are trying to do this in Java you are losing your time. This problem was solved simply using Opentype.js and the site https://opentype.js.org, but particularly glyph inspector and font inspector.

I downloaded both code by copying and pasting from page source. I then modified glyph inspector to do the job. You need to go deeply into Opentype.js to get the kerning pairs, though, but it is all there (check code below).

I ended up porting the entire program to JavaScript. I didn't program JavaScript too much before. Therefore, it must be extremely easy for whom already programs in JavaScript. This program just generates a Java class with the glyphs, the kerning pairs and widths (the advanceWidth for each glyph).

Here, an image to show the result:

The code below in JavaScript dumps the GPOS kerning table into the string text, presenting a list of sets containing the second character and the kern value in each line, while the first character of the pair appears as a Java character at the beginning of the line. Notice, that glyph indexes are avoided by using the ASCII codes of the characters.

This only dumps ' '(space) to '}', which is what is useful for English language. To expand to other characters just use Unicode.

<!-- indoc: true -> writes in HTML on this page  -->
const indoc = true;
const nl = (indoc) ? "<br>" : "\n";
var chars = font.tables.cmap.glyphIndexMap;
var g1,g2;
var i, j, kern;
var text = "";
for ( i = 32; i < 126; i++ ) {
    g1 = font.glyphs.get(chars[i]);
    text += "'" +
    (( i == 39 || i == 92) ? "\\" + String.fromCharCode(i) : String.fromCharCode(i) )+ "'";
    for ( j = 32; j < 126; j++ ) {
        g2 = font.glyphs.get(chars[j]);
        if ( (kern = font.getKerningValue(g1,g2)) !== 0 ) {
            text += ", { '" +
            (( j == 39 || j == 92) ? "\\" + String.fromCharCode(j) : String.fromCharCode(j) )+
            "', " + kern + " }";
        }
    }
    text += nl;
}

这篇关于如何使用Opentype字体从GPOS表中使用字距调整对并从中提取字距调整对,以在Java中将字形正确显示为Path2D?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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