Ejemplo n.º 1
0
    def __init__(self,
                 path_old: Union[Path, str],
                 path_new: Union[Path, str],
                 log: bool = True) -> None:

        self.font_old = TTFont(str(path_old))
        self.font_old.cmap = {
            v: k
            for k, v in self.path_old.getBestCmap().items()
        }
        self.font_old.go = self.path_old.getGlyphOrder()
        self.font_old.path = path_old

        self.font_new = TTFont(str(path_new))
        self.font_new.cmap = self.path_new.getBestCmap()
        self.font_new.go = self.path_new.getGlyphOrder()
        self.font_new.path = path_new

        self.log = True

        self.name_map = {
            k: self.font_new.cmap.get(v)
            for k, v in self.font_old.cmap.items()
        }
        self.name_map.update({
            i: i
            for i in filter(lambda x: x in self.font_new.go, self.font_old.go)
        })
        self.incompatible_glyphs = self.get_incompatible_glyphs()
Ejemplo n.º 2
0
 def __init__(
     self,
     path_old: Union[Path, str],
     path_new: Union[Path, str],
     path_xml: Union[Path, str],
 ):
     self.font_old = TTFont(str(path_old))
     self.font_new = TTFont(str(path_new))
     self.tree = et.parse(str(path_xml))
Ejemplo n.º 3
0
def removeOverlaps(
    font: ttFont.TTFont,
    glyphNames: Optional[Iterable[str]] = None,
    removeHinting: bool = True,
) -> None:
    """Simplify glyphs in TTFont by merging overlapping contours.

    Overlapping components are first decomposed to simple contours, then merged.

    Currently this only works with TrueType fonts with 'glyf' table.
    Raises NotImplementedError if 'glyf' table is absent.

    Note that removing overlaps invalidates the hinting. By default we drop hinting
    from all glyphs whether or not overlaps are removed from a given one, as it would
    look weird if only some glyphs are left (un)hinted.

    Args:
        font: input TTFont object, modified in place.
        glyphNames: optional iterable of glyph names (str) to remove overlaps from.
            By default, all glyphs in the font are processed.
        removeHinting (bool): set to False to keep hinting for unmodified glyphs.
    """
    try:
        glyfTable = font["glyf"]
    except KeyError:
        raise NotImplementedError(
            "removeOverlaps currently only works with TTFs")

    hmtxTable = font["hmtx"]
    # wraps the underlying glyf Glyphs, takes care of interfacing with drawing pens
    glyphSet = font.getGlyphSet()

    if glyphNames is None:
        glyphNames = font.getGlyphOrder()

    # process all simple glyphs first, then composites with increasing component depth,
    # so that by the time we test for component intersections the respective base glyphs
    # have already been simplified
    glyphNames = sorted(
        glyphNames,
        key=lambda name: (
            glyfTable[name].getCompositeMaxpValues(glyfTable).maxComponentDepth
            if glyfTable[name].isComposite() else 0,
            name,
        ),
    )
    modified = set()
    for glyphName in glyphNames:
        if removeTTGlyphOverlaps(glyphName, glyphSet, glyfTable, hmtxTable,
                                 removeHinting):
            modified.add(glyphName)

    log.debug("Removed overlaps for %s glyphs:\n%s", len(modified),
              " ".join(modified))
Ejemplo n.º 4
0
    def update(self):
        glyphs_dict = {}
        font = TTFont(font_VTT_source)
        glyphs = font.getGlyphOrder()
        for glyph in glyphs:
            glyphs_dict[glyph] = [font.getGlyphID(glyph)]

        font = TTFont(font_new)
        glyphs = font.getGlyphOrder()
        for glyph in glyphs:
            if glyph in glyphs_dict:
                glyphs_dict[glyph].append(font.getGlyphID(glyph))

        id_dict = {v[0]: v[1] for v in glyphs_dict.values() if len(v) == 2}

        root = self.tree.find("glyf")

        for child in root:
            talk = child.find("instructions//talk").text
            if talk != None:
                glyph_id = child.attrib["ID"]
                new_id = id_dict[int(glyph_id)]
                child.set("ID", str(id_dict[int(glyph_id)]))
            assembly = child.find("instructions//assembly").text
            assembly_content = []
            if assembly:
                for line in assembly.split("\n"):
                    if line.startswith("OFFSET[R]"):
                        line = line.split(",")
                        line[1] = " %s" % (id_dict[int(line[1])])
                        line = ",".join(line)
                        print(line)
                    assembly_content.append(line)
                child.find("instructions//assembly").text = "\n".join(
                    assembly_content)
Ejemplo n.º 5
0
	def __init__(self, file=None, shareTables=False, **kwargs):
		fonts = self.fonts = []
		if file is None:
			return

		assert 'fontNumber' not in kwargs, kwargs

		closeStream = False
		if not hasattr(file, "read"):
			file = open(file, "rb")
			closeStream = True

		tableCache = {} if shareTables else None

		header = readTTCHeader(file)
		for i in range(header.numFonts):
			font = TTFont(file, fontNumber=i, _tableCache=tableCache, **kwargs)
			fonts.append(font)

		# don't close file if lazy=True, as the TTFont hold a reference to the original
		# file; the file will be closed once the TTFonts are closed in the
		# TTCollection.close(). We still want to close the file if lazy is None or
		# False, because in that case the TTFont no longer need the original file
		# and we want to avoid 'ResourceWarning: unclosed file'.
		if not kwargs.get("lazy") and closeStream:
			file.close()
Ejemplo n.º 6
0
def flattenGlyphs(input, fontNumber, output):
    font = TTFont(input, fontNumber=fontNumber)
    font.recalcBBoxes = False
    if "glyf" in font:
        for glyphName in font.getGlyphOrder():
            glyph = font["glyf"][glyphName]
            coordinates, endPtsOfContours, flags = glyph.getCoordinates(
                font["glyf"])
            glyph.numberOfContours = len(endPtsOfContours)
            glyph.coordinates = coordinates
            glyph.endPtsOfContours = endPtsOfContours
            glyph.flags = flags
            glyph.program = ttProgram.Program()
            font["glyf"][glyphName] = glyph
    elif "CFF " in font:
        cff = font["CFF "]
        fontName = cff.cff.fontNames[0]
        topDict = cff.cff[fontName]
        for glyphID in range(len(font.getGlyphOrder())):
            charString = topDict.CharStrings.charStringsIndex[glyphID]
            charString.decompile()
            localSubrs = getattr(charString.private, "Subrs", [])
            globalSubrs = charString.globalSubrs
            inlinedProgram = inlineProgram(localSubrs, globalSubrs,
                                           charString.program)
            charString.program = inlinedProgram
        if "Private" in topDict.rawDict and "Subrs" in topDict.Private.rawDict:
            topDict.Private.Subrs
            del topDict.Private.rawDict["Subrs"]
            del topDict.Private.Subrs
        topDict.GlobalSubrs.items = []
    else:
        raise FlattenError("Could not flatten glyphs.")

    font.save(output)
Ejemplo n.º 7
0
 def run(self):
     try:
         # Debugging in stdout
         print(f"\n\n{datetime.datetime.now()}")
         self.ttfont = TTFont(self.font_model.fontpath)
         # instantiate
         self.instantiate_variable_font()
         # edit name table records
         self.edit_name_table()
         # edit bit flags
         self.edit_bit_flags()
         # write to disk
         self.ttfont.save(self.outpath)
     except Exception as e:
         self.signals.error.emit(f"{e}")
         sys.stderr.write(f"{traceback.format_exc()}\n")
     else:
         # returns the file out file path on success
         self.signals.result.emit(self.outpath)
         self.signals.finished.emit()
Ejemplo n.º 8
0
    def _convert(filename):
        out_file = tmp_path / "converted_file.ttf"

        process = subprocess.run(
            f"python -m bdf2ttf.convert {filename} -o {out_file}",
            shell=True,
            stderr=subprocess.STDOUT)

        __tracebackhide__ = True
        if process.returncode:
            pytest.fail(f"failed to convert:\n{capfd.readouterr().out}")

        assert out_file.exists()

        return TTFont(out_file)
Ejemplo n.º 9
0
    def __init__(self, file=None, shareTables=False, **kwargs):
        fonts = self.fonts = []
        if file is None:
            return

        assert 'fontNumber' not in kwargs, kwargs

        if not hasattr(file, "read"):
            file = open(file, "rb")

        tableCache = {} if shareTables else None

        header = readTTCHeader(file)
        for i in range(header.numFonts):
            font = TTFont(file, fontNumber=i, _tableCache=tableCache, **kwargs)
            fonts.append(font)
