Merge pull request #1130 from anthrotype/temp-revert-split-glyphs

Temporarily revert PR #1035 bamidei/split_g_l_y_f_to_one_per_file
This commit is contained in:
Cosimo Lupo 2017-12-18 12:21:47 +00:00 committed by GitHub
commit 060f856f92
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 49 additions and 160 deletions

View File

@ -17,8 +17,7 @@ BUFSIZE = 0x4000
class XMLReader(object): class XMLReader(object):
def __init__(self, fileOrPath, ttFont, progress=None, quiet=None, contentOnly=False): def __init__(self, fileOrPath, ttFont, progress=None, quiet=None):
if fileOrPath == '-': if fileOrPath == '-':
fileOrPath = sys.stdin fileOrPath = sys.stdin
if not hasattr(fileOrPath, "read"): if not hasattr(fileOrPath, "read"):
@ -36,7 +35,6 @@ class XMLReader(object):
self.quiet = quiet self.quiet = quiet
self.root = None self.root = None
self.contentStack = [] self.contentStack = []
self.contentOnly = contentOnly
self.stackSize = 0 self.stackSize = 0
def read(self, rootless=False): def read(self, rootless=False):
@ -75,24 +73,8 @@ class XMLReader(object):
parser.Parse(chunk, 0) parser.Parse(chunk, 0)
def _startElementHandler(self, name, attrs): def _startElementHandler(self, name, attrs):
if self.stackSize == 1 and self.contentOnly:
# We already know the table we're parsing, skip
# parsing the table tag and continue to
# stack '2' which begins parsing content
self.contentStack.append([])
self.stackSize = 2
return
stackSize = self.stackSize stackSize = self.stackSize
self.stackSize = stackSize + 1 self.stackSize = stackSize + 1
subFile = attrs.get("src")
if subFile is not None:
if hasattr(self.file, 'name'):
# if file has a name, get its parent directory
dirname = os.path.dirname(self.file.name)
else:
# else fall back to using the current working directory
dirname = os.getcwd()
subFile = os.path.join(dirname, subFile)
if not stackSize: if not stackSize:
if name != "ttFont": if name != "ttFont":
raise TTXParseError("illegal root tag: %s" % name) raise TTXParseError("illegal root tag: %s" % name)
@ -103,7 +85,15 @@ class XMLReader(object):
self.ttFont.sfntVersion = sfntVersion self.ttFont.sfntVersion = sfntVersion
self.contentStack.append([]) self.contentStack.append([])
elif stackSize == 1: elif stackSize == 1:
subFile = attrs.get("src")
if subFile is not None: if subFile is not None:
if hasattr(self.file, 'name'):
# if file has a name, get its parent directory
dirname = os.path.dirname(self.file.name)
else:
# else fall back to using the current working directory
dirname = os.getcwd()
subFile = os.path.join(dirname, subFile)
subReader = XMLReader(subFile, self.ttFont, self.progress) subReader = XMLReader(subFile, self.ttFont, self.progress)
subReader.read() subReader.read()
self.contentStack.append([]) self.contentStack.append([])
@ -129,11 +119,6 @@ class XMLReader(object):
self.currentTable = tableClass(tag) self.currentTable = tableClass(tag)
self.ttFont[tag] = self.currentTable self.ttFont[tag] = self.currentTable
self.contentStack.append([]) self.contentStack.append([])
elif stackSize == 2 and subFile is not None:
subReader = XMLReader(subFile, self.ttFont, self.progress, contentOnly=True)
subReader.read()
self.contentStack.append([])
self.root = subReader.root
elif stackSize == 2: elif stackSize == 2:
self.contentStack.append([]) self.contentStack.append([])
self.root = (name, attrs, self.contentStack[-1]) self.root = (name, attrs, self.contentStack[-1])
@ -149,13 +134,12 @@ class XMLReader(object):
def _endElementHandler(self, name): def _endElementHandler(self, name):
self.stackSize = self.stackSize - 1 self.stackSize = self.stackSize - 1
del self.contentStack[-1] del self.contentStack[-1]
if not self.contentOnly: if self.stackSize == 1:
if self.stackSize == 1: self.root = None
self.root = None elif self.stackSize == 2:
elif self.stackSize == 2: name, attrs, content = self.root
name, attrs, content = self.root self.currentTable.fromXML(name, attrs, content, self.ttFont)
self.currentTable.fromXML(name, attrs, content, self.ttFont) self.root = None
self.root = None
class ProgressPrinter(object): class ProgressPrinter(object):

View File

@ -247,8 +247,7 @@ class TTFont(object):
def saveXML(self, fileOrPath, progress=None, quiet=None, def saveXML(self, fileOrPath, progress=None, quiet=None,
tables=None, skipTables=None, splitTables=False, disassembleInstructions=True, tables=None, skipTables=None, splitTables=False, disassembleInstructions=True,
splitGlyphs=False, bitmapGlyphDataFormat='raw', newlinestr=None): bitmapGlyphDataFormat='raw', newlinestr=None):
"""Export the font as TTX (an XML-based text file), or as a series of text """Export the font as TTX (an XML-based text file), or as a series of text
files when splitTables is true. In the latter case, the 'fileOrPath' files when splitTables is true. In the latter case, the 'fileOrPath'
argument should be a path to a directory. argument should be a path to a directory.
@ -291,7 +290,7 @@ class TTFont(object):
if not splitTables: if not splitTables:
writer.newline() writer.newline()
if splitTables or splitGlyphs: else:
# 'fileOrPath' must now be a path # 'fileOrPath' must now be a path
path, ext = os.path.splitext(fileOrPath) path, ext = os.path.splitext(fileOrPath)
fileNameTemplate = path + ".%s" + ext fileNameTemplate = path + ".%s" + ext
@ -300,11 +299,8 @@ class TTFont(object):
if progress: if progress:
progress.set(i) progress.set(i)
tag = tables[i] tag = tables[i]
if splitTables or (splitGlyphs and tag == 'glyf'):
tablePath = fileNameTemplate % tagToIdentifier(tag)
else:
tablePath = None
if splitTables: if splitTables:
tablePath = fileNameTemplate % tagToIdentifier(tag)
tableWriter = xmlWriter.XMLWriter(tablePath, idlefunc=idlefunc, tableWriter = xmlWriter.XMLWriter(tablePath, idlefunc=idlefunc,
newlinestr=newlinestr) newlinestr=newlinestr)
tableWriter.begintag("ttFont", ttLibVersion=version) tableWriter.begintag("ttFont", ttLibVersion=version)
@ -314,7 +310,7 @@ class TTFont(object):
writer.newline() writer.newline()
else: else:
tableWriter = writer tableWriter = writer
self._tableToXML(tableWriter, tag, progress, splitGlyphs=splitGlyphs) self._tableToXML(tableWriter, tag, progress)
if splitTables: if splitTables:
tableWriter.endtag("ttFont") tableWriter.endtag("ttFont")
tableWriter.newline() tableWriter.newline()
@ -328,7 +324,7 @@ class TTFont(object):
if not hasattr(fileOrPath, "write") and fileOrPath != "-": if not hasattr(fileOrPath, "write") and fileOrPath != "-":
writer.close() writer.close()
def _tableToXML(self, writer, tag, progress, splitGlyphs=False, quiet=None): def _tableToXML(self, writer, tag, progress, quiet=None):
if quiet is not None: if quiet is not None:
deprecateArgument("quiet", "configure logging instead") deprecateArgument("quiet", "configure logging instead")
if tag in self: if tag in self:
@ -350,9 +346,7 @@ class TTFont(object):
attrs['raw'] = True attrs['raw'] = True
writer.begintag(xmlTag, **attrs) writer.begintag(xmlTag, **attrs)
writer.newline() writer.newline()
if tag == "glyf": if tag in ("glyf", "CFF "):
table.toXML(writer, self, progress, splitGlyphs)
elif tag == "CFF ":
table.toXML(writer, self, progress) table.toXML(writer, self, progress)
else: else:
table.toXML(writer, self) table.toXML(writer, self)
@ -879,8 +873,8 @@ def _escapechar(c):
return hex(byteord(c))[2:] return hex(byteord(c))[2:]
def nameToIdentifier(name): def tagToIdentifier(tag):
"""Convert a name to a valid (but UGLY) python identifier, """Convert a table tag to a valid (but UGLY) python identifier,
as well as a filename that's guaranteed to be unique even on a as well as a filename that's guaranteed to be unique even on a
caseless file system. Each character is mapped to two characters. caseless file system. Each character is mapped to two characters.
Lowercase letters get an underscore before the letter, uppercase Lowercase letters get an underscore before the letter, uppercase
@ -893,25 +887,19 @@ def nameToIdentifier(name):
'OS/2' -> 'O_S_2f_2' 'OS/2' -> 'O_S_2f_2'
""" """
import re import re
while len(name) > 1 and name[-1] == ' ': tag = Tag(tag)
name = name[:-1] if tag == "GlyphOrder":
return tag
assert len(tag) == 4, "tag should be 4 characters long"
while len(tag) > 1 and tag[-1] == ' ':
tag = tag[:-1]
ident = "" ident = ""
for c in name: for c in tag:
ident = ident + _escapechar(c) ident = ident + _escapechar(c)
if re.match("[0-9]", ident): if re.match("[0-9]", ident):
ident = "_" + ident ident = "_" + ident
return ident return ident
def tagToIdentifier(tag):
"""This performs the same conversion which nameToIdentifiier does
with the additional assertion that the source tag is 4 characters
long which is criteria for a valid tag name.
"""
if tag == "GlyphOrder":
return tag
ret = nameToIdentifier(tag)
assert len(tag) == 4, "tag should be 4 characters long"
return ret
def identifierToTag(ident): def identifierToTag(ident):
"""the opposite of tagToIdentifier()""" """the opposite of tagToIdentifier()"""

View File

@ -5,7 +5,6 @@ from collections import namedtuple
from fontTools.misc.py23 import * from fontTools.misc.py23 import *
from fontTools.misc import sstruct from fontTools.misc import sstruct
from fontTools import ttLib from fontTools import ttLib
from fontTools import version
from fontTools.misc.textTools import safeEval, pad from fontTools.misc.textTools import safeEval, pad
from fontTools.misc.arrayTools import calcBounds, calcIntBounds, pointInRect from fontTools.misc.arrayTools import calcBounds, calcIntBounds, pointInRect
from fontTools.misc.bezierTools import calcQuadraticBounds from fontTools.misc.bezierTools import calcQuadraticBounds
@ -17,17 +16,10 @@ import sys
import struct import struct
import array import array
import logging import logging
import os
from fontTools.misc import xmlWriter
from fontTools.ttLib import nameToIdentifier
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
# We compute the version the same as is computed in ttlib/__init__
# so that we can write 'ttLibVersion' attribute of the glyf TTX files
# when glyf is written to separate files.
version = ".".join(version.split('.')[:2])
# #
# The Apple and MS rasterizers behave differently for # The Apple and MS rasterizers behave differently for
# scaled composite components: one does scale first and then translate # scaled composite components: one does scale first and then translate
@ -118,16 +110,12 @@ class table__g_l_y_f(DefaultTable.DefaultTable):
ttFont['maxp'].numGlyphs = len(self.glyphs) ttFont['maxp'].numGlyphs = len(self.glyphs)
return data return data
def toXML(self, writer, ttFont, progress=None, splitGlyphs=False): def toXML(self, writer, ttFont, progress=None):
notice = ( writer.newline()
"The xMin, yMin, xMax and yMax values\n"
"will be recalculated by the compiler.")
glyphNames = ttFont.getGlyphNames() glyphNames = ttFont.getGlyphNames()
if not splitGlyphs: writer.comment("The xMin, yMin, xMax and yMax values\nwill be recalculated by the compiler.")
writer.newline() writer.newline()
writer.comment(notice) writer.newline()
writer.newline()
writer.newline()
counter = 0 counter = 0
progressStep = 10 progressStep = 10
numGlyphs = len(glyphNames) numGlyphs = len(glyphNames)
@ -138,44 +126,21 @@ class table__g_l_y_f(DefaultTable.DefaultTable):
counter = counter + 1 counter = counter + 1
glyph = self[glyphName] glyph = self[glyphName]
if glyph.numberOfContours: if glyph.numberOfContours:
if splitGlyphs: writer.begintag('TTGlyph', [
path, ext = os.path.splitext(writer.file.name) ("name", glyphName),
fileNameTemplate = path + ".%s" + ext ("xMin", glyph.xMin),
glyphPath = fileNameTemplate % nameToIdentifier(glyphName) ("yMin", glyph.yMin),
glyphWriter = xmlWriter.XMLWriter( ("xMax", glyph.xMax),
glyphPath, idlefunc=writer.idlefunc, ("yMax", glyph.yMax),
newlinestr=writer.newlinestr) ])
glyphWriter.begintag("ttFont", ttLibVersion=version) writer.newline()
glyphWriter.newline() glyph.toXML(writer, ttFont)
glyphWriter.begintag("glyf") writer.endtag('TTGlyph')
glyphWriter.newline() writer.newline()
glyphWriter.comment(notice)
glyphWriter.newline()
writer.simpletag("TTGlyph", src=os.path.basename(glyphPath))
else:
glyphWriter = writer
glyphWriter.begintag('TTGlyph', [
("name", glyphName),
("xMin", glyph.xMin),
("yMin", glyph.yMin),
("xMax", glyph.xMax),
("yMax", glyph.yMax),
])
glyphWriter.newline()
glyph.toXML(glyphWriter, ttFont)
glyphWriter.endtag('TTGlyph')
glyphWriter.newline()
if splitGlyphs:
glyphWriter.endtag("glyf")
glyphWriter.newline()
glyphWriter.endtag("ttFont")
glyphWriter.newline()
glyphWriter.close()
else: else:
writer.simpletag('TTGlyph', name=glyphName) writer.simpletag('TTGlyph', name=glyphName)
writer.comment("contains no outline data") writer.comment("contains no outline data")
if not splitGlyphs: writer.newline()
writer.newline()
writer.newline() writer.newline()
def fromXML(self, name, attrs, content, ttFont): def fromXML(self, name, attrs, content, ttFont):

