Пример #1
0
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)
Пример #2
0
 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
Пример #3
0
  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
Пример #4
0
 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
Пример #5
0
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
Пример #6
0
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
Пример #7
0
    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
Пример #8
0
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
Пример #9
0
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
Пример #10
0
    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
Пример #11
0
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
Пример #12
0
 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)
Пример #13
0
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
Пример #14
0
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
Пример #15
0
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)
Пример #17
0
 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
Пример #18
0
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
Пример #19
0
def getShapeFuncForSkiaTypeface(skTypeface):
    face = makeHBFaceFromSkiaTypeface(skTypeface)
    font = hb.Font(face)
    return functools.partial(_shape, face, font)
Пример #20
0
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