Skip to content

Instantly share code, notes, and snippets.

@Saqoosha
Created August 21, 2015 16:32
Show Gist options
  • Save Saqoosha/b557906eae258120ab47 to your computer and use it in GitHub Desktop.
Save Saqoosha/b557906eae258120ab47 to your computer and use it in GitHub Desktop.
OpenType フォントのカーニング情報をぶっこぬく ref: http://qiita.com/Saqoosha/items/8a9bb825e02db770408e
(OTF
(OffsetTable
(sfnt-version 20308.21583)
(numTables 25)
(searchRange 256)
(enterSelector 4)
(rangeShift 384))
(Table 0 (tag "BASE" #x42415345)
(checkSum 6962C672) (offset #x00000430) (length: #x000001C8))
(Table 1 (tag "CFF " #x43464620)
(checkSum 0BDFCA60) (offset #x0034700C) (length: #x0080F295))
(Table 2 (tag "EBDT" #x45424454)
(checkSum E109E7DA) (offset #x00213B60) (length: #x001334AA))
(Table 3 (tag "EBLC" #x45424C43)
(checkSum 81D5AE36) (offset #x00002A58) (length: #x0001064C))
(Table 4 (tag "GPOS" #x47504F53)
(checkSum D6E4B8CC) (offset #x00036E04) (length: #x00015098))
(Table 5 (tag "GSUB" #x47535542)
...
#include <iostream>
#include "otf.h"
#include <ft2build.h>
#include FT_FREETYPE_H
int glyph_contains(OTF_Coverage *coverage, OTF_GlyphID glyph_id) {
if (coverage->CoverageFormat == 1) {
for (int i = 0; i < coverage->Count; i++) {
if (coverage->table.GlyphArray[i] == glyph_id) {
return i;
}
}
} else if (coverage->CoverageFormat == 2) {
for (int i = 0; i < coverage->Count; i++) {
OTF_RangeRecord *range = coverage->table.RangeRecord + i;
for (int j = range->Start; j <= range->End; j++) {
if (j == glyph_id) {
return j;
}
}
}
}
// ふくまれてない
return -1;
}
OTF_PairValueRecord *get_pair_set(OTF_LookupSubTableGPOS *sub_table, OTF_GlyphID left, OTF_GlyphID right) {
// printf("Coverage Format: %d, Count: %d, left: %d, right: %d\n", sub_table->Coverage.CoverageFormat,
// sub_table->Coverage.Count, glyph_contains(&sub_table->Coverage, left), glyph_contains(&sub_table->Coverage,
// right));
int pair_set_index = glyph_contains(&sub_table->Coverage, left);
if (pair_set_index < 0) {
// この sub table には left の情報無い
return NULL;
}
OTF_PairSet *pair_set = &sub_table->u.pair1.PairSet[pair_set_index];
for (int i = 0; i < pair_set->PairValueCount; i++) {
if (pair_set->PairValueRecord[i].SecondGlyph == right) {
return &pair_set->PairValueRecord[i];
}
}
// right との情報無い
return NULL;
}
int get_kerning_value(OTF *otf, OTF_GlyphString *gstring) {
char name[5];
OTF_Tag kern = OTF_tag("kern");
// OTF_Tag palt = OTF_tag("palt");
// よくわからんので最初の Script
OTF_LangSys *lang_sys = &otf->gpos->ScriptList.Script[0].DefaultLangSys;
for (int i = 0; i < lang_sys->FeatureCount; i++) {
int featureIndex = lang_sys->FeatureIndex[i];
OTF_Feature *feature = &otf->gpos->FeatureList.Feature[featureIndex];
OTF_tag_name(feature->FeatureTag, name);
// printf("%d: %d, %s\n", i, featureIndex, name);
if (feature->FeatureTag != kern) continue;
// LookupListIndex ながさ 1 なので最初のやつ。複数はいってることってあるの?
unsigned int lookupIndex = feature->LookupListIndex[0];
// printf("%i: %s, %d\n", i, name, lookupIndex);
// このへんもリストの最初だけ
OTF_PairValueRecord *value = get_pair_set(&otf->gpos->LookupList.Lookup[lookupIndex].SubTable.gpos[0], gstring->glyphs[0].glyph_id, gstring->glyphs[1].glyph_id);
if (value) {
// XAdvance 以外に値はいってることあるの?
return value->Value1.XAdvance;
}
}
return 0;
}
int main(int argc, const char *argv[]) {
OTF *otf = OTF_open("/Library/Fonts/ヒラギノ明朝 Pro W6.otf");
OTF_get_table(otf, "GPOS");
OTF_GlyphString gstring;
gstring.size = 2;
gstring.used = 2;
gstring.glyphs = (OTF_Glyph *)calloc(gstring.size, sizeof(OTF_Glyph));
gstring.glyphs[0].c = 0x3042; // あ
gstring.glyphs[1].c = 0x3062; // ぢ
OTF_drive_cmap(otf, &gstring);
printf("Left glyph=0x%04x, Right glyph=0x%04x\n", gstring.glyphs[0].glyph_id, gstring.glyphs[1].glyph_id);
int kerning_value = get_kerning_value(otf, &gstring);
printf("Kerning value=%d\n", kerning_value);
free(gstring.glyphs);
OTF_close(otf);
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment