Skip to content

Instantly share code, notes, and snippets.

@celestialphineas
Created January 30, 2021 04:00
Show Gist options
  • Save celestialphineas/4d20fae0d54c2ebbbb7f98a127cee7b9 to your computer and use it in GitHub Desktop.
Save celestialphineas/4d20fae0d54c2ebbbb7f98a127cee7b9 to your computer and use it in GitHub Desktop.
Generate otfcc font dump out of a folder of images
{
"head": {
"version": 1.0,
"fontRevision": 1.0,
"flags": {
"baselineAtY_0": true,
"alwaysUseIntegerSize": true
},
"unitsPerEm": 1000,
"macStyle": {},
"lowestRecPPEM": 8,
"indexToLocFormat": 0,
"glyphDataFormat": 0
},
"hhea": {
"version": 1.0,
"ascender": 850,
"descender": -150,
"lineGap": 0,
"caretSlopeRise": 1,
"caretSlopeRun": 0,
"caretOffset": 0
},
"vhea": {
"version": 1.0,
"ascent": 500,
"descent": -500,
"lineGap": 0,
"caretSlopeRise": 0,
"caretSlopeRun": 1,
"caretOffset": 0
},
"post": {
"version": 3.0,
"italicAngle": 0,
"underlinePosition": -100,
"underlineThickness": 50,
"isFixedPitch": false
},
"OS_2": {
"version": 3,
"usWeightClass": 400,
"usWidthClass": 5,
"fsType": {},
"ySubscriptXSize": 650,
"ySubscriptYSize": 600,
"ySubscriptXOffset": 0,
"ySubscriptYOffset": 75,
"ySupscriptXSize": 650,
"ySupscriptYSize": 600,
"ySupscriptXOffset": 0,
"ySupscriptYOffset": 350,
"yStrikeoutSize": 45,
"yStrikeoutPosition": 250,
"sFamilyClass": 0,
"panose": [
2,
0,
0,
0,
0,
0,
0,
0,
0,
0
],
"ulUnicodeRange2": {
"CJK_Compatibility": true,
"CJK_Unified_Ideographs": true
},
"achVendID": "TEST",
"fsSelection": {
"regular": true
},
"usFirstCharIndex": 32,
"usLastCharIndex": 65509,
"sTypoAscender": 850,
"sTypoDescender": -150,
"sTypoLineGap": 1000,
"usWinAscent": 861,
"usWinDescent": 220,
"ulCodePageRange1": {
"latin1": true,
"latin2": true,
"gbk": true
},
"ulCodePageRange2": {},
"sxHeight": 480,
"sCapHeight": 700,
"usDefaultChar": 0,
"usBreakChar": 32,
"usMaxContext": 1,
"usLowerOpticalPointSize": 0,
"usUpperOpticalPointSize": 0
},
"name": [
{
"platformID": 1,
"encodingID": 0,
"languageID": 0,
"nameID": 0,
"nameString": "${COPYRIGHT}"
},
{
"platformID": 1,
"encodingID": 0,
"languageID": 0,
"nameID": 1,
"nameString": "${FONTNAME}"
},
{
"platformID": 1,
"encodingID": 0,
"languageID": 0,
"nameID": 2,
"nameString": "Regular"
},
{
"platformID": 1,
"encodingID": 0,
"languageID": 0,
"nameID": 3,
"nameString": "${FONTIDENTIFIER}"
},
{
"platformID": 1,
"encodingID": 0,
"languageID": 0,
"nameID": 4,
"nameString": "${FONTNAME}"
},
{
"platformID": 1,
"encodingID": 0,
"languageID": 0,
"nameID": 5,
"nameString": "Version 1.00"
},
{
"platformID": 1,
"encodingID": 0,
"languageID": 0,
"nameID": 6,
"nameString": "${FONTIDENTIFIER}"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 1033,
"nameID": 0,
"nameString": "${COPYRIGHT}"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 1033,
"nameID": 1,
"nameString": "${FONTNAME}"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 1033,
"nameID": 2,
"nameString": "Regular"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 1033,
"nameID": 3,
"nameString": "${FONTIDENTIFIER}"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 1033,
"nameID": 4,
"nameString": "${FONTNAME}"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 1033,
"nameID": 5,
"nameString": "Version 1.00"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 1033,
"nameID": 6,
"nameString": "${FONTIDENTIFIER}"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 2052,
"nameID": 0,
"nameString": "${COPYRIGHT}"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 2052,
"nameID": 1,
"nameString": "${FONTNAME_ZH}"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 2052,
"nameID": 2,
"nameString": "Regular"
},
{
"platformID": 3,
"encodingID": 1,
"languageID": 2052,
"nameID": 4,
"nameString": "${FONTNAME_ZH}"
}
],
"cmap": {
"U+0020": "space"
},
"CFF_": {
"isCID": true,
"${FONTNAME}": "${FONTIDENTIFIER}",
"fullName": "${FONTIDENTIFIER}",
"cidRegistry": "Adobe",
"cidOrdering": "Identity",
"cidSupplement": 0,
"fdArray": {
"${FONTIDENTIFIER}": {
"privates": {
"defaultWidthX": 1000.0,
"nominalWidthX": 853
}
}
}
},
"glyf": {
".notdef": {
"advanceWidth": 1000,
"advanceHeight": 1000,
"verticalOrigin": 850,
"CFF_fdSelect": "${FONTIDENTIFIER}",
"CFF_CID": 0
},
"space": {
"advanceWidth": 300
}
}
}
import json
import potrace
import numpy as np
from skimage import io, transform
def trace(filename, baseline=150, upm=1000):
img = io.imread(filename)
if len(img.shape) > 2: img = img[:,:,0]
h, w = img.shape
resized = transform.resize(img, (int(upm), int(upm/h*w))) < 0.5
bmp = potrace.Bitmap(resized)
path = bmp.trace()
contours = []
for curve in path:
contour = []
for segment in curve:
if not segment.is_corner:
contour.insert(0, {
'x': int(segment.c1[0] + 0.5),
'y': int(upm - segment.c1[1] - int(baseline) + 0.5),
'on': False
})
contour.insert(0, {
'x': int(segment.c2[0] + 0.5),
'y': int(upm - segment.c2[1] - int(baseline) + 0.5),
'on': False
})
contour.insert(0, {
'x': int(segment.end_point[0] + 0.5),
'y': int(upm - segment.end_point[1] - int(baseline) + 0.5),
'on': True
})
contours.append(contour)
return contours
def build_font(glyph_dict, copyright='Copyright 2021 Next Lab',
fontname='Test font', fontname_zh='测试字体', font_identifier='TESTFONT'):
font_base = open('base.json').read()
font_base = font_base.replace('${COPYRIGHT}', copyright)
font_base = font_base.replace('${FONTNAME}', fontname)
font_base = font_base.replace('${FONTNAME_ZH}', fontname_zh)
font_base = font_base.replace('${FONTIDENTIFIER}', font_identifier)
font_obj = json.loads(font_base)
for unicode in glyph_dict:
upper = unicode.upper()
contours = glyph_dict[unicode]
font_obj['cmap']['U+'+ upper] = 'uni' + upper
font_obj['glyf']['uni' + upper] = {
'advanceWidth': 1000,
'advanceHeight': 1000,
'verticalOrigin': 850,
'CFF_fdSelect': font_identifier,
'CFF_CID': 0,
'contours': contours
}
return font_obj
import os
import multiprocessing as mp
files = os.listdir('yan')
if __name__ == '__main__':
manager = mp.Manager()
glyph_dict = manager.dict()
def process(filename):
char = filename.split('_')[1][0]
unicode = '%X' % ord(char)
glyph_dict[unicode] = trace('yan/' + filename)
with mp.Pool(processes=8) as p:
p.map(process, files)
out_file = open('export.json', 'w')
json.dump(
build_font(glyph_dict.copy(), fontname='Next Lab Yan', font_identifier='NextLabYan', fontname_zh='Next Lab 颜体'),
out_file
)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment