123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126 |
- from fontTools.ttLib.ttFont import TTFont
- from fontTools.ttLib.sfnt import readTTCHeader, writeTTCHeader
- from io import BytesIO
- import struct
- import logging
- log = logging.getLogger(__name__)
- class TTCollection(object):
- """Object representing a TrueType Collection / OpenType Collection.
- The main API is self.fonts being a list of TTFont instances.
- If shareTables is True, then different fonts in the collection
- might point to the same table object if the data for the table was
- the same in the font file. Note, however, that this might result
- in suprises and incorrect behavior if the different fonts involved
- have different GlyphOrder. Use only if you know what you are doing.
- """
- 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()
- def __enter__(self):
- return self
- def __exit__(self, type, value, traceback):
- self.close()
- def close(self):
- for font in self.fonts:
- font.close()
- def save(self, file, shareTables=True):
- """Save the font to disk. Similarly to the constructor,
- the 'file' argument can be either a pathname or a writable
- file object.
- """
- if not hasattr(file, "write"):
- final = None
- file = open(file, "wb")
- else:
- # assume "file" is a writable file object
- # write to a temporary stream to allow saving to unseekable streams
- final = file
- file = BytesIO()
- tableCache = {} if shareTables else None
- offsets_offset = writeTTCHeader(file, len(self.fonts))
- offsets = []
- for font in self.fonts:
- offsets.append(file.tell())
- font._save(file, tableCache=tableCache)
- file.seek(0, 2)
- file.seek(offsets_offset)
- file.write(struct.pack(">%dL" % len(self.fonts), *offsets))
- if final:
- final.write(file.getvalue())
- file.close()
- def saveXML(self, fileOrPath, newlinestr="\n", writeVersion=True, **kwargs):
- from fontTools.misc import xmlWriter
- writer = xmlWriter.XMLWriter(fileOrPath, newlinestr=newlinestr)
- if writeVersion:
- from fontTools import version
- version = ".".join(version.split(".")[:2])
- writer.begintag("ttCollection", ttLibVersion=version)
- else:
- writer.begintag("ttCollection")
- writer.newline()
- writer.newline()
- for font in self.fonts:
- font._saveXML(writer, writeVersion=False, **kwargs)
- writer.newline()
- writer.endtag("ttCollection")
- writer.newline()
- writer.close()
- def __getitem__(self, item):
- return self.fonts[item]
- def __setitem__(self, item, value):
- self.fonts[item] = value
- def __delitem__(self, item):
- return self.fonts[item]
- def __len__(self):
- return len(self.fonts)
- def __iter__(self):
- return iter(self.fonts)
|