def main(argv):
    """Decompose all fonts provided in the command line."""
    for font_file_name in argv[1:]:
        with open(font_file_name, 'rb') as font_file:
            font = sfnt.SFNTReader(font_file, fontNumber=0)
            num_fonts = font.numFonts
        for font_number in range(num_fonts):
            font = ttLib.TTFont(font_file_name, fontNumber=font_number)
            font.save('%s-part%d' % (font_file_name, font_number))
示例#2
0
def DiffTables(font_filename1, font_filename2):
    """Prints a table-by-table size comparison of two fonts.

  Args:
    font_filename1: The first font to compare.
    font_filename2: The second font to compare.
  Returns:
    String describing size difference. One line per unique table in either font.
  """
    result = ['    Table    Changes  Delta-Bytes(from=>to)  % Change']
    result.append('    -------------------------------------------------')
    sfnt1 = sfnt.SFNTReader(open(font_filename1))
    sfnt2 = sfnt.SFNTReader(open(font_filename2))

    font_sz1 = os.stat(font_filename1).st_size

    sum_tables1 = 0
    sum_tables2 = 0

    table_l1_l2s = []
    for t in fonts.UniqueSort(sfnt1.tables, sfnt2.tables, _KNOWN_TABLES):
        table1_sz = sfnt1.tables[t].length if t in sfnt1 else 0
        table2_sz = sfnt2.tables[t].length if t in sfnt2 else 0
        sum_tables1 += table1_sz
        sum_tables2 += table2_sz
        table_l1_l2s.append((t, table1_sz, table2_sz))

    for (table, table1_sz, table2_sz) in table_l1_l2s:
        delta_pct = float(table2_sz - table1_sz) / font_sz1 * 100
        result.append(
            '    %s  %+6d      %06d => %06d %+10.1f%%' %
            (table, table2_sz - table1_sz, table1_sz, table2_sz, delta_pct))

    delta_pct = float(sum_tables2 - sum_tables1) / font_sz1 * 100
    result.append(
        '    TOTAL %+6d      %06d => %06d %+10.1f%%' %
        (sum_tables2 - sum_tables1, sum_tables1, sum_tables2, delta_pct))

    return '\n'.join(result)
示例#3
0
def get_fonts_table_sizes(fonts):
    """ Returns tuple with available tables from all fonts and their length """
    from fontTools.ttLib import sfnt
    _fonts = {}
    tables = []
    for font in fonts:
        _fonts[op.basename(font)] = {}
        with open(font) as fp_font:
            sf = sfnt.SFNTReader(fp_font)
            for t in sf.tables:
                if t not in tables:
                    tables.append(t)
                _fonts[op.basename(font)][t] = sf.tables[t].length
    return tables, _fonts
示例#4
0
def run(options):
    ttc_path = options.ttc_path

    with open(ttc_path, 'rb') as fp:
        num_fonts = sfnt.SFNTReader(fp, fontNumber=0).numFonts

    if options.report:
        unique_tables = set()
        print(f'Input font: {os.path.basename(ttc_path)}\n')

    for ft_idx in range(num_fonts):
        font = TTFont(ttc_path, fontNumber=ft_idx, lazy=True)

        psname = get_psname(font)
        if psname is None:
            ttc_name = os.path.splitext(os.path.basename(ttc_path))[0]
            psname = f'{ttc_name}-font{ft_idx}'

        ext = '.otf' if font.sfntVersion == 'OTTO' else '.ttf'
        font_filename = f'{psname}{ext}'

        if options.report:
            # this code is based on fontTools.ttx.ttList
            reader = font.reader
            tags = sorted(reader.keys())
            print(f'Font {ft_idx}: {font_filename}')
            print('    tag ', '   checksum', '   length', '   offset')
            print('    ----', ' ----------', ' --------', ' --------')
            for tag in tags:
                entry = reader.tables[tag]
                checksum = int(entry.checkSum)
                if checksum < 0:
                    checksum += 0x100000000
                checksum = f'0x{checksum:08X}'
                tb_info = (tag, checksum, entry.length, entry.offset)
                if tb_info not in unique_tables:
                    print('    {:4s}  {:10s}  {:8d}  {:8d}'.format(*tb_info))
                    unique_tables.add(tb_info)
                else:
                    print(f'    {tag:4s}  - shared -')
            print()
        else:
            save_path = os.path.join(os.path.dirname(ttc_path), font_filename)
            font.save(save_path)
            logger.info(f'Saved {save_path}')

        font.close()
示例#5
0
    def __init__(self, file=None, res_name_or_index=None,
            sfntVersion="\000\001\000\000", checkChecksums=0,
            verbose=0, recalcBBoxes=1, allowVID=0, ignoreDecompileErrors=False,
            fontNumber=-1):

        from fontTools.ttLib import sfnt
        self.verbose = verbose
        self.recalcBBoxes = recalcBBoxes
        self.tables = {}
        self.reader = None

        # Permit the user to reference glyphs that are not int the font.
        self.last_vid = 0xFFFE # Can't make it be 0xFFFF, as the world is full unsigned short integer counters that get incremented after the last seen GID value.
        self.reverseVIDDict = {}
        self.VIDDict = {}
        self.allowVID = allowVID
        self.ignoreDecompileErrors = ignoreDecompileErrors

        self.reader = sfnt.SFNTReader(file, checkChecksums, fontNumber=fontNumber)
        self.sfntVersion = self.reader.sfntVersion
