def shaping_string(fontdata, glyphOrder, text, language=None): face = hb.Face(fontdata) font = hb.Font(face) upem = face.upem font.scale = (upem, upem) hb.ot_font_set_funcs(font) buf = hb.Buffer() buf.add_str(text) buf.guess_segment_properties() if language: buf.language = language features = {"kern": True, "liga": True} hb.shape(font, buf, features) infos = buf.glyph_infos positions = buf.glyph_positions outs = [] for info, pos in zip(buf.glyph_infos, buf.glyph_positions): name = glyphOrder[info.codepoint] if name in ignorables: continue outs.append("%s=%i" % (name, info.cluster)) if pos.position[0] != 0 or pos.position[1] != 0: outs[-1] = outs[-1] + "<%i,%i>" % (pos.position[0], pos.position[1]) return "|".join(outs)
def prepare_shaper(self): face = hb.Face(self.fontdata) font = hb.Font(face) upem = face.upem font.scale = (upem, upem) hb.ot_font_set_funcs(font) self.hbfont = font
def pair_kerning(self, left, right): """The kerning between two glyphs (specified by name), in font units.""" if self.face.has_kerning: return (self.face.get_kerning(left, right).x >> 6) * self.scale_factor else: if not self.hbFont: with open(self.filename, "rb") as fontfile: fontdata = fontfile.read() face = hb.Face(fontdata) font = hb.Font(face) scale = face.upem * self.scale_factor font.scale = (scale, scale) self.hbFont = font buf = hb.Buffer() buf.add_str(left+right) buf.guess_segment_properties() hb.shape(self.hbFont, buf, {"kern":True}) pos = buf.glyph_positions[0].x_advance buf = hb.Buffer() buf.add_str(left+right) buf.guess_segment_properties() hb.shape(self.hbFont, buf, {"kern":False}) pos2 = buf.glyph_positions[0].x_advance return pos-pos2
def hbfont(self): if self._hbfont: return self._hbfont if self.is_vertical: return self.horizontal_font.hbfont byte_array = self.byte_array hbface = hb.Face(byte_array, self.font_index or 0) self._hbfont = hb.Font(hbface) return self._hbfont
def ttf_font(ttf_path): with open(ttf_path, 'rb') as font_file: font_data = font_file.read() face = hb.Face(font_data) font = hb.Font(face) upem = face.upem font.scale = (upem, upem) hb.ot_font_set_funcs(font) return font
def opensans(): """Return a subset of OpenSans.ttf containing the following glyphs/characters: [ {gid=0, name=".notdef"}, {gid=1, name="A", code=0x41}, ] """ face = hb.Face(OPEN_SANS_TTF_PATH.read_bytes()) font = hb.Font(face) return font
def __init__(self, writer: BasePdfFileWriter, font_handle, font_size, features=None, ot_language_tag=None, ot_script_tag=None, writing_direction=None, bcp47_lang_code=None, obj_stream=None): # harfbuzz expects bytes font_handle.seek(0) font_bytes = font_handle.read() font_handle.seek(0) face = hb.Face(font_bytes) self.font_size = font_size self.hb_font = hb.Font(face) self.tt = tt = ttLib.TTFont(font_handle) base_ps_name = _read_ps_name(tt) super().__init__( writer, base_ps_name, embedded_subset=True, obj_stream=obj_stream ) self._font_ref = writer.allocate_placeholder() try: cff = self.tt['CFF '] self.cff_charset = cff.cff[0].charset # CFF font programs are embedded differently # (in a more Adobe-native way) self.cidfont_obj = cidfont_obj = CIDFontType0( tt, base_ps_name, self.subset_prefix ) self.use_raw_gids = cidfont_obj.use_raw_gids except KeyError: self.cff_charset = None self.use_raw_gids = True self.cidfont_obj = CIDFontType2( tt, base_ps_name, self.subset_prefix ) self.features = features # the 'head' table is mandatory self.units_per_em = tt['head'].unitsPerEm self._glyphs = {} self._glyph_set = tt.getGlyphSet(preferCFF=True) self._cid_to_unicode = {} self.__reverse_cmap = None self.ot_language_tag = _check_ot_tag(ot_language_tag) self.ot_script_tag = _check_ot_tag(ot_script_tag) if writing_direction is not None and \ writing_direction not in ('ltr', 'rtl', 'ttb', 'btt'): raise ValueError( "Writing direction must be one of 'ltr', 'rtl', 'ttb' or 'btt'." ) self.writing_direction = writing_direction self.bcp47_lang_code = bcp47_lang_code self._subset_created = self._write_prepared = False
def latest_ttf(latest_ttf_path): """HB Font from latest TTF""" with open(latest_ttf_path, 'rb') as font_file: font_data = font_file.read() face = hb.Face(font_data) font = hb.Font(face) upem = face.upem font.scale = (upem, upem) hb.ot_font_set_funcs(font) return font
def opensans(): """Return a subset of OpenSans.ttf containing the following glyphs/characters: [ {gid=0, name=".notdef"}, {gid=1, name="A", code=0x41}, ] """ face = hb.Face(OPEN_SANS_TTF_PATH.read_bytes()) font = hb.Font(face) upem = face.upem font.scale = (upem, upem) hb.ot_font_set_funcs(font) return font
def __init__(self, fontData, *, fontNumber=0, getGlyphNameFromCodePoint=None, getHorizontalAdvance=None, getVerticalAdvance=None, getVerticalOrigin=None, ttFont=None): self._fontData = fontData self._fontNumber = fontNumber self.face = hb.Face(fontData, fontNumber) self.font = hb.Font(self.face) if ttFont is None: f = io.BytesIO(self._fontData) ttFont = TTFont(f, fontNumber=self._fontNumber, lazy=True) self._ttFont = ttFont self.glyphOrder = ttFont.getGlyphOrder() if getGlyphNameFromCodePoint is None and getHorizontalAdvance is not None: def _getGlyphNameFromCodePoint(cmap, codePoint): return cmap.get(codePoint) getGlyphNameFromCodePoint = functools.partial( _getGlyphNameFromCodePoint, self._ttFont.getBestCmap()) if getGlyphNameFromCodePoint is not None: assert getHorizontalAdvance is not None self.getGlyphNameFromCodePoint = getGlyphNameFromCodePoint self.getHorizontalAdvance = getHorizontalAdvance self.getVerticalAdvance = getVerticalAdvance self.getVerticalOrigin = getVerticalOrigin if getGlyphNameFromCodePoint is not None and getHorizontalAdvance is not None: self._funcs = hb.FontFuncs.create() self._funcs.set_nominal_glyph_func(_getGlyphIDFunc, self) self._funcs.set_glyph_h_advance_func(_getHorizontalAdvanceFunc, self) if getVerticalAdvance is not None: self._funcs.set_glyph_v_advance_func(_getVerticalAdvanceFunc, self) if getVerticalOrigin is not None: self._funcs.set_glyph_v_origin_func(_getVerticalOriginFunc, self) else: self._funcs = None
def blankfont(): """Return a subset of AdobeBlank.ttf containing the following glyphs/characters: [ {gid=0, name=".notdef"}, {gid=1, name="a", code=0x61}, {gid=2, name="b", code=0x62}, {gid=3, name="c", code=0x63}, {gid=4, name="d", code=0x64}, {gid=5, name="e", code=0x65}, {gid=6, name="ccedilla", code=0x62}, {gid=7, name="uni0431", code=0x0431}, # CYRILLIC SMALL LETTER BE {gid=8, name="u1F4A9", code=0x1F4A9}, # PILE OF POO ] """ face = hb.Face(ADOBE_BLANK_TTF_PATH.read_bytes()) font = hb.Font(face) return font
def __init__(self, path, ttFont=None, hbFont=None): if ttFont is not None: assert hbFont is not None assert path is None self.ttFont = ttFont else: assert hbFont is None self.ttFont = TTFont(path, lazy=True) self.axes = { axis.axisTag: (axis.minValue, axis.defaultValue, axis.maxValue) for axis in self.ttFont["fvar"].axes } if hbFont is not None: self.hbFont = hbFont else: with open(path, "rb") as f: face = hb.Face(f.read()) self.hbFont = hb.Font(face)
def pair_kerning(font, left, right): """The kerning between two glyphs (specified by name), in font units.""" with open(font, "rb") as fontfile: fontdata = fontfile.read() face = hb.Face(fontdata) font = hb.Font(face) scale = face.upem font.scale = (scale, scale) buf = hb.Buffer() buf.add_str(left + right) buf.guess_segment_properties() hb.shape(font, buf, {"kern": True}) pos = buf.glyph_positions[0].x_advance buf = hb.Buffer() buf.add_str(left + right) buf.guess_segment_properties() hb.shape(font, buf, {"kern": False}) pos2 = buf.glyph_positions[0].x_advance return pos - pos2
def get_mhbfont( ctx, path ): import uharfbuzz as HB ### NOTE import after ctx available ### cache = _get_cache( ctx ) R = cache.fonts.get( path, None ) if R != None: # ctx.log( '^myharfbuzz/get_mhbfont@334^', "font cached: {}".format( path ) ) return R #......................................................................................................... ctx.log( '^myharfbuzz/get_mhbfont@335^', "reading font: {}".format( path ) ) with open( path, 'rb' ) as fontfile: fontdata = fontfile.read() R = ctx.AttributeDict() R.face = HB.Face( fontdata ) R.font = HB.Font( R.face ) R.upem = R.face.upem R.font.scale = ( R.upem, R.upem, ) HB.ot_font_set_funcs( R.font ) #......................................................................................................... cache.fonts[ path ] = R return R
def shapeHB(text, font_name, font_size, features: Dict[str, bool] = None): font = pdfmetrics.getFont(font_name) if not isinstance(font, TTFont): # TODO make valid for all types of fonts raise RLKerningError("Not a TTF font") fontdata = font.face._ttf_data face = hb.Face(fontdata) font = hb.Font(face) # HB scales to integers in offset and advance so very big scale # will divide by SCALE_MULT to get the actual size in fractional points font.scale = (font_size * SCALE_MULT, font_size * SCALE_MULT) hb.ot_font_set_funcs(font) buf = hb.Buffer() buf.add_str(text) buf.guess_segment_properties() hb.shape(font, buf, features) return buf
def shaper(s, tf, size): face = hb.Face.create_for_tables(getSkiaFontTable, tf) font = hb.Font(face) upem = size * 64.0 font.scale = (upem, upem) hb.ot_font_set_funcs(font) buf = hb.Buffer() buf.add_utf8(s.encode('utf-8')) # buf.add_str(s) buf.guess_segment_properties() features = {"kern": True, "liga": True} # features = {} hb.shape(font, buf, features) infos = buf.glyph_infos positions = buf.glyph_positions glyphs = [info.codepoint for info in infos] positions = [(pos.x_advance / 64.0, pos.x_offset / 64.0, pos.y_offset / 64.0) for pos in positions] return (glyphs, positions)
def __init__(self, path: Path): self.path = path face = hb.Face(path.read_bytes()) # type: ignore self.font = hb.Font(face) # type: ignore hb.ot_font_set_funcs(self.font) # type: ignore
def sparsefont(): """Return a font that only has a few tables: GPOS, cmap, head, maxp and post""" face = hb.Face(SPARSE_FONT_TTF_PATH.read_bytes()) font = hb.Font(face) return font
def getShapeFuncForSkiaTypeface(skTypeface): face = makeHBFaceFromSkiaTypeface(skTypeface) font = hb.Font(face) return functools.partial(_shape, face, font)
def mutatorsans(): """Return a subset of MutatorSans-VF with a wdth and wght axis.""" face = hb.Face(MUTATOR_SANS_TTF_PATH.read_bytes()) font = hb.Font(face) return font