Пример #1
0
def _build_ttf_entries(fpath):
    """ Given the path to a TTF/TTC file, return a list of :class:`FontEntry`
    instances.
    """
    entries = []

    ext = os.path.splitext(fpath)[-1]
    try:
        with open(fpath, "rb") as fp:
            if ext.lower() == ".ttc":
                collection = TTCollection(fp)
                try:
                    for idx, font in enumerate(collection.fonts):
                        entries.append(_ttf_font_property(fpath, font, idx))
                except Exception:
                    logger.error(_FONT_ENTRY_ERR_MSG, fpath, exc_info=True)
            else:
                font = TTFont(fp)
                try:
                    entries.append(_ttf_font_property(fpath, font))
                except Exception:
                    logger.error(_FONT_ENTRY_ERR_MSG, fpath, exc_info=True)
    except (RuntimeError, TTLibError):
        logger.error(f"Could not open font file {fpath}", exc_info=True)
    except UnicodeError:
        logger.error(f"Cannot handle unicode file: {fpath}", exc_info=True)

    return entries
def run(path, options):
    try:
        font = TTFont(path, fontNumber=options.face_index)
        extension = '.ttf'
    except TTLibError:
        font = TTCollection(path)
        extension = '.ttc'

    if options.output and not os.path.isdir(options.output):
        output = options.output
    else:
        output = makeOutputFileName(path,
                                    outputDir=options.output,
                                    extension=extension,
                                    overWrite=options.overwrite)

    try:
        otf_to_ttf(font,
                   post_format=options.post_format,
                   max_err=options.max_error,
                   reverse_direction=options.reverse_direction)
    except TTLibError as warn:
        log.warning(f'"{path}" cannot be converted since it is {warn}.')
    else:
        font.save(output)
Пример #3
0
def generate_ttx_dump(font_path, tables=None):
    try:
        font = TTFont(font_path)
    except TTLibError:
        font = TTCollection(font_path)

    with font:
        temp_path = get_temp_file_path()
        font.saveXML(temp_path, tables=tables)
        return temp_path
Пример #4
0
def fix(file):
    dirname = args.dirname if os.path.exists(args.dirname) \
        else os.path.join(os.path.dirname(file), args.dirname)
    basename = os.path.basename(file)

    if not os.path.exists(dirname):
        os.mkdir(dirname)

    logger.name = basename

    with open(file, 'rb') as f:
        header = f.read(4)

    font = TTCollection(file, **options) if header == b'ttcf' \
        else TTFont(file, **options)

    repair(font)

    font.save(os.path.join(dirname, basename))
Пример #5
0
def unpack_ttc(filepath: Path) -> None:
    try:
        collection = TTCollection(str(filepath.resolve()))
    except:
        print(f"Failed to parse {filepath}, ignore")
        return
    for font in collection.fonts:
        ttf_path = filepath.parent / f"{get_font_name(font)}.ttf"
        font.save(ttf_path)
        print(f"{filepath} -> {ttf_path}")
    filepath.unlink()
Пример #6
0
def get_ttc_list(filename):
    #clear font list
    ttc_names = []
    #lazy=True: https://github.com/fonttools/fonttools/issues/2019
    ttc = TTCollection(filename, lazy=True)
    for font in ttc:
        # single font name in getName(nameID, platformID, platEncID, langID=None), 0x409 make sure all font in English name
        ttf_name = font["name"].getName(4, 3, 1, 0x409)
        # add the font name itself instead of the XML representation
        ttc_names.append(str(ttf_name))
    #return array of names
    return ttc_names
Пример #7
0
def run(path, options):
    with open(path, 'rb') as f:
        header = f.read(4)

    if header == b'ttcf' and options.face_index == -1:
        extension = '.ttc'
        font = TTCollection(path)
    else:
        extension = '.ttf'
        font = TTFont(path, fontNumber=options.face_index)

    if options.output and not os.path.isdir(options.output):
        output = options.output
    else:
        output = makeOutputFileName(path, outputDir=options.output,
                                    extension=extension,
                                    overWrite=options.overwrite)

    otf_to_ttf(font,
               post_format=options.post_format,
               max_err=options.max_error,
               reverse_direction=options.reverse_direction)
    font.save(output)
Пример #8
0
def find_glyph(path, glyph):
    if path.suffix == '.ttc':
        fonts = TTCollection(path)
    else:
        fonts = [TTFont(path)]
    for n, font in enumerate(fonts):

        def _inspect():
            for table in font['cmap'].tables:
                if glyph in table.cmap:
                    return (n, (table.platformID, table.platEncID),
                            table.cmap[glyph])

        result = _inspect()
        if result is not None:
            yield result
