• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1from fontTools.ttLib.ttFont import TTFont
2from fontTools.ttLib.sfnt import readTTCHeader, writeTTCHeader
3from io import BytesIO
4import struct
5import logging
6
7log = logging.getLogger(__name__)
8
9
10class TTCollection(object):
11
12	"""Object representing a TrueType Collection / OpenType Collection.
13	The main API is self.fonts being a list of TTFont instances.
14
15	If shareTables is True, then different fonts in the collection
16	might point to the same table object if the data for the table was
17	the same in the font file.  Note, however, that this might result
18	in suprises and incorrect behavior if the different fonts involved
19	have different GlyphOrder.  Use only if you know what you are doing.
20	"""
21
22	def __init__(self, file=None, shareTables=False, **kwargs):
23		fonts = self.fonts = []
24		if file is None:
25			return
26
27		assert 'fontNumber' not in kwargs, kwargs
28
29		if not hasattr(file, "read"):
30			file = open(file, "rb")
31
32		tableCache = {} if shareTables else None
33
34		header = readTTCHeader(file)
35		for i in range(header.numFonts):
36			font = TTFont(file, fontNumber=i, _tableCache=tableCache, **kwargs)
37			fonts.append(font)
38
39	def __enter__(self):
40		return self
41
42	def __exit__(self, type, value, traceback):
43		self.close()
44
45	def close(self):
46		for font in self.fonts:
47			font.close()
48
49	def save(self, file, shareTables=True):
50		"""Save the font to disk. Similarly to the constructor,
51		the 'file' argument can be either a pathname or a writable
52		file object.
53		"""
54		if not hasattr(file, "write"):
55			final = None
56			file = open(file, "wb")
57		else:
58			# assume "file" is a writable file object
59			# write to a temporary stream to allow saving to unseekable streams
60			final = file
61			file = BytesIO()
62
63		tableCache = {} if shareTables else None
64
65		offsets_offset = writeTTCHeader(file, len(self.fonts))
66		offsets = []
67		for font in self.fonts:
68			offsets.append(file.tell())
69			font._save(file, tableCache=tableCache)
70			file.seek(0,2)
71
72		file.seek(offsets_offset)
73		file.write(struct.pack(">%dL" % len(self.fonts), *offsets))
74
75		if final:
76			final.write(file.getvalue())
77		file.close()
78
79	def saveXML(self, fileOrPath, newlinestr=None, writeVersion=True, **kwargs):
80
81		from fontTools.misc import xmlWriter
82		writer = xmlWriter.XMLWriter(fileOrPath, newlinestr=newlinestr)
83
84		if writeVersion:
85			from fontTools import version
86			version = ".".join(version.split('.')[:2])
87			writer.begintag("ttCollection", ttLibVersion=version)
88		else:
89			writer.begintag("ttCollection")
90		writer.newline()
91		writer.newline()
92
93		for font in self.fonts:
94			font._saveXML(writer, writeVersion=False, **kwargs)
95			writer.newline()
96
97		writer.endtag("ttCollection")
98		writer.newline()
99
100		writer.close()
101
102
103	def __getitem__(self, item):
104		return self.fonts[item]
105
106	def __setitem__(self, item, value):
107		self.fonts[item] = value
108
109	def __delitem__(self, item):
110		return self.fonts[item]
111
112	def __len__(self):
113		return len(self.fonts)
114
115	def __iter__(self):
116		return iter(self.fonts)
117