def runHB(direction, script, language, features, text, fontname, positions): font = getHbFont(fontname) buf = HarfBuzz.buffer_create() text = toUnicode(text) HarfBuzz.buffer_add_utf8(buf, text.encode('utf-8'), 0, -1) HarfBuzz.buffer_set_direction(buf, HarfBuzz.direction_from_string(toBytes(direction))) HarfBuzz.buffer_set_script(buf, HarfBuzz.script_from_string(toBytes(script))) if language: HarfBuzz.buffer_set_language(buf, HarfBuzz.language_from_string(toBytes(language))) if features: features = [HarfBuzz.feature_from_string(toBytes(fea))[1] for fea in features.split(',')] else: features = [] HarfBuzz.shape(font, buf, features) info = HarfBuzz.buffer_get_glyph_infos(buf) ttfont = getTtFont(fontname) if positions: pos = HarfBuzz.buffer_get_glyph_positions(buf) glyphs = [] for i, p in zip(info, pos): glyph = ttfont.getGlyphName(i.codepoint) if p.x_offset or p.y_offset: glyph += "@%d,%d" % (p.x_offset, p.y_offset) glyph += "+%d" % p.x_advance if p.y_advance: glyph += ",%d" % p.y_advance glyphs.append(glyph) out = "|".join(glyphs) else: out = "|".join([ttfont.getGlyphName(i.codepoint) for i in info]) return "[%s]" % out
def glyph_metrics(string: str) -> Iterable[Metrics]: font, upem, buffer = setup_harfbuzz() HarfBuzz.buffer_clear_contents(buffer) if False: HarfBuzz.buffer_add_utf8(buffer, string.encode("utf-8"), 0, -1) elif sys.maxunicode == 0x10FFFF: HarfBuzz.buffer_add_utf32( buffer, array.array("I", string.encode("utf-32"))[1:], 0, -1) else: HarfBuzz.buffer_add_utf16( buffer, array.array("H", string.encode("utf-16"))[1:], 0, -1) # If this doesn't get run, the Python interpreter crashes HarfBuzz.buffer_guess_segment_properties(buffer) HarfBuzz.shape(font, buffer, []) codepoints = [ info.codepoint for info in HarfBuzz.buffer_get_glyph_infos(buffer) ] positions = HarfBuzz.buffer_get_glyph_positions(buffer) for extents, pos in zip(glyphs_extents(font, codepoints), positions): yield Metrics( Positions(pos.x_advance, pos.y_advance, pos.x_offset, pos.y_offset), extents, upem, )
def runHB(text, buf, font, ttfont): HarfBuzz.buffer_clear_contents(buf) HarfBuzz.buffer_add_utf8(buf, text.encode('utf-8'), 0, -1) HarfBuzz.buffer_set_direction(buf, HarfBuzz.direction_t.RTL) HarfBuzz.buffer_set_script(buf, HarfBuzz.script_t.ARABIC) HarfBuzz.buffer_set_language(buf, HarfBuzz.language_from_string(b"ar")) HarfBuzz.shape(font, buf, []) info = HarfBuzz.buffer_get_glyph_infos(buf) out = "|".join([ttfont.getGlyphName(i.codepoint) for i in info]) return "[%s]" % out
def shape(text, font): text = toUnicode(text) buf = HarfBuzz.buffer_create() HarfBuzz.buffer_add_utf8(buf, text.encode('utf-8'), 0, -1) HarfBuzz.buffer_set_direction(buf, HarfBuzz.direction_t.RTL) HarfBuzz.buffer_set_script(buf, HarfBuzz.script_t.ARABIC) HarfBuzz.buffer_set_language(buf, HarfBuzz.language_from_string("ar")) HarfBuzz.shape(font, buf, [HarfBuzz.feature_from_string("+ss01")[1]]) glyphs = HarfBuzz.buffer_get_glyph_infos(buf) positions = HarfBuzz.buffer_get_glyph_positions(buf) return [(g.codepoint, p.x_advance, p.x_offset, p.y_offset) for g, p in zip(glyphs, positions)]
def shape(self, text_="abvd", flag=False): text = text_ # Need to create GLib.Bytes explicitly until this bug is fixed: # https://bugzilla.gnome.org/show_bug.cgi?id=729541 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) ## ## Add text to buffer ## # # See https://github.com/harfbuzz/harfbuzz/pull/271 # if flag: # If you do not care about cluster values reflecting Python # string indices, then this is quickest way to add text to # buffer: # void hb_buffer_add_utf8 (hb_buffer_t *buffer, # const char *text, # int text_length, # unsigned int item_offset, # int item_length); hb.buffer_add_utf8(buf, text.encode('utf-8'), 0, -1) # Otherwise, then following handles both narrow and wide # Python builds: elif sys.maxunicode == 0x10FFFF: hb.buffer_add_utf32(buf, array.array('I', text.encode('utf-32le')), 0, -1) else: hb.buffer_add_utf16(buf, array.array('H', text.encode('utf-16le')), 0, -1) hb.buffer_guess_segment_properties(buf) hb.shape(self.__font, buf, []) # del font infos = hb.buffer_get_glyph_infos(buf) # positions = hb.buffer_get_glyph_positions(buf) return [info.codepoint for info in infos]
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 runHB(text, buf, font, ttfont): HarfBuzz.buffer_clear_contents(buf) HarfBuzz.buffer_add_utf8(buf, text.encode('utf-8'), 0, -1) HarfBuzz.buffer_set_direction(buf, HarfBuzz.direction_t.RTL) HarfBuzz.buffer_set_script(buf, HarfBuzz.script_t.ARABIC) HarfBuzz.buffer_set_language(buf, HarfBuzz.language_from_string(b"ar")) HarfBuzz.shape(font, buf, []) info = HarfBuzz.buffer_get_glyph_infos(buf) positions = HarfBuzz.buffer_get_glyph_positions(buf) out = [] for i, p in zip(info, positions): text = "" text += ttfont.getGlyphName(i.codepoint) text += " w=%d" % p.x_advance if p.x_offset: text += " x=%d" % p.x_offset if p.y_offset: text += " y=%d" % p.y_offset out.append(text) return "[%s]" % "|".join(out)
debugger = Debugger() hb.buffer_set_message_func(buf, debugger.message, 1, 0) ## ## Add text to buffer ## # # See https://github.com/harfbuzz/harfbuzz/pull/271 # if False: # If you do not care about cluster values reflecting Python # string indices, then this is quickest way to add text to # buffer: hb.buffer_add_utf8(buf, text.encode('utf-8'), 0, -1) # Otherwise, then following handles both narrow and wide # Python builds: elif sys.maxunicode == 0x10FFFF: hb.buffer_add_utf32(buf, array.array('I', text.encode('utf-32')), 0, -1) else: hb.buffer_add_utf16(buf, array.array('H', text.encode('utf-16')), 0, -1) hb.buffer_guess_segment_properties(buf) hb.shape(font, buf, []) del font infos = hb.buffer_get_glyph_infos(buf) positions = hb.buffer_get_glyph_positions(buf)
print(msg) return True debugger = Debugger() hb.buffer_set_message_func (buf, debugger.message, 1, 0) ## ## Add text to buffer ## # # See https://github.com/harfbuzz/harfbuzz/pull/271 # if False: # If you do not care about cluster values reflecting Python # string indices, then this is quickest way to add text to # buffer: hb.buffer_add_utf8 (buf, text.encode('utf-8'), 0, -1) # Otherwise, then following handles both narrow and wide # Python builds: elif sys.maxunicode == 0x10FFFF: hb.buffer_add_utf32 (buf, array.array('I', text.encode('utf-32')), 0, -1) else: hb.buffer_add_utf16 (buf, array.array('H', text.encode('utf-16')), 0, -1) hb.buffer_guess_segment_properties (buf) hb.shape (font, buf, []) del font infos = hb.buffer_get_glyph_infos (buf) positions = hb.buffer_get_glyph_positions (buf)
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) hb.buffer_add_utf8(buf, text.encode("utf-8"), 0, -1) hb.buffer_guess_segment_properties(buf) hb.shape(font, buf, []) del font infos = hb.buffer_get_glyph_infos(buf) positions = hb.buffer_get_glyph_positions(buf) for info, pos in zip(infos, positions): gid = info.codepoint cluster = info.cluster x_advance = pos.x_advance x_offset = pos.x_offset y_offset = pos.y_offset