Пример #9
0
def load_font(font_path):
    """
    Read ttc, ttf, otf font file, return a TTFont object
    """

    # ttc is collection of ttf
    if font_path.endswith('ttc'):
        ttc = TTCollection(font_path)
        # assume all ttfs in ttc file have same supported chars
        return ttc.fonts[0]

    if font_path.endswith('ttf') or font_path.endswith('TTF') or font_path.endswith('otf'):
        ttf = TTFont(font_path, 0, allowVID=0,
                     ignoreDecompileErrors=True,
                     fontNumber=-1)

        return ttf
Пример #10
0
 def check_font(self):
     font_new = []
     for fonts in self.font_list:
         fontsname = os.path.join(self.font_path, fonts)
         #print '------------------------------------------'
         #print fontsname
         if (fontsname.endswith('ttc')):
             ttc = TTCollection(fontsname)
             fonts_load = ttc.fonts[0]
         elif (fontsname.endswith('ttf') or fontsname.endswith('TTF')
               or fontsname.endswith('otf')):
             ttf = TTFont(fontsname,
                          0,
                          allowVID=0,
                          ignoreDecompileErrors=True,
                          fontNumber=1)
             fonts_load = ttf
         else:
             #print 'the type of fonts is not supported !'
             #return None
             continue
         chars = chain.from_iterable(
             [y + (Unicode[y[0]], ) for y in x.cmap.items()]
             for x in fonts_load['cmap'].tables)
         #print fontsname,' support chars: ',len(chars)
         chars_int = []
         for c in chars:
             chars_int.append(c[0])
         unsupport_chars = []
         support_chars = []
         for c in self.dict:
             if ord(c) not in chars_int:
                 unsupport_chars.append(c)
                 #print c
             else:
                 support_chars.append(c)
         fonts_load.close()
         if (len(unsupport_chars) != 0):
             print fontsname, ' not support all the chars in dic !'
         else:
             #print fontsname,' supports all the chars in dic !'
             font_new.append(fonts)
     self.font_list = font_new
     for fonts in self.font_list:
         print fonts, ' is used .'
Пример #11
0
    def _load_ttfont(self, font_path: str) -> TTFont:
        """
        Read ttc, ttf, otf font file, return a TTFont object
        """

        # ttc is collection of ttf
        if font_path.endswith("ttc"):
            ttc = TTCollection(font_path)
            # assume all ttfs in ttc file have same supported chars
            return ttc.fonts[0]

        if (font_path.endswith("ttf") or font_path.endswith("TTF")
                or font_path.endswith("otf")):
            ttf = TTFont(font_path,
                         0,
                         allowVID=0,
                         ignoreDecompileErrors=True,
                         fontNumber=-1)

            return ttf
Пример #12
0
def test_lazy_open_path(lazy):
    ttc_path = TTX_DATA_DIR / "TestTTC.ttc"
    with TTCollection(ttc_path, lazy=lazy) as collection:
        assert len(collection) == 2
        assert collection[0]["maxp"].numGlyphs == 6
        assert collection[1]["maxp"].numGlyphs == 6
Пример #13
0
all Unicode characters covered by all fonts, e.g.