View File

@ -38,9 +38,6 @@ usage: ttx [options] inputfile1 [... inputfileN]
to the individual table dumps. This file can be used as to the individual table dumps. This file can be used as
input to ttx, as long as the table files are in the input to ttx, as long as the table files are in the
same directory. same directory.
-g Split glyf table: Save the glyf data into separate TTX files
per glyph and write a small TTX for the glyf table which
contains references to the individual TTGlyph elements.
-i Do NOT disassemble TT instructions: when this option is given, -i Do NOT disassemble TT instructions: when this option is given,
all TrueType programs (glyph programs, the font program and the all TrueType programs (glyph programs, the font program and the
pre-program) will be written to the TTX file as hex data pre-program) will be written to the TTX file as hex data
@ -113,7 +110,6 @@ class Options(object):
verbose = False verbose = False
quiet = False quiet = False
splitTables = False splitTables = False
splitGlyphs = False
disassembleInstructions = True disassembleInstructions = True
mergeFile = None mergeFile = None
recalcBBoxes = True recalcBBoxes = True
@ -164,8 +160,6 @@ class Options(object):
self.skipTables.append(value) self.skipTables.append(value)
elif option == "-s": elif option == "-s":
self.splitTables = True self.splitTables = True
elif option == "-g":
self.splitGlyphs = True
elif option == "-i": elif option == "-i":
self.disassembleInstructions = False self.disassembleInstructions = False
elif option == "-z": elif option == "-z":
@ -261,7 +255,6 @@ def ttDump(input, output, options):
tables=options.onlyTables, tables=options.onlyTables,
skipTables=options.skipTables, skipTables=options.skipTables,
splitTables=options.splitTables, splitTables=options.splitTables,
splitGlyphs=options.splitGlyphs,
disassembleInstructions=options.disassembleInstructions, disassembleInstructions=options.disassembleInstructions,
bitmapGlyphDataFormat=options.bitmapGlyphDataFormat, bitmapGlyphDataFormat=options.bitmapGlyphDataFormat,
newlinestr=options.newlinestr) newlinestr=options.newlinestr)
@ -325,7 +318,7 @@ def guessFileType(fileName):
def parseOptions(args): def parseOptions(args):
rawOptions, files = getopt.getopt(args, "ld:o:fvqht:x:sgim:z:baey:", rawOptions, files = getopt.getopt(args, "ld:o:fvqht:x:sim:z:baey:",
['unicodedata=', "recalc-timestamp", 'flavor=', 'version', ['unicodedata=', "recalc-timestamp", 'flavor=', 'version',
'with-zopfli', 'newline=']) 'with-zopfli', 'newline='])

View File

@ -142,48 +142,7 @@ class TestXMLReader(unittest.TestCase):
self.assertTrue(reader.file.closed) self.assertTrue(reader.file.closed)
os.remove(tmp.name) os.remove(tmp.name)
def test_read_sub_file(self):
# Verifies that sub-file content is able to be read to a table.
expectedContent = u'testContent'
expectedNameID = '1'
expectedPlatform = '3'
expectedLangId = '0x409'
with tempfile.NamedTemporaryFile(delete=False) as tmp:
subFileData = (
'<ttFont ttLibVersion="3.15">'
'<name>'
'<namerecord nameID="%s" platformID="%s" platEncID="1" langID="%s">'
'%s'
'</namerecord>'
'</name>'
'</ttFont>'
) % (expectedNameID, expectedPlatform, expectedLangId, expectedContent)
tmp.write(subFileData.encode("utf-8"))
with tempfile.NamedTemporaryFile(delete=False) as tmp2:
fileData = (
'<ttFont ttLibVersion="3.15">'
'<name>'
'<namerecord src="%s"/>'
'</name>'
'</ttFont>'
) % tmp.name
tmp2.write(fileData.encode('utf-8'))
ttf = TTFont()
with open(tmp2.name, "rb") as f:
reader = XMLReader(f, ttf)
reader.read()
reader.close()
nameTable = ttf['name']
self.assertTrue(int(expectedNameID) == nameTable.names[0].nameID)
self.assertTrue(int(expectedLangId, 16) == nameTable.names[0].langID)
self.assertTrue(int(expectedPlatform) == nameTable.names[0].platformID)
self.assertEqual(expectedContent, nameTable.names[0].string.decode(nameTable.names[0].getEncoding()))
os.remove(tmp.name)
os.remove(tmp2.name)
if __name__ == '__main__': if __name__ == '__main__':
import sys import sys