Ejemplo n.º 10
0
def reorderFont(input, fontNumber, desiredGlyphOrder, output):
    font = TTFont(input, fontNumber=fontNumber, lazy=False)
    font = fullyLoadFont(font)

    if "CFF " in font:
        cff = font["CFF "]
        fontName = cff.cff.fontNames[0]
        topDict = cff.cff[fontName]
        topDict.compilerClass = ReorderedTopDictCompiler

    glyphOrder = font.getGlyphOrder()
    reorderedGlyphs = reorderGlyphs(glyphOrder, desiredGlyphOrder)
    if reorderedGlyphs is None:
        return False

    font.setGlyphOrder(reorderedGlyphs)
    # Glyph order is cached in a few places, clear those out.
    if "glyf" in font:
        del font["glyf"].glyphOrder
    if hasattr(font, "_reverseGlyphOrderDict"):
        del font._reverseGlyphOrderDict

    # CFF stores glyph order internally, set it:
    if "CFF " in font:
        cff = font["CFF "]
        fontName = cff.cff.fontNames[0]
        topDict = cff.cff[fontName]
        topDict.charset = reorderedGlyphs

    fixLayoutCoverage(font)

    tmp = BytesIO()
    font.save(tmp)

    tableOrder = font.reader.keys()
    success = computeTableOrder(tableOrder)
    if not success:
        tmp.close()
        return False
    outputStream = open(output, "wb")
    reorderFontTables(tmp, outputStream, tableOrder)
    tmp.close()
    outputStream.close()

    return True
Ejemplo n.º 11
0
def ttfont_glyph_to_skia_path(glyph_name: str, tt_font: ttFont.TTFont) -> pathops.Path:
    """
    Converts fontTools.ttLib.TTFont glyph to a pathops.Path object
    by glyph name.  During this conversion, all composite paths are
    decomposed.
    """
    glyf_table = tt_font["glyf"]
    glyph_set: ttFont._TTGlyphSet = tt_font.getGlyphSet()
    tt_glyph = glyf_table[glyph_name]
    skia_path = pathops.Path()
    skia_path_pen = skia_path.getPen()

    if tt_glyph.isComposite():
        decompose_pen = DecomposingRecordingPen(glyph_set)
        glyph_set[glyph_name].draw(decompose_pen)
        decompose_pen.replay(skia_path_pen)
        return skia_path
    else:
        glyph_set[glyph_name].draw(skia_path_pen)
        return skia_path
Ejemplo n.º 12
0
 def font_desecret(self, font_url, string_list):
     bin_data = base64.decodebytes(font_url.encode())
     font = TTFont(BytesIO(bin_data))
     font.saveXML("text.xml")
     font = TTFont(BytesIO(bin_data))
     c = font['cmap'].tables[0].ttFont.tables['cmap'].tables[0].cmap
     res_ls = []
     for string in string_list:
         res_str = ''
         for char in string:
             try:
                 decode_num = ord(char)
                 num = c[decode_num]
                 num = int(num[-2:]) - 1
             except:
                 num = "."
             res_str += str(num)
         res_ls.append(res_str)
     return res_ls
Ejemplo n.º 13
0
from pprint import pprint

# woff反爬
# 难点:爬下来的字是个特殊符号,并且其对应的字符编码每次请求都会改变,
# 线索:虽然字符编码数不胜数轮番上阵,但表示某个数字的字符编码们有着唯一坐标,(坐标——多种编码——数字)
# 过程:下载一个woff文件,
#       通过fonttool找到编码与坐标的对应关系,通过手动python找到数字与编码的对应关系,从而找到数字与坐标的关系,这个关系是唯一的,无论字符编码怎么改变
#       在新的请求中爬取内容,得到特殊符号,解析字符编码,通过fonttool找到坐标,通过之前的对应关系找到数字
#       得到结果
#
# 然而以上并不成立,对应的坐标只是大致相同

crawl_url = 'https://maoyan.com/films/344869'

# 建立第坐标与数字对应关系
font = TTFont('maoyan7.woff')