list_ttf_chars.py $ANDROID_HOME/platforms/android-XY/data/fonts/*.ttf

Requires FontTools: https://pypi.python.org/pypi/FontTools
'''

import sys

from fontTools.ttLib import TTFont, TTCollection

chars = {}
for f in sys.argv[1:]:
    try:
        if f.endswith('.ttc'):
            fonts = TTCollection(f)
        else:
            fonts = [TTFont(f)]
        for font in fonts:
            bestTable = font.getBestCmap()
            if bestTable is not None:
                chars.update(bestTable)
            else:
                print('Warning: Font does not have a Unicode cmap:',
                      f,
                      file=sys.stderr)
                for table in font['cmap'].tables:
                    chars.update(table.cmap)
    except:
        print('Could not process arg:', f, file=sys.stderr)
        raise
Пример #14
0
import sys
from fontTools.ttLib import TTFont, TTCollection

import common

if __name__ == "__main__":
    param = common.ParamFromArgument(sys.argv[1])

    ttc = TTCollection(param['font'], recalcBBoxes=False)
    font = ttc[0]
    del font['vhea']
    del font['vmtx']
    font_head = font['head']

    ref = TTFont(param['reference'])
    ref_head = ref['head']
    scale = font_head.unitsPerEm / ref_head.unitsPerEm

    font_head.yMin = round(ref_head.yMin * scale)
    font_head.yMax = round(ref_head.yMax * scale)

    ttc.save(param['out'])
Пример #15
0
    parser.add_argument(
        '--delete',
        action="store_true",
        default=False,
        help=
        'whether or not to delete font which not full support the chars_file')

    args, _ = parser.parse_known_args()

    charset = load_chars(args.chars_file)
    font_paths = glob.glob(args.font_dir + '/*.*')

    fonts = {}
    for p in font_paths:
        if p.endswith('ttc'):
            ttc = TTCollection(p)
            for f in ttc.fonts:
                fonts["%s_1" % p] = f

        if p.endswith('ttf') or p.endswith('TTF') or p.endswith('otf'):
            ttf = TTFont(p,
                         0,
                         allowVID=0,
                         ignoreDecompileErrors=True,
                         fontNumber=-1)

            fonts[p] = ttf

    useful_fonts = []
    for k, v in fonts.items():
        print("checking font %s" % k)
Пример #16
0
			ppemHw = int(i) + 1

		widths = []
		for name in font.getGlyphOrder():
			width = hmtx_[name][0]
			widths.append(math.ceil(width / widthHw) * ppemHw)
		record = bytes([ ppem, max(widths) ] + widths) + pad
		deviceRecords.append(record)

	hdmxHeader = sstruct.pack(hdmxHeaderFormat, SimpleNamespace(version = 0, numRecords = len(deviceRecords), recordSize = recordSize))
	
	hdmx_ = DefaultTable('hdmx')
	hdmx_.data = hdmxHeader + b''.join(deviceRecords)
	font['hdmx'] = hdmx_

if __name__ == "__main__":
	parser = argparse.ArgumentParser()
	parser.add_argument('-i', '--input', required = True)
	parser.add_argument('-o', '--output', required = True)
	args = parser.parse_args()

	try:
		ttc = TTCollection(args.input, recalcBBoxes = False)
		for font in ttc:
			BuildRawHdmx(font)
		ttc.save(args.output)
	except TTLibError:
		font = TTFont(args.input, recalcBBoxes = False)
		BuildRawHdmx(font)
		font.save(args.output)
Пример #17
0
def analyzeFonts(fontList, makeDict=False):
    """
    Set makeDict to True to create a dictionary of glyphs supported by each font
    suitable for JSON export.
    """

    errorList = []

    fontDict = {}

    ## Always update these lines with information on which OS the font files came from ##
    withOS = OS.objects.get(slug="mac-11")
    withOSLabel = "Big Sur"

    for idx, fontFile in enumerate(fontList):
        isCollection = False
        if str(fontFile)[-3:] == "ttc":
            isCollection = True
        try:
            if isCollection:
                fontCollection = TTCollection(fontFile)
            else:
                fontCollection = [TTFont(fontFile)]
        except Exception as e:
            print("Failed to read", fontFile)
            print(e)
            continue

        fileNameStem = fontFile.stem

        if makeDict:
            fontDict[fileNameStem] = []

        for font in fontCollection:
            fontName = font["name"].names[1].toStr()
            try:
                fontVersion = font["name"].names[5].toStr(
                )[:64]  # 64 character limit for model charFields
            except IndexError:
                fontVersion = ""

            if "LastResort" in fontName:
                continue
            if "©" in fontName or "Copyright" in fontName:
                fontName = fileNameStem.replace("-", " ")
                fontName = re.sub(r'([a-z])([A-Z])', r'\1 \2', fontName)

            try:
                fontStyle = font["name"].names[2].toStr()
            except IndexError:
                fontStyle = ""
            print("filename: ", fileNameStem)
            slug = slugify(fontName[:64 - len(fontStyle) - 1] + " " +
                           fontStyle[:64])[:64]
            print("slug: ", slug)
            slugDup = False

            fontDbObj = None
            print("fontname: ", fontName)
            print("fontstyle: ", fontStyle)
            print("fontversion: ", fontVersion)
            """NOTE! In most recent update, added check for version number. This will end up creating 
            duplicate Font objects in the database since many of the original imports did not include 
            version numbers."""

            fontDbObjs = Font.objects.filter(name=fontName.replace(
                "109uh", "")[:64],
                                             style=fontStyle[:64],
                                             fileName=fileNameStem,
                                             version=fontVersion)

            if makeDict:
                fontObj = {
                    "name": fontName.replace("109uh", "")[:64],
                    "style": fontStyle[:64],
                    "fileType": str(fontFile)[-3:],
                    "slug": slug,
                    "version": fontVersion,
                    "glyphs": set()
                }
                fontDict[fileNameStem] += [fontObj]

            if not fontDbObjs.exists() and fontName[0] == ".":
                fontName = fontName[1:]
                fontDbObjs = Font.objects.filter(name=fontName.replace(
                    "109uh", "")[:64],
                                                 style=fontStyle[:64],
                                                 fileName=fileNameStem,
                                                 version=fontVersion)
            if not fontDbObjs.exists():
                fontDbObjs = Font.objects.filter(fileName=fileNameStem,
                                                 version=fontVersion)
            if fontDbObjs.exists():
                fontDbObj = fontDbObjs[0]
                print(f"Adding to {withOSLabel} font list")
                fontDbObj.incWithOS.add(withOS)
                fontDbObj.save()
                print("Skipping further analysis", fontName, " ", fontStyle)
                print()
                continue

            else:
                slugDup = Font.objects.filter(slug=slug).exists()
                if slugDup:
                    slug = slug[:50] + "-" + str(int(random.random() * 10000))
                try:
                    fontDbObj = Font(name=fontName.replace("109uh", "")[:64],
                                     style=fontStyle[:64],
                                     fileName=fileNameStem,
                                     fileType=str(fontFile)[-3:],
                                     slug=slug,
                                     version=fontVersion)
                    print(f"Created font: {fontName} {fontStyle}")
                    print(fontDbObj)
                    fontDbObj.save()
                except django.db.utils.IntegrityError as e:
                    print("ERROR: ", e)
                    continue

            for cmap in font['cmap'].tables:
                if cmap.isUnicode():
                    for idx, uniChar in enumerate(cmap.cmap):
                        glyphObj, result = Glyph.objects.get_or_create(
                            codePoint=uniChar,
                            defaults={
                                "officialName": "Private or unassigned",
                                "slug": "%04X" % uniChar,
                                "codePlane": uniChar // 65536
                            })
                        if result:
                            print("Created new Glyph object for codePoint ",
                                  hex(uniChar).upper())
                        # except Glyph.DoesNotExist:
                        #    print(f"WARNING: In {dictKey}/{fontName}, no glyph found for ", hex(uniChar))
                        #    errorList += [hex(uniChar)]
                        #    continue
                        fontDbObj.glyphs.add(glyphObj)
                        if idx % 250 == 0:
                            print('.', end='')

                        if makeDict:
                            fontDict[fileNameStem][-1]["glyphs"].add(
                                f"{hex(uniChar).upper()[2:]}")

            print(f"Added {fontDbObj.glyphs.count()} glyphs to font")
            fontDbObj.save()
            print(f"Adding to {withOSLabel} font list...")
            fontDbObj.incWithOS.add(withOS)
            fontDbObj.save()
            print("Finished ", fontDbObj)
            print("=====")
            print()

            #errorList = list(set(errorList))
            #print("Error list first 10 items are ", errorList[:10], f"out of {len(errorList)} total")

    return fontDict
Пример #18
0
def createFontList(fontfiles, fontext='ttf'):
    """
    A function to create a font lookup list.  The default is to create
    a list of TrueType fonts.  An AFM font list can optionally be
    created.
    """
    # FIXME: This function is particularly difficult to debug
    fontlist = []
    #  Add fonts from list of known font files.
    seen = {}
    for fpath in fontfiles:
        logger.debug("createFontDict %s", fpath)
        fname = os.path.split(fpath)[1]
        if fname in seen:
            continue
        else:
            seen[fname] = 1
        if fontext == 'afm':
            try:
                fh = open(fpath, 'r')
            except Exception:
                logger.error("Could not open font file %s",
                             fpath,
                             exc_info=True)
                continue
            try:
                try:
                    font = afm.AFM(fh)
                finally:
                    fh.close()
            except RuntimeError:
                logger.error("Could not parse font file %s",
                             fpath,
                             exc_info=True)
                continue
            try:
                prop = afmFontProperty(fpath, font)
            except Exception:
                logger.error("Could not covert font to FontEntry for file %s",
                             fpath,
                             exc_info=True)
                continue
        else:
            _, ext = os.path.splitext(fpath)
            try:
                if ext.lower() == ".ttc":
                    collection = TTCollection(six.text_type(fpath))
                    try:
                        props = []
                        for font in collection.fonts:
                            props.append(ttfFontProperty(fpath, font))
                        fontlist.extend(props)
                        continue
                    except Exception:
                        logger.error(
                            "Could not covert font to FontEntry for file %s",
                            fpath,
                            exc_info=True)
                        continue
                else:
                    font = TTFont(six.text_type(fpath))
            except (RuntimeError, TTLibError):
                logger.error("Could not open font file %s",
                             fpath,
                             exc_info=True)
                continue
            except UnicodeError:
                logger.error("Cannot handle unicode file: %s",
                             fpath,
                             exc_info=True)
                continue

            try:
                prop = ttfFontProperty(fpath, font)
            except Exception:
                logger.error("Could not covert font to FontEntry for file %s",
                             fpath,
                             exc_info=True)
                continue

        fontlist.append(prop)
    return fontlist
Пример #19
0
def test_lazy_open_file(lazy):
    with (TTX_DATA_DIR / "TestTTC.ttc").open("rb") as file:
        collection = TTCollection(file, lazy=lazy)
        assert len(collection) == 2
        assert collection[0]["maxp"].numGlyphs == 6
        assert collection[1]["maxp"].numGlyphs == 6