示例#6
0
	def __init__(self, file=None, res_name_or_index=None,
			sfntVersion="\000\001\000\000", flavor=None, checkChecksums=False,
			verbose=None, recalcBBoxes=True, allowVID=False, ignoreDecompileErrors=False,
			recalcTimestamp=True, fontNumber=-1, lazy=None, quiet=None):

		"""The constructor can be called with a few different arguments.
		When reading a font from disk, 'file' should be either a pathname
		pointing to a file, or a readable file object.

		It we're running on a Macintosh, 'res_name_or_index' maybe an sfnt
		resource name or an sfnt resource index number or zero. The latter
		case will cause TTLib to autodetect whether the file is a flat file
		or a suitcase. (If it's a suitcase, only the first 'sfnt' resource
		will be read!)

		The 'checkChecksums' argument is used to specify how sfnt
		checksums are treated upon reading a file from disk:
			0: don't check (default)
			1: check, print warnings if a wrong checksum is found
			2: check, raise an exception if a wrong checksum is found.

		The TTFont constructor can also be called without a 'file'
		argument: this is the way to create a new empty font.
		In this case you can optionally supply the 'sfntVersion' argument,
		and a 'flavor' which can be None, 'woff', or 'woff2'.

		If the recalcBBoxes argument is false, a number of things will *not*
		be recalculated upon save/compile:
			1) 'glyf' glyph bounding boxes
			2) 'CFF ' font bounding box
			3) 'head' font bounding box
			4) 'hhea' min/max values
			5) 'vhea' min/max values
		(1) is needed for certain kinds of CJK fonts (ask Werner Lemberg ;-).
		Additionally, upon importing an TTX file, this option cause glyphs
		to be compiled right away. This should reduce memory consumption
		greatly, and therefore should have some impact on the time needed
		to parse/compile large fonts.

		If the recalcTimestamp argument is false, the modified timestamp in the
		'head' table will *not* be recalculated upon save/compile.

		If the allowVID argument is set to true, then virtual GID's are
		supported. Asking for a glyph ID with a glyph name or GID that is not in
		the font will return a virtual GID.   This is valid for GSUB and cmap
		tables. For SING glyphlets, the cmap table is used to specify Unicode
		values for virtual GI's used in GSUB/GPOS rules. If the gid N is requested
		and does not exist in the font, or the glyphname has the form glyphN
		and does not exist in the font, then N is used as the virtual GID.
		Else, the first virtual GID is assigned as 0x1000 -1; for subsequent new
		virtual GIDs, the next is one less than the previous.

		If ignoreDecompileErrors is set to True, exceptions raised in
		individual tables during decompilation will be ignored, falling
		back to the DefaultTable implementation, which simply keeps the
		binary data.

		If lazy is set to True, many data structures are loaded lazily, upon
		access only.  If it is set to False, many data structures are loaded
		immediately.  The default is lazy=None which is somewhere in between.
		"""

		from fontTools.ttLib import sfnt

		for name in ("verbose", "quiet"):
			val = locals().get(name)
			if val is not None:
				deprecateArgument(name, "configure logging instead")
			setattr(self, name, val)

		self.lazy = lazy
		self.recalcBBoxes = recalcBBoxes
		self.recalcTimestamp = recalcTimestamp
		self.tables = {}
		self.reader = None

		# Permit the user to reference glyphs that are not int the font.
		self.last_vid = 0xFFFE # Can't make it be 0xFFFF, as the world is full unsigned short integer counters that get incremented after the last seen GID value.
		self.reverseVIDDict = {}
		self.VIDDict = {}
		self.allowVID = allowVID
		self.ignoreDecompileErrors = ignoreDecompileErrors

		if not file:
			self.sfntVersion = sfntVersion
			self.flavor = flavor
			self.flavorData = None
			return
		if not hasattr(file, "read"):
			closeStream = True
			# assume file is a string
			if res_name_or_index is not None:
				# see if it contains 'sfnt' resources in the resource or data fork
				from . import macUtils
				if res_name_or_index == 0:
					if macUtils.getSFNTResIndices(file):
						# get the first available sfnt font.
						file = macUtils.SFNTResourceReader(file, 1)
					else:
						file = open(file, "rb")
				else:
					file = macUtils.SFNTResourceReader(file, res_name_or_index)
			else:
				file = open(file, "rb")

		else:
			# assume "file" is a readable file object
			closeStream = False
		if not self.lazy:
			# read input file in memory and wrap a stream around it to allow overwriting
			tmp = BytesIO(file.read())
			if hasattr(file, 'name'):
				# save reference to input file name
				tmp.name = file.name
			if closeStream:
				file.close()
			file = tmp
		self.reader = sfnt.SFNTReader(file, checkChecksums, fontNumber=fontNumber)
		self.sfntVersion = self.reader.sfntVersion
		self.flavor = self.reader.flavor
		self.flavorData = self.reader.flavorData