FONT = {
    "uniE723": "0",
    "uniF4EF": "3",
    "uniF259": "7",
    "uniED7A": "5",
    "uniF202": "2",
    "uniE99E": "4",
    "uniEA38": "9",
    "uniED43": '1',
    "uniE153": '8',
    "uniE1DC": '6'
}

dic = {
Ejemplo n.º 14
0
    def update(self,
               filename: str,
               x_counts=40,
               y_counts=20,
               fontsize=27,
               show_img=False,
               strict=False):
        """更新字体映射表, 或者覆盖原来的映射表

        :param fontsize:
        :param strict:
        :param filename: 字体文件
        :param x_counts: pillow画出来的图片一行几个字
        :param y_counts: pillow画出来的图片一列几个字
        :param show_img: 展示pillow画出来的图片不?
        :return:
        """
        # open font file
        self.font = TTFont(filename)
        self.pillow_font = ImageFont.truetype(filename, fontsize)

        font = self.font
        pillow_font = self.pillow_font

        # draw font
        cmap: dict = font.getBestCmap()
        # 删除没用的字体代码
        del cmap[120]

        # get font info
        font_name = chr(list(cmap.keys())[0])
        font_size = list(pillow_font.getsize(font_name))
        font_offset = list(pillow_font.getoffset(font_name))

        font_size[0] += font_offset[0] // 2
        font_size[1] += font_offset[1] // 2

        batch_size = x_counts * y_counts
        # 连续作画
        for i in range(0, len(cmap), batch_size):
            cmap_batch = list(cmap.items())[i:i + batch_size]
            canvas_size = font_size[0] * (x_counts +
                                          3), font_size[1] * y_counts

            # drawing
            text = ''
            for index, each in enumerate(cmap_batch):
                char = chr(each[0])
                text += char
                if (index + 1) % x_counts == 0:
                    text += '\n'

            text = text.strip()

            canvas = Image.new('RGB', canvas_size, (255, 255, 255))
            draw = ImageDraw.Draw(canvas)
            draw.text((0, 0), text, fill=0, font=pillow_font)
            if show_img:
                canvas.show()
            canvas.save('temp.jpeg', format='jpeg')

            result = self._orc.recognize('temp.jpeg')

            t_text = text.split('\n')
            t_result = result.split('\n')

            has_error = False
            for j in zip(t_text, t_result):
                # print(list(j), len(j[0]), len(j[1]))
                if len(j[0]) != len(j[1]):  # 识别失败
                    has_error = True
                    # 打印错误信息
                    if strict:
                        raise RuntimeError('识别失误 {}, {}, {}'.format(
                            list(j), len(j[0]), len(j[1])))
                self.real_font_mapping.update(dict(zip(*j)))
            if not has_error:
                logger.info('字体图标识别成功')
Ejemplo n.º 15
0
import fontTools
from fontTools.ttLib.ttFont import TTFont
#
font = TTFont('maoyan7.woff')

font.saveXML('local_fonts7.xml')

# # 每一个数字虽然对应多个16进制,但是对应一个唯一坐标
# f = font.getGlyphOrder()[2]
# print(f)
# print(font['glyf'][f].coordinates)
# print(font['glyf'][f].coordinates.array)
# print(font['glyf'][f].coordinates.array.tobytes())
# print(font['glyf'][f].coordinates.array.tobytes().hex())
# '7e01f5ff1d01e2ff2401230206010402d900e601a400c7017200bb0170000f02b0003102f90064020f01760221018c023001af025201cc027e01d1027e01e6ff'
# '7f01f1ff1e01e6ff2401230203011102c900e6019d00b8016900b70174001a02ac003102f40064020b017702210196022f01ae024401bd028201d1027801e6ff'
# '7f01e6ff2401e6ff24011e020301fe01ce00db019000b9016700ba0170000b02b600310201015e0206017d02260196023801b8024a01c6027001c2027e01e5ff'
#
# # print(font.keys())  # ['GlyphOrder', 'head', 'hhea', 'maxp', 'OS/2', 'hmtx', 'cmap', 'loca', 'glyf', 'name', 'post', 'GSUB']
# #
# # # 获取getGlyphOrder节点的name值,返回为列表
# # print(font.getGlyphOrder())  # ['glyph00000', 'x', 'uniF013', 'uniF4D4', 'uniEE40', 'uniF7E1', 'uniF34B', 'uniE1A0', 'uniF1BE', 'uniE91E', 'uniF16F', 'uniF724']
# # print(font.getGlyphNames())
# # print(font.getBestCmap())
# #
# s =""""""
# print(s)
# print(ord(s))
# ''
#
# #
Ejemplo n.º 16
0
def main():
    import argparse
    parser = argparse.ArgumentParser()
    parser.add_argument("font")
    args = parser.parse_args()
    solve(TTFont(args.font))
Ejemplo n.º 17
0
    "1EEAB..1EEBB",
    "1FBF0..1FBF9",
    "20000..2A6DD",
    "2A700..2B734",
    "2B740..2B81D",
    "2B820..2CEA1",
    "2CEB0..2EBE0",
    "2F800..2FA1D",
    "30000..3134A",
    "E0100..E01EF",
]


