[ttc] Implement table sharing in save()
This commit is contained in:
parent
fb77bd0b0c
commit
370368d8c2
@ -215,6 +215,12 @@ class SFNTWriter(object):
|
|||||||
self.file.write(b'\0' * (self.nextTableOffset - self.file.tell()))
|
self.file.write(b'\0' * (self.nextTableOffset - self.file.tell()))
|
||||||
self.tables = OrderedDict()
|
self.tables = OrderedDict()
|
||||||
|
|
||||||
|
def setEntry(self, tag, entry):
|
||||||
|
if tag in self.tables:
|
||||||
|
raise TTLibError("cannot rewrite '%s' table" % tag)
|
||||||
|
|
||||||
|
self.tables[tag] = entry
|
||||||
|
|
||||||
def __setitem__(self, tag, data):
|
def __setitem__(self, tag, data):
|
||||||
"""Write raw table data to disk."""
|
"""Write raw table data to disk."""
|
||||||
if tag in self.tables:
|
if tag in self.tables:
|
||||||
@ -243,7 +249,10 @@ class SFNTWriter(object):
|
|||||||
self.file.write(b'\0' * (self.nextTableOffset - self.file.tell()))
|
self.file.write(b'\0' * (self.nextTableOffset - self.file.tell()))
|
||||||
assert self.nextTableOffset == self.file.tell()
|
assert self.nextTableOffset == self.file.tell()
|
||||||
|
|
||||||
self.tables[tag] = entry
|
self.setEntry(tag, entry)
|
||||||
|
|
||||||
|
def __getitem__(self, tag):
|
||||||
|
return self.tables[tag]
|
||||||
|
|
||||||
def close(self):
|
def close(self):
|
||||||
"""All tables must have been written to disk. Now write the
|
"""All tables must have been written to disk. Now write the
|
||||||
|
@ -37,7 +37,7 @@ class TTCollection(object):
|
|||||||
font = TTFont(file, fontNumber=i, _tableCache=tableCache, **kwargs)
|
font = TTFont(file, fontNumber=i, _tableCache=tableCache, **kwargs)
|
||||||
fonts.append(font)
|
fonts.append(font)
|
||||||
|
|
||||||
def save(self, file):
|
def save(self, file, shareTables=True):
|
||||||
"""Save the font to disk. Similarly to the constructor,
|
"""Save the font to disk. Similarly to the constructor,
|
||||||
the 'file' argument can be either a pathname or a writable
|
the 'file' argument can be either a pathname or a writable
|
||||||
file object.
|
file object.
|
||||||
@ -51,12 +51,13 @@ class TTCollection(object):
|
|||||||
final = file
|
final = file
|
||||||
file = BytesIO()
|
file = BytesIO()
|
||||||
|
|
||||||
offsets_offset = writeTTCHeader(file, len(self.fonts))
|
tableCache = {} if shareTables else None
|
||||||
|
|
||||||
|
offsets_offset = writeTTCHeader(file, len(self.fonts))
|
||||||
offsets = []
|
offsets = []
|
||||||
for font in self.fonts:
|
for font in self.fonts:
|
||||||
offsets.append(file.tell())
|
offsets.append(file.tell())
|
||||||
font._save(file)
|
font._save(file, tableCache=tableCache)
|
||||||
file.seek(0,2)
|
file.seek(0,2)
|
||||||
|
|
||||||
file.seek(offsets_offset)
|
file.seek(offsets_offset)
|
||||||
|
@ -134,7 +134,7 @@ class TTFont(object):
|
|||||||
if closeStream:
|
if closeStream:
|
||||||
file.close()
|
file.close()
|
||||||
file = tmp
|
file = tmp
|
||||||
self.tableCache = _tableCache
|
self._tableCache = _tableCache
|
||||||
self.reader = SFNTReader(file, checkChecksums, fontNumber=fontNumber)
|
self.reader = SFNTReader(file, checkChecksums, fontNumber=fontNumber)
|
||||||
self.sfntVersion = self.reader.sfntVersion
|
self.sfntVersion = self.reader.sfntVersion
|
||||||
self.flavor = self.reader.flavor
|
self.flavor = self.reader.flavor
|
||||||
@ -186,7 +186,7 @@ class TTFont(object):
|
|||||||
if closeStream:
|
if closeStream:
|
||||||
file.close()
|
file.close()
|
||||||
|
|
||||||
def _save(self, file):
|
def _save(self, file, tableCache=None):
|
||||||
"""Internal function, to be shared by save() and TTCollection.save()"""
|
"""Internal function, to be shared by save() and TTCollection.save()"""
|
||||||
|
|
||||||
if self.recalcTimestamp and 'head' in self:
|
if self.recalcTimestamp and 'head' in self:
|
||||||
@ -201,7 +201,7 @@ class TTFont(object):
|
|||||||
|
|
||||||
done = []
|
done = []
|
||||||
for tag in tags:
|
for tag in tags:
|
||||||
self._writeTable(tag, writer, done)
|
self._writeTable(tag, writer, done, tableCache)
|
||||||
|
|
||||||
writer.close()
|
writer.close()
|
||||||
|
|
||||||
@ -380,8 +380,8 @@ class TTFont(object):
|
|||||||
import traceback
|
import traceback
|
||||||
log.debug("Reading '%s' table from disk", tag)
|
log.debug("Reading '%s' table from disk", tag)
|
||||||
data = self.reader[tag]
|
data = self.reader[tag]
|
||||||
if self.tableCache is not None:
|
if self._tableCache is not None:
|
||||||
table = self.tableCache.get((Tag(tag), data))
|
table = self._tableCache.get((Tag(tag), data))
|
||||||
if table is not None:
|
if table is not None:
|
||||||
return table
|
return table
|
||||||
tableClass = getTableClass(tag)
|
tableClass = getTableClass(tag)
|
||||||
@ -403,8 +403,8 @@ class TTFont(object):
|
|||||||
table.ERROR = file.getvalue()
|
table.ERROR = file.getvalue()
|
||||||
self.tables[tag] = table
|
self.tables[tag] = table
|
||||||
table.decompile(data, self)
|
table.decompile(data, self)
|
||||||
if self.tableCache is not None:
|
if self._tableCache is not None:
|
||||||
self.tableCache[(Tag(tag), data)] = table
|
self._tableCache[(Tag(tag), data)] = table
|
||||||
return table
|
return table
|
||||||
else:
|
else:
|
||||||
raise KeyError("'%s' table not found" % tag)
|
raise KeyError("'%s' table not found" % tag)
|
||||||
@ -612,7 +612,7 @@ class TTFont(object):
|
|||||||
for glyphID in range(len(glyphOrder)):
|
for glyphID in range(len(glyphOrder)):
|
||||||
d[glyphOrder[glyphID]] = glyphID
|
d[glyphOrder[glyphID]] = glyphID
|
||||||
|
|
||||||
def _writeTable(self, tag, writer, done):
|
def _writeTable(self, tag, writer, done, tableCache=None):
|
||||||
"""Internal helper function for self.save(). Keeps track of
|
"""Internal helper function for self.save(). Keeps track of
|
||||||
inter-table dependencies.
|
inter-table dependencies.
|
||||||
"""
|
"""
|
||||||
@ -622,13 +622,21 @@ class TTFont(object):
|
|||||||
for masterTable in tableClass.dependencies:
|
for masterTable in tableClass.dependencies:
|
||||||
if masterTable not in done:
|
if masterTable not in done:
|
||||||
if masterTable in self:
|
if masterTable in self:
|
||||||
self._writeTable(masterTable, writer, done)
|
self._writeTable(masterTable, writer, done, tableCache)
|
||||||
else:
|
else:
|
||||||
done.append(masterTable)
|
done.append(masterTable)
|
||||||
|
done.append(tag)
|
||||||
tabledata = self.getTableData(tag)
|
tabledata = self.getTableData(tag)
|
||||||
|
if tableCache is not None:
|
||||||
|
entry = tableCache.get((Tag(tag), tabledata))
|
||||||
|
if entry is not None:
|
||||||
|
log.debug("reusing '%s' table", tag)
|
||||||
|
writer.setEntry(tag, entry)
|
||||||
|
return
|
||||||
log.debug("writing '%s' table to disk", tag)
|
log.debug("writing '%s' table to disk", tag)
|
||||||
writer[tag] = tabledata
|
writer[tag] = tabledata
|
||||||
done.append(tag)
|
if tableCache is not None:
|
||||||
|
tableCache[(Tag(tag), tabledata)] = writer[tag]
|
||||||
|
|
||||||
def getTableData(self, tag):
|
def getTableData(self, tag):
|
||||||
"""Returns raw table data, whether compiled or directly read from disk.
|
"""Returns raw table data, whether compiled or directly read from disk.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user