def buildCompatChars(sfd, ttf): zwj = u'\u200D' ranges = ( (0xfb50, 0xfbb1), (0xfbd3, 0xfd3d), (0xfd50, 0xfdf9), (0xfdfc, 0xfdfc), (0xfe70, 0xfefc), ) with open(ttf, "rb") as f: data = f.read() blob = HarfBuzz.glib_blob_create(GLib.Bytes.new(data)) face = HarfBuzz.face_create(blob, 0) hbfont = HarfBuzz.font_create(face) upem = HarfBuzz.face_get_upem(face) HarfBuzz.font_set_scale(hbfont, upem, upem) HarfBuzz.ot_font_set_funcs(hbfont) ttfont = TTFont(ttf) for r in ranges: for c in range(r[0], r[1] + 1): dec = ucd.decomposition(unichr(c)).split() if dec: keyword = dec[0] text = u'' for i in dec[1:]: text += unichr(int(str(i), 16)) if keyword == '<initial>': text = text + zwj elif keyword == '<final>': text = zwj + text elif keyword == '<medial>': text = zwj + text + zwj components = shape(text, hbfont) if components: glyph = sfd.createChar(c) glyph.clear() glyph.color = 0xff0000 # red color x = 0 for component in components: gid = component[0] name = ttfont.getGlyphName(gid) x_advance = component[1] x_offset = component[2] y_offset = component[3] matrix = psMat.translate(x + x_offset, y_offset) # ignore blank glyphs, e.g. space or ZWJ if sfd[name].foreground or sfd[name].references: glyph.addReference(name, matrix) x += x_advance glyph.width = x
def setup_harfbuzz() -> Tuple[HarfBuzz.font_t, HarfBuzz.buffer_t]: """ Finds a font for HarfBuzz to use, and creates a buffer Because this is wrapped with functools.lru_cache, the buffer returned may have text still in it, which means gi.repository.HarfBuzz.buffer_clear_contents() will need to be called on the buffer to return it to its empty state """ font_file = get_font_file() font_blob = HarfBuzz.glib_blob_create( GLib.Bytes.new(font_file.read_bytes())) face = HarfBuzz.face_create(font_blob, 0) del font_blob font = HarfBuzz.font_create(face) upem = HarfBuzz.face_get_upem(face) del face HarfBuzz.font_set_scale(font, 100, 100) HarfBuzz.ot_font_set_funcs(font) buffer = HarfBuzz.buffer_create() # HarfBuzz.buffer_set_message_func( # buffer, # lambda *args: True, # 1, # 0, # ) return (font, upem, buffer)
def buildCompatChars(sfd, ttf): zwj = u'\u200D' ranges = ( (0xfb50, 0xfbb1), (0xfbd3, 0xfd3d), (0xfd50, 0xfdf9), (0xfdfc, 0xfdfc), (0xfe70, 0xfefc), ) with open(ttf, "rb") as f: data = f.read() blob = HarfBuzz.glib_blob_create(GLib.Bytes.new(data)) face = HarfBuzz.face_create(blob, 0) hbfont = HarfBuzz.font_create(face) upem = HarfBuzz.face_get_upem(face) HarfBuzz.font_set_scale(hbfont, upem, upem) HarfBuzz.ot_font_set_funcs(hbfont) ttfont = TTFont(ttf) for r in ranges: for c in range(r[0], r[1]+1): dec = ucd.decomposition(unichr(c)).split() if dec: keyword = dec[0] text = u'' for i in dec[1:]: text += unichr(int(str(i),16)) if keyword == '<initial>': text = text + zwj elif keyword == '<final>': text = zwj + text elif keyword == '<medial>': text = zwj + text + zwj components = shape(text, hbfont) if components: glyph = sfd.createChar(c) glyph.clear() glyph.color = 0xff0000 # red color x = 0 for component in components: gid = component[0] name = ttfont.getGlyphName(gid) x_advance = component[1] x_offset = component[2] y_offset = component[3] matrix = psMat.translate(x + x_offset, y_offset) # ignore blank glyphs, e.g. space or ZWJ if sfd[name].foreground or sfd[name].references: glyph.addReference(name, matrix) x += x_advance glyph.width = x
def getHbFont(fontname): font = open(fontname, "rb") data = font.read() font.close() blob = HarfBuzz.glib_blob_create(GLib.Bytes.new(data)) face = HarfBuzz.face_create(blob, 0) font = HarfBuzz.font_create(face) upem = HarfBuzz.face_get_upem(face) HarfBuzz.font_set_scale(font, upem, upem) HarfBuzz.ot_font_set_funcs(font) return font
def get_text_shape(text, font=None, weight=None, path=None, debug=False): if weight is not None: font = f'{font}:{weight}' if path is None: path = get_font_path(font) base, ext = os.path.splitext(path) ext = ext[1:] with open(path, 'rb') as fid: fontdata = fid.read() bdata = GLib.Bytes.new(fontdata) blob = hb.glib_blob_create(bdata) face = hb.face_create(blob, 0) font = hb.font_create(face) upem = hb.face_get_upem(face) hb.font_set_scale(font, upem, upem) # hb.font_set_ptem(font, font_size) if ext == 'woff': hb.ft_font_set_funcs(font) buf = hb.buffer_create() hb.buffer_add_utf8(buf, text.encode('utf-8'), 0, -1) hb.buffer_guess_segment_properties(buf) hb.shape(font, buf, []) infos = hb.buffer_get_glyph_infos(buf) positions = hb.buffer_get_glyph_positions(buf) extents = [hb.font_get_glyph_extents(font, i.codepoint) for i in infos] if debug: return font, infos, positions, extents norm = upem wh_extract = lambda ext: (ext.extents.width / norm, -ext.extents.height / norm) cluster = [(i.codepoint, i.cluster) for i in infos] shapes = [wh_extract(e) for e in extents] deltas = [(p.x_advance / norm, p.y_advance / norm) for p in positions] offsets = [(p.x_offset / norm, p.y_offset / norm) for p in positions] return cluster, shapes, deltas, offsets
def main(): font_file = barcode_wheel.get_font_file() font_blob = HarfBuzz.glib_blob_create(GLib.Bytes.new(font_file.read_bytes())) face = HarfBuzz.face_create(font_blob, 0) del font_blob font = HarfBuzz.font_create(face) upem = HarfBuzz.face_get_upem(face) del face HarfBuzz.font_set_scale(font, upem, upem) text = sys.argv[1] HarfBuzz.ot_font_set_funcs(font) buf = HarfBuzz.buffer_create() HarfBuzz.buffer_set_message_func( buf, # lambda *args: [print(x) for x in args] and True, lambda *args: True, 1, 0, ) if False: HarfBuzz.buffer_add_utf8(buf, text.encode("utf-8"), 0, -1) elif sys.maxunicode == 0x10FFFF: HarfBuzz.buffer_add_utf32( buf, array.array("I", text.encode("utf-32"))[1:], 0, -1 ) else: HarfBuzz.buffer_add_utf16( buf, array.array("H", text.encode("utf-16"))[1:], 0, -1 ) HarfBuzz.buffer_guess_segment_properties(buf) HarfBuzz.shape(font, buf, []) del font infos = HarfBuzz.buffer_get_glyph_infos(buf) positions = HarfBuzz.buffer_get_glyph_positions(buf) for info, pos in zip(infos, positions): gid = info.codepoint cluster = info.cluster print(f"gid {gid} = {cluster} @ {pos.x_advance}, {pos.x_offset}+{pos.y_offset}")
def __init__(self, font_path): try: assert os.path.isfile(font_path) font_file = open(font_path, "br") fontdata = font_file.read() blob = hb.glib_blob_create(GLib.Bytes.new(fontdata)) del fontdata face = hb.face_create(blob, 0) del blob self.__font = hb.font_create(face) upem = hb.face_get_upem(face) del face font_file.close() hb.font_set_scale(self.__font, upem, upem) #hb.ft_font_set_funcs (font) hb.ot_font_set_funcs(self.__font) except Exception: print(font_path)
unicode = str def tounicode(s, encoding='utf-8'): if not isinstance(s, unicode): return s.decode(encoding) else: return s fontdata = open(sys.argv[1], 'rb').read() text = tounicode(sys.argv[2]) # Need to create GLib.Bytes explicitly until this bug is fixed: # https://bugzilla.gnome.org/show_bug.cgi?id=729541 blob = hb.glib_blob_create(GLib.Bytes.new(fontdata)) face = hb.face_create(blob, 0) del blob font = hb.font_create(face) upem = hb.face_get_upem(face) del face hb.font_set_scale(font, upem, upem) #hb.ft_font_set_funcs (font) hb.ot_font_set_funcs(font) buf = hb.buffer_create() class Debugger(object): def message(self, buf, font, msg, data, _x_what_is_this): print(msg) return True
unicode except NameError: unicode = str def tounicode(s, encoding='utf-8'): if not isinstance(s, unicode): return s.decode(encoding) else: return s fontdata = open (sys.argv[1], 'rb').read () text = tounicode(sys.argv[2]) # Need to create GLib.Bytes explicitly until this bug is fixed: # https://bugzilla.gnome.org/show_bug.cgi?id=729541 blob = hb.glib_blob_create (GLib.Bytes.new (fontdata)) face = hb.face_create (blob, 0) del blob font = hb.font_create (face) upem = hb.face_get_upem (face) del face hb.font_set_scale (font, upem, upem) #hb.ft_font_set_funcs (font) hb.ot_font_set_funcs (font) buf = hb.buffer_create () class Debugger(object): def message (self, buf, font, msg, data, _x_what_is_this): print(msg) return True debugger = Debugger() hb.buffer_set_message_func (buf, debugger.message, 1, 0)
def _hb_face_from_path(filepath): with open(filepath, 'rb') as fi: fontdata = fi.read() return hb.face_create(hb.glib_blob_create(Bytes.new(fontdata)), 0)