if __name__ == "__main__":
    list_of_fonts = [
        TTFont(file=Path("C:\\Windows\\fonts\\arial.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\calibri.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\cour.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\ebrima.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\LeelawUI.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\micross.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\taile.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\msyi.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\Nirmala.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\segoeui.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\seguihis.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\seguisym.ttf")),
        TTFont(file=Path("C:\\Windows\\fonts\\seguisym.ttf")),
    ]

    xid_start_glyphs = {}
Ejemplo n.º 18
0
def sortFonts(fontPaths):
    return sorted(
        fontPaths,
        key=lambda ff:
        (-TTFont(file=ff)["OS/2"].usWidthClass, -TTFont(file=ff)["post"].
         italicAngle, TTFont(file=ff)["OS/2"].usWeightClass))
Ejemplo n.º 19
0
class VTT_updater:
    def __init__(self,
                 path_old: Union[Path, str],
                 path_new: Union[Path, str],
                 log: bool = True) -> None:

        self.font_old = TTFont(str(path_old))
        self.font_old.cmap = {
            v: k
            for k, v in self.path_old.getBestCmap().items()
        }
        self.font_old.go = self.path_old.getGlyphOrder()
        self.font_old.path = path_old

        self.font_new = TTFont(str(path_new))
        self.font_new.cmap = self.path_new.getBestCmap()
        self.font_new.go = self.path_new.getGlyphOrder()
        self.font_new.path = path_new

        self.log = True

        self.name_map = {
            k: self.font_new.cmap.get(v)
            for k, v in self.font_old.cmap.items()
        }
        self.name_map.update({
            i: i
            for i in filter(lambda x: x in self.font_new.go, self.font_old.go)
        })
        self.incompatible_glyphs = self.get_incompatible_glyphs()

    def get_glyph_map(self) -> dict:
        glyph_map = {}
        for i, g_new in enumerate(self.font_new.go):
            if g_new in self.font_old.go:
                glyph_map[self.font_old.index(g_new)] = i
            return glyph_map

    def get_incompatible_glyphs(self) -> list:
        incompatible_glyphs = list(
            filter(lambda x: not self.name_map[x] in self.font_new.go,
                   self.font_old.go))
        for g_name in self.font_old.go:
            if g_name not in incompatible_glyphs:
                g_old = self.font_old["glyf"][g_name]
                g_new = self.font_new["glyf"][self.name_map[g_name]]

                pen_old = RecordingPen()
                g_old.draw(pen_old, self.font_old["glyf"])

                pen_new = RecordingPen()
                g_new.draw(pen_new, self.font_new["glyf"])

                for (pt_old, *_), (pt_new,
                                   *_) in zip_longest(pen_old.value,
                                                      pen_new.value,
                                                      fillvalue=[None, None]):
                    if pt_old != pt_new:
                        if self.log:
                            print(
                                f"{g_name}/{self.name_map[g_name]} has an incompatible contour"
                            )
                        break
                else:
                    if hasattr(g_old, "components") and hasattr(
                            g_new, "components"):
                        for comp_old, comp_new in zip_longest(
                                g_old.components, g_new.components):
                            if comp_old.glyphName != comp_new.glyphName:
                                if self.log:
                                    print(
                                        f"{g_name}/{self.name_map[g_name]} has incompatible components"
                                    )
                                break
                    continue
                incompatible_glyphs.append(g_name)
        return incompatible_glyphs

    def update_assembly(self) -> None:
        for g_name in self.font_old.go:
            if g_name not in self.incompatible_glyphs:
                g_old = self.font_old["glyf"][g_name]
                if hasattr(g_old, "program"):
                    g_new = self.font_new["glyf"][self.name_map[g_name]]
                    g_new.program = g_old.program
        return None

    def update_glyph_programs(self, font) -> None:
        pattern = r"(.*OFFSET\[[r,R]\]\ ?),.*"
        for key in font["TSI1"].glyphPrograms:
            glyph_program = font["TSI1"].glyphPrograms[key].replace("\r", "\n")
            matches = list(re.finditer(pattern, glyph_program))
            if matches:
                components = self.font_new["glyf"][
                    self.name_map[key]].components
                for match, component in zip(matches[::-1], components[::-1]):
                    left, right = match.span(0)
                    command = match.group(1)
                    g_name, (*transformations, x,
                             y) = component.getComponentInfo()
                    assembly = [x, y]
                    if transformations != [1, 0, 0, 1]:
                        assembly.extend(transformations)
                    assembly = list(map(str, assembly))
                    gid = self.font_new.go.index(g_name)
                    new_command = f"{command}, {gid}, {', '.join(assembly)}"
                    glyph_program = (glyph_program[:left] + new_command +
                                     glyph_program[right:])
                font["TSI1"].glyphPrograms[key] = glyph_program.replace(
                    "\n", "\r")
        return None

    def _filter_glyphs(self, dict_data) -> dict:
        new_dict_data = {}
        keys = [i for i in dict_data.keys()]
        for key in keys:
            if key not in self.incompatible_glyphs:
                new_dict_data[self.name_map[key]] = dict_data[key]
        return new_dict_data

    def update_TSI_tables(self) -> None:

        self.font_new["TSI0"] = self.font_old["TSI0"]  # empty...
        self.font_new["TSI1"] = self.font_old["TSI1"]  # assembly
        self.font_new["TSI2"] = self.font_old["TSI2"]  # empty...
        self.font_new["TSI3"] = self.font_old["TSI3"]  # VTT talks
        self.font_new["TSI5"] = self.font_old["TSI5"]  # glyph groups
        self.font_new["cvt "] = self.font_old["cvt "]  # cvts
        self.font_new["prep"] = self.font_old["prep"]  # prep
        self.font_new["fpgm"] = self.font_old["fpgm"]  # fpgm

        self.font_new["TSI1"].glyphPrograms = self._filter_glyphs(
            self.font_new["TSI1"].glyphPrograms)
        self.font_new["TSI3"].glyphPrograms = self._filter_glyphs(
            self.font_new["TSI3"].glyphPrograms)
        return None

    def update_table_entries(self) -> None:
        update = dict(
            maxp=[
                "maxSizeOfInstructions",
                "maxFunctionDefs",
                "maxStorage",
                "maxStackElements",
                "maxZones",
                "maxTwilightPoints",
            ],
            head=["checkSumAdjustment"],
        )

        for table, attributes in update.items():
            for attribute in attributes:
                setattr(
                    self.font_new[table],
                    attribute,
                    getattr(self.font_old[table], attribute),
                )

        self.font_new["head"].flags |= 1 << 3

        return None

    def update(self) -> None:
        self.update_assembly()
        self.update_glyph_programs(self.font_old)
        self.update_TSI_tables()
        self.update_table_entries()
        return None

    def write(self, save_as: Union[Path, str, bool] = None) -> None:
        if save_as:
            self.font_new.save(str(save_as))
        else:
            self.font_new.save(str(self.font_new.path))
        return None
