CFF/T2 <-> XML roundtripping has begun!
git-svn-id: svn://svn.code.sf.net/p/fonttools/code/trunk@254 4cde692c-a291-49d1-8350-778aa11640f8
This commit is contained in:
parent
f2cf9c5d6d
commit
4e5af60930
@ -1,13 +1,14 @@
|
||||
"""cffLib.py -- read/write tools for Adobe CFF fonts."""
|
||||
|
||||
#
|
||||
# $Id: cffLib.py,v 1.21 2002-05-23 21:50:36 jvr Exp $
|
||||
# $Id: cffLib.py,v 1.22 2002-05-24 09:58:03 jvr Exp $
|
||||
#
|
||||
|
||||
import struct, sstruct
|
||||
import string
|
||||
from types import FloatType, ListType, TupleType
|
||||
from types import FloatType, ListType, StringType, TupleType
|
||||
from fontTools.misc import psCharStrings
|
||||
from fontTools.misc.textTools import safeEval
|
||||
|
||||
|
||||
DEBUG = 0
|
||||
@ -25,16 +26,16 @@ class CFFFontSet:
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def decompile(self, file):
|
||||
def decompile(self, file, otFont):
|
||||
sstruct.unpack(cffHeaderFormat, file.read(4), self)
|
||||
assert self.major == 1 and self.minor == 0, \
|
||||
"unknown CFF format: %d.%d" % (self.major, self.minor)
|
||||
|
||||
file.seek(self.hdrSize)
|
||||
self.fontNames = list(Index(file, "fontNames"))
|
||||
self.fontNames = list(Index(file))
|
||||
self.topDictIndex = TopDictIndex(file)
|
||||
self.strings = IndexedStrings(file)
|
||||
self.GlobalSubrs = GlobalSubrsIndex(file, name="GlobalSubrsIndex")
|
||||
self.GlobalSubrs = GlobalSubrsIndex(file)
|
||||
self.topDictIndex.strings = self.strings
|
||||
self.topDictIndex.GlobalSubrs = self.GlobalSubrs
|
||||
|
||||
@ -54,7 +55,7 @@ class CFFFontSet:
|
||||
raise KeyError, name
|
||||
return self.topDictIndex[index]
|
||||
|
||||
def compile(self, file):
|
||||
def compile(self, file, otFont):
|
||||
strings = IndexedStrings()
|
||||
writer = CFFWriter()
|
||||
writer.add(sstruct.pack(cffHeaderFormat, self))
|
||||
@ -67,11 +68,14 @@ class CFFFontSet:
|
||||
writer.add(strings.getCompiler())
|
||||
writer.add(self.GlobalSubrs.getCompiler(strings, None))
|
||||
|
||||
for topDict in self.topDictIndex:
|
||||
if not hasattr(topDict, "charset") or topDict.charset is None:
|
||||
charset = otFont.getGlyphOrder()
|
||||
topDict.charset = charset
|
||||
|
||||
for child in topCompiler.getChildren(strings):
|
||||
writer.add(child)
|
||||
|
||||
print writer.data
|
||||
|
||||
writer.toFile(file)
|
||||
|
||||
def toXML(self, xmlWriter, progress=None):
|
||||
@ -92,7 +96,33 @@ class CFFFontSet:
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content)):
|
||||
xxx
|
||||
if not hasattr(self, "GlobalSubrs"):
|
||||
self.GlobalSubrs = GlobalSubrsIndex()
|
||||
self.major = 1
|
||||
self.minor = 0
|
||||
self.hdrSize = 4
|
||||
self.offSize = 4 # XXX ??
|
||||
if name == "CFFFont":
|
||||
if not hasattr(self, "fontNames"):
|
||||
self.fontNames = []
|
||||
self.topDictIndex = TopDictIndex()
|
||||
fontName = attrs["name"]
|
||||
topDict = TopDict(GlobalSubrs=self.GlobalSubrs)
|
||||
topDict.charset = None # gets filled in later
|
||||
self.fontNames.append(fontName)
|
||||
self.topDictIndex.append(topDict)
|
||||
for element in content:
|
||||
if isinstance(element, StringType):
|
||||
continue
|
||||
topDict.fromXML(element)
|
||||
elif name == "GlobalSubrs":
|
||||
for element in content:
|
||||
if isinstance(element, StringType):
|
||||
continue
|
||||
name, attrs, content = element
|
||||
subr = psCharStrings.T2CharString(None, subrs=None, globalSubrs=None)
|
||||
subr.fromXML((name, attrs, content))
|
||||
self.GlobalSubrs.append(subr)
|
||||
|
||||
|
||||
class CFFWriter:
|
||||
@ -107,21 +137,25 @@ class CFFWriter:
|
||||
lastPosList = None
|
||||
count = 1
|
||||
while 1:
|
||||
print "XXX iteration", count
|
||||
count += 1
|
||||
if DEBUG:
|
||||
print "CFFWriter.toFile() iteration:", count
|
||||
count = count + 1
|
||||
pos = 0
|
||||
posList = [pos]
|
||||
for item in self.data:
|
||||
if hasattr(item, "setPos"):
|
||||
item.setPos(pos)
|
||||
if hasattr(item, "getDataLength"):
|
||||
pos = pos + item.getDataLength()
|
||||
endPos = pos + item.getDataLength()
|
||||
else:
|
||||
pos = pos + len(item)
|
||||
endPos = pos + len(item)
|
||||
if hasattr(item, "setPos"):
|
||||
item.setPos(pos, endPos)
|
||||
pos = endPos
|
||||
posList.append(pos)
|
||||
if posList == lastPosList:
|
||||
break
|
||||
lastPosList = posList
|
||||
if DEBUG:
|
||||
print "CFFWriter.toFile() writing to file."
|
||||
begin = file.tell()
|
||||
posList = [0]
|
||||
for item in self.data:
|
||||
@ -130,10 +164,6 @@ class CFFWriter:
|
||||
else:
|
||||
file.write(item)
|
||||
posList.append(file.tell() - begin)
|
||||
if posList != lastPosList:
|
||||
print "++++"
|
||||
print posList
|
||||
print lastPosList
|
||||
assert posList == lastPosList
|
||||
|
||||
|
||||
@ -181,8 +211,6 @@ class IndexCompiler:
|
||||
return dataLength
|
||||
|
||||
def toFile(self, file):
|
||||
size = self.getDataLength()
|
||||
start = file.tell()
|
||||
offsets = self.getOffsets()
|
||||
writeCard16(file, len(self.items))
|
||||
offSize = calcOffSize(offsets[-1])
|
||||
@ -198,7 +226,6 @@ class IndexCompiler:
|
||||
item.toFile(file)
|
||||
else:
|
||||
file.write(item)
|
||||
assert start + size == file.tell()
|
||||
|
||||
|
||||
class IndexedStringsCompiler(IndexCompiler):
|
||||
@ -231,12 +258,12 @@ class GlobalSubrsCompiler(IndexCompiler):
|
||||
return out
|
||||
|
||||
class SubrsCompiler(GlobalSubrsCompiler):
|
||||
def setPos(self, pos):
|
||||
def setPos(self, pos, endPos):
|
||||
offset = pos - self.parent.pos
|
||||
self.parent.rawDict["Subrs"] = offset
|
||||
|
||||
class CharStringsCompiler(GlobalSubrsCompiler):
|
||||
def setPos(self, pos):
|
||||
def setPos(self, pos, endPos):
|
||||
self.parent.rawDict["CharStrings"] = pos
|
||||
|
||||
|
||||
@ -246,9 +273,8 @@ class Index:
|
||||
|
||||
compilerClass = IndexCompiler
|
||||
|
||||
def __init__(self, file=None, name=None):
|
||||
if name is None:
|
||||
name = self.__class__.__name__
|
||||
def __init__(self, file=None):
|
||||
name = self.__class__.__name__
|
||||
if file is None:
|
||||
self.items = []
|
||||
return
|
||||
@ -308,9 +334,8 @@ class GlobalSubrsIndex(Index):
|
||||
|
||||
compilerClass = GlobalSubrsCompiler
|
||||
|
||||
def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None,
|
||||
name=None):
|
||||
Index.__init__(self, file, name)
|
||||
def __init__(self, file=None, globalSubrs=None, private=None, fdSelect=None, fdArray=None):
|
||||
Index.__init__(self, file)
|
||||
self.globalSubrs = globalSubrs
|
||||
self.private = private
|
||||
self.fdSelect = fdSelect
|
||||
@ -331,6 +356,9 @@ class GlobalSubrsIndex(Index):
|
||||
|
||||
def toXML(self, xmlWriter, progress):
|
||||
fdSelect = self.fdSelect
|
||||
xmlWriter.comment("The 'index' attribute is only for humans; "
|
||||
"it is ignored when parsed.")
|
||||
xmlWriter.newline()
|
||||
for i in range(len(self)):
|
||||
xmlWriter.begintag("CharString", index=i)
|
||||
xmlWriter.newline()
|
||||
@ -338,6 +366,13 @@ class GlobalSubrsIndex(Index):
|
||||
xmlWriter.endtag("CharString")
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content)):
|
||||
if name <> "CharString":
|
||||
return
|
||||
subr = psCharStrings.T2CharString(None, subrs=None, globalSubrs=None)
|
||||
subr.fromXML((name, attrs, content))
|
||||
self.append(subr)
|
||||
|
||||
def getItemAndSelector(self, index):
|
||||
fdSelect = self.fdSelect
|
||||
if fdSelect is None:
|
||||
@ -371,30 +406,55 @@ class TopDictIndex(Index):
|
||||
class CharStrings:
|
||||
|
||||
def __init__(self, file, charset, globalSubrs, private, fdSelect, fdArray):
|
||||
self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray)
|
||||
self.nameToIndex = nameToIndex = {}
|
||||
for i in range(len(charset)):
|
||||
nameToIndex[charset[i]] = i
|
||||
if file is not None:
|
||||
self.charStringsIndex = SubrsIndex(file, globalSubrs, private, fdSelect, fdArray)
|
||||
self.charStrings = charStrings = {}
|
||||
for i in range(len(charset)):
|
||||
charStrings[charset[i]] = i
|
||||
self.charStringsAreIndexed = 1
|
||||
else:
|
||||
self.charStrings = {}
|
||||
self.charStringsAreIndexed = 0
|
||||
self.globalSubrs = globalSubrs
|
||||
self.private = private
|
||||
self.fdSelect = fdSelect
|
||||
self.fdArray = fdArray
|
||||
|
||||
def keys(self):
|
||||
return self.nameToIndex.keys()
|
||||
return self.charStrings.keys()
|
||||
|
||||
def values(self):
|
||||
return self.charStringsIndex
|
||||
if self.charStringsAreIndexed:
|
||||
return self.charStringsIndex
|
||||
else:
|
||||
return self.charStrings.values()
|
||||
|
||||
def has_key(self, name):
|
||||
return self.nameToIndex.has_key(name)
|
||||
return self.charStrings.has_key(name)
|
||||
|
||||
def __len__(self):
|
||||
return len(self.charStringsIndex)
|
||||
return len(self.charStrings)
|
||||
|
||||
def __getitem__(self, name):
|
||||
index = self.nameToIndex[name]
|
||||
return self.charStringsIndex[index]
|
||||
charString = self.charStrings[name]
|
||||
if self.charStringsAreIndexed:
|
||||
charString = self.charStringsIndex[charString]
|
||||
return charString
|
||||
|
||||
def __setitem__(self, name, charString):
|
||||
if self.charStringsAreIndexed:
|
||||
index = self.charStrings[name]
|
||||
self.charStringsIndex[index] = charString
|
||||
else:
|
||||
self.charStrings[name] = charString
|
||||
|
||||
def getItemAndSelector(self, name):
|
||||
index = self.nameToIndex[name]
|
||||
return self.charStringsIndex.getItemAndSelector(index)
|
||||
if self.charStringsAreIndexed:
|
||||
index = self.charStrings[name]
|
||||
return self.charStringsIndex.getItemAndSelector(index)
|
||||
else:
|
||||
# XXX needs work for CID fonts
|
||||
return self.charStrings[name], None
|
||||
|
||||
def toXML(self, xmlWriter, progress):
|
||||
names = self.keys()
|
||||
@ -410,6 +470,23 @@ class CharStrings:
|
||||
self[name].toXML(xmlWriter)
|
||||
xmlWriter.endtag("CharString")
|
||||
xmlWriter.newline()
|
||||
|
||||
def fromXML(self, (name, attrs, content)):
|
||||
for element in content:
|
||||
if isinstance(element, StringType):
|
||||
continue
|
||||
name, attrs, content = element
|
||||
if name <> "CharString":
|
||||
continue
|
||||
glyphName = attrs["name"]
|
||||
if hasattr(self.private, "Subrs"):
|
||||
subrs = self.private.Subrs
|
||||
else:
|
||||
subrs = []
|
||||
globalSubrs = self.globalSubrs
|
||||
charString = psCharStrings.T2CharString(None, subrs=subrs, globalSubrs=globalSubrs)
|
||||
charString.fromXML((name, attrs, content))
|
||||
self[glyphName] = charString
|
||||
|
||||
|
||||
def readCard8(file):
|
||||
@ -467,40 +544,78 @@ def buildConverters(table):
|
||||
return d
|
||||
|
||||
|
||||
class BaseConverter:
|
||||
class SimpleConverter:
|
||||
def read(self, parent, value):
|
||||
return value
|
||||
def write(self, parent, value):
|
||||
return value
|
||||
def xmlWrite(self, xmlWriter, name, value):
|
||||
xmlWriter.simpletag(name, value=value)
|
||||
xmlWriter.newline()
|
||||
def xmlRead(self, (name, attrs, content), parent):
|
||||
return attrs["value"]
|
||||
|
||||
def parseNum(s):
|
||||
try:
|
||||
value = int(s)
|
||||
except:
|
||||
value = float(s)
|
||||
return value
|
||||
|
||||
class NumberConverter(SimpleConverter):
|
||||
def xmlRead(self, (name, attrs, content), parent):
|
||||
return parseNum(attrs["value"])
|
||||
|
||||
class ArrayConverter(SimpleConverter):
|
||||
def xmlWrite(self, xmlWriter, name, value):
|
||||
value = map(str, value)
|
||||
xmlWriter.simpletag(name, value=" ".join(value))
|
||||
xmlWriter.newline()
|
||||
def xmlRead(self, (name, attrs, content), parent):
|
||||
values = attrs["value"].split()
|
||||
return map(parseNum, values)
|
||||
|
||||
class TableConverter(SimpleConverter):
|
||||
def xmlWrite(self, xmlWriter, name, value):
|
||||
xmlWriter.begintag(name)
|
||||
xmlWriter.newline()
|
||||
value.toXML(xmlWriter, None)
|
||||
xmlWriter.endtag(name)
|
||||
xmlWriter.newline()
|
||||
def xmlRead(self, (name, attrs, content), parent):
|
||||
ob = self.getClass()()
|
||||
for element in content:
|
||||
if isinstance(element, StringType):
|
||||
continue
|
||||
ob.fromXML(element)
|
||||
return ob
|
||||
|
||||
class PrivateDictConverter(BaseConverter):
|
||||
class PrivateDictConverter(TableConverter):
|
||||
def getClass(self):
|
||||
return PrivateDict
|
||||
def read(self, parent, value):
|
||||
size, offset = value
|
||||
file = parent.file
|
||||
pr = PrivateDict(parent.strings, file, offset)
|
||||
priv = PrivateDict(parent.strings, file, offset)
|
||||
file.seek(offset)
|
||||
data = file.read(size)
|
||||
len(data) == size
|
||||
pr.decompile(data)
|
||||
return pr
|
||||
priv.decompile(data)
|
||||
return priv
|
||||
def write(self, parent, value):
|
||||
return (0, 0) # dummy value
|
||||
|
||||
class SubrsConverter(BaseConverter):
|
||||
class SubrsConverter(TableConverter):
|
||||
def getClass(self):
|
||||
return SubrsIndex
|
||||
def read(self, parent, value):
|
||||
file = parent.file
|
||||
file.seek(parent.offset + value) # Offset(self)
|
||||
return SubrsIndex(file, name="SubrsIndex")
|
||||
return SubrsIndex(file)
|
||||
def write(self, parent, value):
|
||||
return 0 # dummy value
|
||||
|
||||
class CharStringsConverter(BaseConverter):
|
||||
class CharStringsConverter(TableConverter):
|
||||
def read(self, parent, value):
|
||||
file = parent.file
|
||||
charset = parent.charset
|
||||
@ -515,6 +630,12 @@ class CharStringsConverter(BaseConverter):
|
||||
return CharStrings(file, charset, globalSubrs, private, fdSelect, fdArray)
|
||||
def write(self, parent, value):
|
||||
return 0 # dummy value
|
||||
def xmlRead(self, (name, attrs, content), parent):
|
||||
# XXX needs work for CID fonts
|
||||
fdSelect, fdArray = None, None
|
||||
charStrings = CharStrings(None, None, parent.GlobalSubrs, parent.Private, fdSelect, fdArray)
|
||||
charStrings.fromXML((name, attrs, content))
|
||||
return charStrings
|
||||
|
||||
class CharsetConverter:
|
||||
def read(self, parent, value):
|
||||
@ -554,9 +675,14 @@ class CharsetConverter:
|
||||
def write(self, parent, value):
|
||||
return 0 # dummy value
|
||||
def xmlWrite(self, xmlWriter, name, value):
|
||||
# XXX GlyphOrder needs to be stored *somewhere*, but not here...
|
||||
xmlWriter.simpletag("charset", value=value)
|
||||
# XXX only write charset when not in OT/TTX context, where we
|
||||
# dump charset as a separate "GlyphOrder" table.
|
||||
##xmlWriter.simpletag("charset")
|
||||
xmlWriter.comment("charset is dumped separately as the 'GlyphOrder' element")
|
||||
xmlWriter.newline()
|
||||
def xmlRead(self, (name, attrs, content), parent):
|
||||
if 0:
|
||||
return safeEval(attrs["value"])
|
||||
|
||||
|
||||
class CharsetCompiler:
|
||||
@ -570,7 +696,7 @@ class CharsetCompiler:
|
||||
self.data = "".join(data)
|
||||
self.parent = parent
|
||||
|
||||
def setPos(self, pos):
|
||||
def setPos(self, pos, endPos):
|
||||
self.parent.rawDict["charset"] = pos
|
||||
|
||||
def getDataLength(self):
|
||||
@ -607,7 +733,7 @@ def parseCharset(numGlyphs, file, strings, isCID, format):
|
||||
return charset
|
||||
|
||||
|
||||
class FDArrayConverter(BaseConverter):
|
||||
class FDArrayConverter(TableConverter):
|
||||
def read(self, parent, value):
|
||||
file = parent.file
|
||||
file.seek(value)
|
||||
@ -648,7 +774,7 @@ class FDSelectConverter:
|
||||
pass
|
||||
|
||||
|
||||
class ROSConverter(BaseConverter):
|
||||
class ROSConverter(SimpleConverter):
|
||||
def xmlWrite(self, xmlWriter, name, value):
|
||||
registry, order, supplement = value
|
||||
xmlWriter.simpletag(name, [('Registry', registry), ('Order', order),
|
||||
@ -718,6 +844,24 @@ privateDictOperators = [
|
||||
(19, 'Subrs', 'number', None, SubrsConverter()),
|
||||
]
|
||||
|
||||
def addConverters(table):
|
||||
for i in range(len(table)):
|
||||
op, name, arg, default, conv = table[i]
|
||||
if conv is not None:
|
||||
continue
|
||||
if arg in ("delta", "array"):
|
||||
conv = ArrayConverter()
|
||||
elif arg == "number":
|
||||
conv = NumberConverter()
|
||||
elif arg == "SID":
|
||||
conv = SimpleConverter()
|
||||
else:
|
||||
assert 0
|
||||
table[i] = op, name, arg, default, conv
|
||||
|
||||
addConverters(privateDictOperators)
|
||||
addConverters(topDictOperators)
|
||||
|
||||
|
||||
class TopDictDecompiler(psCharStrings.DictDecompiler):
|
||||
operators = buildOperatorDict(topDictOperators)
|
||||
@ -740,20 +884,21 @@ class DictCompiler:
|
||||
if value is None:
|
||||
continue
|
||||
conv = dictObj.converters[name]
|
||||
if conv:
|
||||
value = conv.write(dictObj, value)
|
||||
value = conv.write(dictObj, value)
|
||||
if value == dictObj.defaults.get(name):
|
||||
continue
|
||||
rawDict[name] = value
|
||||
self.rawDict = rawDict
|
||||
|
||||
def setPos(self, pos):
|
||||
def setPos(self, pos, endPos):
|
||||
pass
|
||||
|
||||
def getDataLength(self):
|
||||
return len(self.compile())
|
||||
return len(self.compile("getDataLength"))
|
||||
|
||||
def compile(self):
|
||||
def compile(self, reason):
|
||||
if DEBUG:
|
||||
print "-- compiling %s for %s" % (self.__class__.__name__, reason)
|
||||
rawDict = self.rawDict
|
||||
data = []
|
||||
for name in self.dictObj.order:
|
||||
@ -776,7 +921,7 @@ class DictCompiler:
|
||||
return "".join(data)
|
||||
|
||||
def toFile(self, file):
|
||||
file.write(self.compile())
|
||||
file.write(self.compile("toFile"))
|
||||
|
||||
def arg_number(self, num):
|
||||
return encodeNumber(num)
|
||||
@ -832,8 +977,8 @@ class PrivateDictCompiler(DictCompiler):
|
||||
|
||||
opcodes = buildOpcodeDict(privateDictOperators)
|
||||
|
||||
def setPos(self, pos):
|
||||
size = len(self.compile())
|
||||
def setPos(self, pos, endPos):
|
||||
size = endPos - pos
|
||||
self.parent.rawDict["Private"] = size, pos
|
||||
self.pos = pos
|
||||
|
||||
@ -846,7 +991,7 @@ class PrivateDictCompiler(DictCompiler):
|
||||
|
||||
class BaseDict:
|
||||
|
||||
def __init__(self, strings, file, offset):
|
||||
def __init__(self, strings=None, file=None, offset=None):
|
||||
self.rawDict = {}
|
||||
if DEBUG:
|
||||
print "loading %s at %s" % (self.__class__.__name__, offset)
|
||||
@ -876,8 +1021,7 @@ class BaseDict:
|
||||
if value is None:
|
||||
raise AttributeError, name
|
||||
conv = self.converters[name]
|
||||
if conv is not None:
|
||||
value = conv.read(self, value)
|
||||
value = conv.read(self, value)
|
||||
setattr(self, name, value)
|
||||
return value
|
||||
|
||||
@ -888,14 +1032,13 @@ class BaseDict:
|
||||
value = getattr(self, name, None)
|
||||
if value is None:
|
||||
continue
|
||||
conv = self.converters.get(name)
|
||||
if conv is not None:
|
||||
conv.xmlWrite(xmlWriter, name, value)
|
||||
else:
|
||||
if isinstance(value, ListType):
|
||||
value = " ".join(map(str, value))
|
||||
xmlWriter.simpletag(name, value=value)
|
||||
xmlWriter.newline()
|
||||
conv = self.converters[name]
|
||||
conv.xmlWrite(xmlWriter, name, value)
|
||||
|
||||
def fromXML(self, (name, attrs, content)):
|
||||
conv = self.converters[name]
|
||||
value = conv.xmlRead((name, attrs, content), self)
|
||||
setattr(self, name, value)
|
||||
|
||||
|
||||
class TopDict(BaseDict):
|
||||
@ -906,7 +1049,7 @@ class TopDict(BaseDict):
|
||||
decompilerClass = TopDictDecompiler
|
||||
compilerClass = TopDictCompiler
|
||||
|
||||
def __init__(self, strings, file, offset, GlobalSubrs):
|
||||
def __init__(self, strings=None, file=None, offset=None, GlobalSubrs=None):
|
||||
BaseDict.__init__(self, strings, file, offset)
|
||||
self.GlobalSubrs = GlobalSubrs
|
||||
|
||||
@ -932,6 +1075,7 @@ class TopDict(BaseDict):
|
||||
BaseDict.toXML(self, xmlWriter, progress)
|
||||
|
||||
def decompileAllCharStrings(self):
|
||||
# XXX only when doing ttdump -i?
|
||||
for charString in self.CharStrings.values():
|
||||
charString.decompile()
|
||||
|
||||
@ -952,7 +1096,7 @@ class IndexedStrings:
|
||||
if file is None:
|
||||
strings = []
|
||||
else:
|
||||
strings = list(Index(file, "IndexedStrings"))
|
||||
strings = list(Index(file))
|
||||
self.strings = strings
|
||||
|
||||
def getCompiler(self):
|
||||
|
@ -200,6 +200,9 @@ def encodeFloat(f):
|
||||
return d
|
||||
|
||||
|
||||
class CharStringCompileError(Exception): pass
|
||||
|
||||
|
||||
class T2CharString(ByteCodeBase):
|
||||
|
||||
operandEncoding = t2OperandEncoding
|
||||
@ -229,20 +232,35 @@ class T2CharString(ByteCodeBase):
|
||||
def compile(self):
|
||||
if self.bytecode is not None:
|
||||
return
|
||||
if self.program[-1] not in ("endchar", "return", "callsubr", "callgsubr", "seac"):
|
||||
print "XXX", self.program
|
||||
assert 0, "illegal CharString"
|
||||
bytecode = []
|
||||
opcodes = self.opcodes
|
||||
for token in self.program:
|
||||
program = self.program
|
||||
i = 0
|
||||
end = len(program)
|
||||
while i < end:
|
||||
token = program[i]
|
||||
i = i + 1
|
||||
tp = type(token)
|
||||
if tp == types.StringType:
|
||||
if opcodes.has_key(token):
|
||||
try:
|
||||
bytecode.extend(map(chr, opcodes[token]))
|
||||
else:
|
||||
bytecode.append(token) # hint mask
|
||||
except KeyError:
|
||||
raise CharStringCompileError, "illegal operator: %s" % token
|
||||
if token in ('hintmask', 'cntrmask'):
|
||||
bytecode.append(program[i]) # hint mask
|
||||
i = i + 1
|
||||
elif tp == types.IntType:
|
||||
bytecode.append(encodeIntT2(token))
|
||||
else:
|
||||
assert 0, "unsupported type: %s" % tp
|
||||
bytecode = "".join(bytecode)
|
||||
try:
|
||||
bytecode = "".join(bytecode)
|
||||
except TypeError:
|
||||
print bytecode
|
||||
raise
|
||||
self.setBytecode(bytecode)
|
||||
|
||||
def needsDecompilation(self):
|
||||
@ -321,6 +339,31 @@ class T2CharString(ByteCodeBase):
|
||||
args = []
|
||||
else:
|
||||
args.append(token)
|
||||
|
||||
def fromXML(self, (name, attrs, content)):
|
||||
from fontTools.misc.textTools import binary2num
|
||||
content = "".join(content)
|
||||
content = content.split()
|
||||
program = []
|
||||
end = len(content)
|
||||
i = 0
|
||||
while i < end:
|
||||
token = content[i]
|
||||
i = i + 1
|
||||
try:
|
||||
token = int(token)
|
||||
except ValueError:
|
||||
program.append(token)
|
||||
if token in ('hintmask', 'cntrmask'):
|
||||
mask = content[i]
|
||||
maskBytes = ""
|
||||
for j in range(0, len(mask), 8):
|
||||
maskBytes = maskBytes + chr(binary2num(mask[j:j+8]))
|
||||
program.append(maskBytes)
|
||||
i = i + 1
|
||||
else:
|
||||
program.append(token)
|
||||
self.setProgram(program)
|
||||
|
||||
|
||||
t1Operators = [
|
||||
@ -414,6 +457,8 @@ class SimpleT2Decompiler:
|
||||
pushToStack(token)
|
||||
if needsDecompilation:
|
||||
charString.setProgram(program)
|
||||
if program[-1] not in ("endchar", "return", "callsubr", "callgsubr", "seac"):
|
||||
print "XXX", program
|
||||
assert program[-1] in ("endchar", "return", "callsubr", "callgsubr", "seac")
|
||||
del self.callingStack[-1]
|
||||
|
||||
|
@ -42,7 +42,7 @@ Dumping 'prep' table...
|
||||
"""
|
||||
|
||||
#
|
||||
# $Id: __init__.py,v 1.30 2002-05-23 09:42:45 jvr Exp $
|
||||
# $Id: __init__.py,v 1.31 2002-05-24 09:58:04 jvr Exp $
|
||||
#
|
||||
|
||||
import os
|
||||
@ -534,8 +534,8 @@ class GlyphOrder:
|
||||
|
||||
def toXML(self, writer, ttFont):
|
||||
glyphOrder = ttFont.getGlyphOrder()
|
||||
writer.comment("The 'id' attribute is merely a reading aid; "
|
||||
"it is ignored when read.")
|
||||
writer.comment("The 'id' attribute is only for humans; "
|
||||
"it is ignored when parsed.")
|
||||
writer.newline()
|
||||
for i in range(len(glyphOrder)):
|
||||
glyphName = glyphOrder[i]
|
||||
|
@ -2,12 +2,6 @@ import DefaultTable
|
||||
from fontTools import cffLib
|
||||
|
||||
|
||||
# temporary switch:
|
||||
# - if true use possibly incomplete compile/decompile/toXML/fromXML implementation
|
||||
# - if false use DefaultTable, ie. dump as hex.
|
||||
TESTING_CFF = 0
|
||||
|
||||
|
||||
class table_C_F_F_(DefaultTable.DefaultTable):
|
||||
|
||||
def __init__(self, tag):
|
||||
@ -17,12 +11,14 @@ class table_C_F_F_(DefaultTable.DefaultTable):
|
||||
|
||||
def decompile(self, data, otFont):
|
||||
from cStringIO import StringIO
|
||||
self.data = data # XXX while work is in progress...
|
||||
self.cff.decompile(StringIO(data))
|
||||
self.cff.decompile(StringIO(data), otFont)
|
||||
assert len(self.cff) == 1, "can't deal with multi-font CFF tables."
|
||||
|
||||
#def compile(self, otFont):
|
||||
# xxx
|
||||
def compile(self, otFont):
|
||||
from cStringIO import StringIO
|
||||
f = StringIO()
|
||||
self.cff.compile(f, otFont)
|
||||
return f.getvalue()
|
||||
|
||||
def haveGlyphNames(self):
|
||||
if hasattr(self.cff[self.cff.fontNames[0]], "ROS"):
|
||||
@ -43,12 +39,10 @@ class table_C_F_F_(DefaultTable.DefaultTable):
|
||||
#self.cff[self.cff.fontNames[0]].setGlyphOrder(glyphOrder)
|
||||
|
||||
def toXML(self, writer, otFont, progress=None):
|
||||
if TESTING_CFF:
|
||||
self.cff.toXML(writer, progress)
|
||||
else:
|
||||
# dump as hex as long as we can't compile
|
||||
DefaultTable.DefaultTable.toXML(self, writer, otFont)
|
||||
self.cff.toXML(writer, progress)
|
||||
|
||||
#def fromXML(self, (name, attrs, content), otFont):
|
||||
# xxx
|
||||
def fromXML(self, (name, attrs, content), otFont):
|
||||
if not hasattr(self, "cff"):
|
||||
self.cff = cffLib.CFFFontSet()
|
||||
self.cff.fromXML((name, attrs, content))
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user