Ejemplo n.º 20
0
class InstanceWorker(QRunnable):
    def __init__(
        self,
        outpath=None,
        font_model=None,
        axis_model=None,
        name_model=None,
        bit_model=None,
    ):
        super().__init__()
        self.signals = InstanceWorkerSignals()
        self.outpath = outpath
        self.font_model = font_model
        self.axis_model = axis_model
        self.name_model = name_model
        self.bit_model = bit_model
        self.ttfont = None

    @pyqtSlot()
    def run(self):
        try:
            # Debugging in stdout
            print(f"\n\n{datetime.datetime.now()}")
            self.ttfont = TTFont(self.font_model.fontpath)
            # instantiate
            self.instantiate_variable_font()
            # edit name table records
            self.edit_name_table()
            # edit bit flags
            self.edit_bit_flags()
            # write to disk
            self.ttfont.save(self.outpath)
        except Exception as e:
            self.signals.error.emit(f"{e}")
            sys.stderr.write(f"{traceback.format_exc()}\n")
        else:
            # returns the file out file path on success
            self.signals.result.emit(self.outpath)
            self.signals.finished.emit()

    def instantiate_variable_font(self):
        axis_instance_data = self.axis_model.get_instance_data()
        instantiateVariableFont(self.ttfont, axis_instance_data, inplace=True)
        print("\nAXIS INSTANCE VALUES")
        print(
            f"Instantiated variable font with axis definitions:\n{axis_instance_data}"
        )

    def edit_name_table(self):
        # string, nameID, platformID, platEncID, langID
        name_record_plat_enc_lang = (3, 1, 1033)
        name_instance_data = self.name_model.get_instance_data()
        name_table = self.ttfont["name"]
        # set 3, 1, 1033 name records (only!)
        # mandatory writes
        name_table.setName(name_instance_data["nameID1"], 1, *name_record_plat_enc_lang)
        name_table.setName(name_instance_data["nameID2"], 2, *name_record_plat_enc_lang)
        name_table.setName(name_instance_data["nameID3"], 3, *name_record_plat_enc_lang)
        name_table.setName(name_instance_data["nameID4"], 4, *name_record_plat_enc_lang)
        name_table.setName(name_instance_data["nameID6"], 6, *name_record_plat_enc_lang)

        # optional writes
        # Approach:
        # (1) if user text data exists, write it
        # (2) if user text data does not exist but record does, delete it
        # (3) otherwise do nothing
        if name_instance_data["nameID16"] != "":
            name_table.setName(
                name_instance_data["nameID16"], 16, *name_record_plat_enc_lang
            )
        elif name_table.getName(16, *name_record_plat_enc_lang):
            name_table.removeNames(16, *name_record_plat_enc_lang)

        if name_instance_data["nameID17"] != "":
            name_table.setName(
                name_instance_data["nameID17"], 17, *name_record_plat_enc_lang
            )
        elif name_table.getName(17, *name_record_plat_enc_lang):
            name_table.removeNames(17, *name_record_plat_enc_lang)

        if name_instance_data["nameID21"] != "":
            name_table.setName(
                name_instance_data["nameID21"], 21, *name_record_plat_enc_lang
            )
        elif name_table.getName(21, *name_record_plat_enc_lang):
            name_table.removeNames(21, *name_record_plat_enc_lang)

        if name_instance_data["nameID22"] != "":
            name_table.setName(
                name_instance_data["nameID22"], 22, *name_record_plat_enc_lang
            )
        elif name_table.getName(22, *name_record_plat_enc_lang):
            name_table.removeNames(22, *name_record_plat_enc_lang)

        # update name table data
        self.ttfont["name"] = name_table

        # print name table report
        print("\nNAME TABLE EDITS")
        print("Name records at write time:\n")
        print(f"nameID1: {self.ttfont['name'].getName(1, *name_record_plat_enc_lang)}")
        print(f"nameID2: {self.ttfont['name'].getName(2, *name_record_plat_enc_lang)}")
        print(f"nameID3: {self.ttfont['name'].getName(3, *name_record_plat_enc_lang)}")
        print(f"nameID4: {self.ttfont['name'].getName(4, *name_record_plat_enc_lang)}")
        print(f"nameID6: {self.ttfont['name'].getName(6, *name_record_plat_enc_lang)}")
        print(
            f"nameID16: {self.ttfont['name'].getName(16, *name_record_plat_enc_lang)}"
        )
        print(
            f"nameID17: {self.ttfont['name'].getName(17, *name_record_plat_enc_lang)}"
        )
        print(
            f"nameID21: {self.ttfont['name'].getName(21, *name_record_plat_enc_lang)}"
        )
        print(
            f"nameID22: {self.ttfont['name'].getName(22, *name_record_plat_enc_lang)}"
        )

    def edit_bit_flags(self):
        # edit the OS/2.fsSelection bit flag
        pre_os2_fsselection_int = self.ttfont["OS/2"].fsSelection
        edited_os2_fsselection_int = self.bit_model.edit_os2_fsselection_bits(
            pre_os2_fsselection_int
        )
        # edit OS/2.fsSelection in the TTFont attribute
        self.ttfont["OS/2"].fsSelection = edited_os2_fsselection_int

        # edit head.macstyle bit flag
        pre_head_macstyle_int = self.ttfont["head"].macStyle
        edited_head_macstyle_int = self.bit_model.edit_head_macstyle_bits(
            pre_head_macstyle_int
        )
        self.ttfont["head"].macStyle = edited_head_macstyle_int

        # bit flag debugging stdout report
        print("\nBIT FLAGS")
        print(
            f"\nOS/2.fsSelection updated with the following data:\n"
            f"{self.bit_model.get_os2_instance_data()}"
        )
        print(f"Pre OS/2.fsSelection:  {num2binary(pre_os2_fsselection_int, bits=16)}")
        print(
            f"Post OS/2.fsSelection: {num2binary(self.ttfont['OS/2'].fsSelection, bits=16)}"
        )
        print(
            f"\nhead.macStyle bit flag updated with the following data:\n"
            f"{self.bit_model.get_head_instance_data()}"
        )
        print(f"Pre head.macStyle:  {num2binary(pre_head_macstyle_int, bits=16)}")
        print(
            f"Post head.macStyle: {num2binary(self.ttfont['head'].macStyle, bits=16)}"
        )
Ejemplo n.º 21
0
parse = argparse.ArgumentParser(description="将ttf字体文件转为图片")
parse.add_argument('-f', required=True, help="输入字体文件")
parse.add_argument('-o', help="图片输出目录,默认为当前目录下imgs", default="imgs")
parse.add_argument('-s', '--size', type=int, help="输出图片的像素大小", default=512)

args = parse.parse_args()
os.makedirs(args.o, exist_ok=True)


def uni_2_png(txt, font=args.f, img_size=args.size):
    img = Image.new('1', (img_size, img_size), 255)
    draw = ImageDraw.Draw(img)
    font = ImageFont.truetype(font, int(img_size * 0.7))

    txt = chr(txt)
    x, y = draw.textsize(txt, font=font)
    draw.text(((img_size - x) // 2, (img_size - y) // 2),
              txt,
              font=font,
              fill=0)
    # draw.text((0,0), txt, font=font, fill=0)
    file_name = '%s/%s.png' % (args.o, i)
    img.save(file_name)


if __name__ == '__main__':
    f = TTFont(args.f)
    for i in f.getBestCmap():
        uni_2_png(i)
Ejemplo n.º 22
0
from pathlib import Path

from fontTools.ttLib.ttFont import TTFont

# some font types require an specified fontNumber parameter
# This list will need to change depending on what fonts you have installed
list_of_fonts = [
    TTFont(file=Path(
        "C:\\Users\\Quinten\\AppData\\Local\\Microsoft\\Windows\\Fonts\\gw2696936.ttf"
    )),
    TTFont(file=Path(
        "C:\\Users\\Quinten\\AppData\\Local\\Microsoft\\Windows\\Fonts\\gw2695709.ttf"
    )),
    TTFont(file=Path(
        "C:\\Users\\Quinten\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Behistun-J8dE.ttf"
    )),
    TTFont(file=Path(
        "C:\\Users\\Quinten\\AppData\\Local\\Microsoft\\Windows\\Fonts\\unifont_upper-13.0.03.ttf"
    )),
    TTFont(file=Path(
        "C:\\Users\\Quinten\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Everson Mono.ttf"
    )),
    TTFont(file=Path(
        "C:\\Users\\Quinten\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Everson Mono Oblique.ttf"
    )),
    TTFont(file=Path(
        "C:\\Users\\Quinten\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Everson Mono Bold Oblique.ttf"
    )),
    TTFont(file=Path(
        "C:\\Users\\Quinten\\AppData\\Local\\Microsoft\\Windows\\Fonts\\Everson Mono Bold.ttf"
    )),