def makeMissingRequiredGlyphs(self): """ Add space and .notdef to the font if they are not present. **This should not be called externally.** Subclasses may override this method to handle the glyph creation in a different way if desired. """ glyphs = {} font = self.ufo unitsPerEm = _roundInt(getAttrWithFallback(font.info, "unitsPerEm")) ascender = _roundInt(getAttrWithFallback(font.info, "ascender")) descender = _roundInt(getAttrWithFallback(font.info, "descender")) defaultWidth = _roundInt(unitsPerEm * 0.5) if ".notdef" not in self.ufo: glyphs[".notdef"] = StubGlyph(name=".notdef", width=defaultWidth, unitsPerEm=unitsPerEm, ascender=ascender, descender=descender) if "space" not in self.ufo: glyphs["space"] = StubGlyph(name="space", width=defaultWidth, unitsPerEm=unitsPerEm, ascender=ascender, descender=descender, unicodes=[32]) return glyphs
def setupTable_post(self): """ Make the post table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["post"] = post = newTable("post") font = self.ufo post.formatType = 3.0 # italic angle italicAngle = getAttrWithFallback(font.info, "italicAngle") post.italicAngle = italicAngle # underline underlinePosition = getAttrWithFallback(font.info, "postscriptUnderlinePosition") if underlinePosition is None: underlinePosition = 0 post.underlinePosition = _roundInt(underlinePosition) underlineThickness = getAttrWithFallback(font.info, "postscriptUnderlineThickness") if underlineThickness is None: underlineThickness = 0 post.underlineThickness = _roundInt(underlineThickness) # determine if the font has a fixed width widths = set([glyph.width for glyph in self.allGlyphs.values()]) post.isFixedPitch = getAttrWithFallback(font.info, "postscriptIsFixedPitch") # misc post.minMemType42 = 0 post.maxMemType42 = 0 post.minMemType1 = 0 post.maxMemType1 = 0
def writeFeatures_hhea(self): """ Write the hhea to a string and return it. This gets the values for the file using the fallback system as described below: =========== === Ascender openTypeHheaAscender Descender openTypeHheaDescender LineGap openTypeHheaLineGap CaretOffset openTypeHheaCaretOffset =========== === **This should not be called externally.** Subclasses may override this method to handle the string creation in a different way if desired. """ ascender = getAttrWithFallback(self.font.info, "openTypeHheaAscender") descender = getAttrWithFallback(self.font.info, "openTypeHheaDescender") lineGap = getAttrWithFallback(self.font.info, "openTypeHheaLineGap") caret = getAttrWithFallback(self.font.info, "openTypeHheaCaretOffset") writer = FeatureTableWriter("hhea") writer.addLineWithKeyValue("Ascender", _roundInt(ascender)) writer.addLineWithKeyValue("Descender", _roundInt(descender)) writer.addLineWithKeyValue("LineGap", _roundInt(lineGap)) writer.addLineWithKeyValue("CaretOffset", _roundInt(caret)) return writer.write()
def setupTable_post(self): """ Make the post table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["post"] = post = newTable("post") font = self.ufo post.formatType = 3.0 # italic angle italicAngle = getAttrWithFallback(font.info, "italicAngle") post.italicAngle = italicAngle # underline underlinePosition = getAttrWithFallback(font.info, "postscriptUnderlinePosition") if underlinePosition is None: underlinePosition = 0 post.underlinePosition = _roundInt(underlinePosition) underlineThickness = getAttrWithFallback( font.info, "postscriptUnderlineThickness") if underlineThickness is None: underlineThickness = 0 post.underlineThickness = _roundInt(underlineThickness) # determine if the font has a fixed width post.isFixedPitch = getAttrWithFallback(font.info, "postscriptIsFixedPitch") # misc post.minMemType42 = 0 post.maxMemType42 = 0 post.minMemType1 = 0 post.maxMemType1 = 0
def setupFile_menuName(self, path): """ Make the menu name source file. This gets the values for the file using the fallback system as described below: ==== === [PS] postscriptFontName f= openTypeNamePreferredFamilyName s= openTypeNamePreferredSubfamilyName l= styleMapFamilyName m=1, openTypeNameCompatibleFullName ==== === **This should not be called externally.** Subclasses may override this method to handle the file creation in a different way if desired. """ psName = getAttrWithFallback(self.font.info, "postscriptFontName") lines = ["[%s]" % psName] # family name familyName = getAttrWithFallback(self.font.info, "openTypeNamePreferredFamilyName") encodedFamilyName = winStr(familyName) lines.append("f=%s" % encodedFamilyName) if encodedFamilyName != familyName: lines.append("f=1,%s" % macStr(familyName)) # style name styleName = getAttrWithFallback(self.font.info, "openTypeNamePreferredSubfamilyName") encodedStyleName = winStr(styleName) lines.append("s=%s" % encodedStyleName) if encodedStyleName != styleName: lines.append("s=1,%s" % macStr(styleName)) # compatible name winCompatible = getAttrWithFallback(self.font.info, "styleMapFamilyName") ## the second qualification here is in place for Mac Office <= 2004. ## in that app the menu name is pulled from name ID 18. the font ## may have standard naming data that combines to a length longer ## than the app can handle (see Adobe Tech Note #5088). the designer ## may have created a specific openTypeNameCompatibleFullName to ## get around this problem. sigh, old app bugs live long lives. if winCompatible != familyName or self.font.info.openTypeNameCompatibleFullName is not None: # windows l = "l=%s" % normalizeStringForPostscript(winCompatible) lines.append(l) # mac macCompatible = getAttrWithFallback( self.font.info, "openTypeNameCompatibleFullName") l = "m=1,%s" % macStr(macCompatible) lines.append(l) text = "\n".join(lines) + "\n" f = open(path, "wb") f.write(text) f.close()
def setupFile_menuName(self, path): """ Make the menu name source file. This gets the values for the file using the fallback system as described below: ==== === [PS] postscriptFontName f= openTypeNamePreferredFamilyName s= openTypeNamePreferredSubfamilyName l= styleMapFamilyName m=1, openTypeNameCompatibleFullName ==== === **This should not be called externally.** Subclasses may override this method to handle the file creation in a different way if desired. """ psName = getAttrWithFallback(self.font.info,"postscriptFontName") lines = [ "[%s]" % psName ] # family name familyName = getAttrWithFallback(self.font.info,"openTypeNamePreferredFamilyName") encodedFamilyName = winStr(familyName) lines.append("f=%s" % encodedFamilyName) if encodedFamilyName != familyName: lines.append("f=1,%s" % macStr(familyName)) # style name styleName = getAttrWithFallback(self.font.info,"openTypeNamePreferredSubfamilyName") encodedStyleName = winStr(styleName) lines.append("s=%s" % encodedStyleName) if encodedStyleName != styleName: lines.append("s=1,%s" % macStr(styleName)) # compatible name winCompatible = getAttrWithFallback(self.font.info,"styleMapFamilyName") ## the second qualification here is in place for Mac Office <= 2004. ## in that app the menu name is pulled from name ID 18. the font ## may have standard naming data that combines to a length longer ## than the app can handle (see Adobe Tech Note #5088). the designer ## may have created a specific openTypeNameCompatibleFullName to ## get around this problem. sigh, old app bugs live long lives. if winCompatible != familyName or self.font.info.openTypeNameCompatibleFullName is not None: # windows l = "l=%s" % normalizeStringForPostscript(winCompatible) lines.append(l) # mac macCompatible = getAttrWithFallback(self.font.info,"openTypeNameCompatibleFullName") l = "m=1,%s" % macStr(macCompatible) lines.append(l) text = "\n".join(lines) + "\n" f = open(path, "wb") f.write(text) f.close()
def setupFile_fontInfo(self, path): """ Make the font info source file. This gets the values for the file using the fallback system as described below: ========================== === IsItalicStyle styleMapStyleName IsBoldStyle styleMapStyleName PreferOS/2TypoMetrics openTypeOS2Selection IsOS/2WidthWeigthSlopeOnly openTypeOS2Selection IsOS/2OBLIQUE openTypeOS2Selection ========================== === **This should not be called externally.** Subclasses may override this method to handle the file creation in a different way if desired. """ lines = [] # style mapping styleMapStyleName = getAttrWithFallback(self.font.info, "styleMapStyleName") if styleMapStyleName in ("italic", "bold italic"): lines.append("IsItalicStyle true") else: lines.append("IsItalicStyle false") if styleMapStyleName in ("bold", "bold italic"): lines.append("IsBoldStyle true") else: lines.append("IsBoldStyle false") # fsSelection bits selection = getAttrWithFallback(self.font.info, "openTypeOS2Selection") if 7 in selection: lines.append("PreferOS/2TypoMetrics true") else: lines.append("PreferOS/2TypoMetrics false") if 8 in selection: lines.append("IsOS/2WidthWeigthSlopeOnly true") else: lines.append("IsOS/2WidthWeigthSlopeOnly false") if 9 in selection: lines.append("IsOS/2OBLIQUE true") else: lines.append("IsOS/2OBLIQUE false") # write the file if lines: f = open(path, "wb") f.write("\n".join(lines)) f.close()
def setupFile_fontInfo(self, path): """ Make the font info source file. This gets the values for the file using the fallback system as described below: ========================== === IsItalicStyle styleMapStyleName IsBoldStyle styleMapStyleName PreferOS/2TypoMetrics openTypeOS2Selection IsOS/2WidthWeigthSlopeOnly openTypeOS2Selection IsOS/2OBLIQUE openTypeOS2Selection ========================== === **This should not be called externally.** Subclasses may override this method to handle the file creation in a different way if desired. """ lines = [] # style mapping styleMapStyleName = getAttrWithFallback(self.font.info,"styleMapStyleName") if styleMapStyleName in ("italic", "bold italic"): lines.append("IsItalicStyle true") else: lines.append("IsItalicStyle false") if styleMapStyleName in ("bold", "bold italic"): lines.append("IsBoldStyle true") else: lines.append("IsBoldStyle false") # fsSelection bits selection = getAttrWithFallback(self.font.info,"openTypeOS2Selection") if 7 in selection: lines.append("PreferOS/2TypoMetrics true") else: lines.append("PreferOS/2TypoMetrics false") if 8 in selection: lines.append("IsOS/2WidthWeigthSlopeOnly true") else: lines.append("IsOS/2WidthWeigthSlopeOnly false") if 9 in selection: lines.append("IsOS/2OBLIQUE true") else: lines.append("IsOS/2OBLIQUE false") # write the file if lines: f = open(path, "wb") f.write("\n".join(lines)) f.close()
def writeFeatures_head(self): """ Write the head to a string and return it. This gets the values for the file using the fallback system as described below: ===== === X.XXX versionMajor.versionMinor ===== === **This should not be called externally.** Subclasses may override this method to handle the string creation in a different way if desired. """ versionMajor = getAttrWithFallback(self.font.info, "versionMajor") versionMinor = getAttrWithFallback(self.font.info, "versionMinor") value = "%d.%s" % (versionMajor, str(versionMinor).zfill(3)) writer = FeatureTableWriter("head") writer.addLineWithKeyValue("FontRevision", value) return writer.write()
def writeFeatures_name(self): """ Write the name to a string and return it. This gets the values for the file using the fallback system as described below: ========= === nameid 0 copyright nameid 7 trademark nameid 8 openTypeNameManufacturer nameid 9 openTypeNameDesigner nameid 10 openTypeNameDescription nameid 11 openTypeNameManufacturerURL nameid 12 openTypeNameDesignerURL nameid 13 openTypeNameLicense nameid 14 openTypeNameLicenseURL nameid 19 openTypeNameSampleText ========= === **This should not be called externally.** Subclasses may override this method to handle the string creation in a different way if desired. """ idToAttr = [ (0 , "copyright"), (7 , "trademark"), (8 , "openTypeNameManufacturer"), (9 , "openTypeNameDesigner"), (10 , "openTypeNameDescription"), (11 , "openTypeNameManufacturerURL"), (12 , "openTypeNameDesignerURL"), (13 , "openTypeNameLicense"), (14 , "openTypeNameLicenseURL"), (19 , "openTypeNameSampleText") ] multilineNameTableEntries = {} lines = [] for id, attr in idToAttr: value = getAttrWithFallback(self.font.info, attr) if value is None: continue s = 'nameid %d "%s";' % (id, winStr(value)) lines.append(s) s = 'nameid %d 1 "%s";' % (id, macStr(value)) lines.append(s) if not lines: return "" writer = FeatureTableWriter("name") for line in lines: writer.addLine(line) return writer.write()
def setupTable_hhea(self): """ Make the hhea table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["hhea"] = hhea = newTable("hhea") font = self.ufo hhea.tableVersion = 1.0 # vertical metrics hhea.ascent = _roundInt(getAttrWithFallback(font.info, "openTypeHheaAscender")) hhea.descent = _roundInt(getAttrWithFallback(font.info, "openTypeHheaDescender")) hhea.lineGap = _roundInt(getAttrWithFallback(font.info, "openTypeHheaLineGap")) # horizontal metrics widths = [] lefts = [] rights = [] extents = [] for glyph in self.allGlyphs.values(): left = glyph.leftMargin right = glyph.rightMargin if left is None: left = 0 if right is None: right = 0 widths.append(glyph.width) lefts.append(left) rights.append(right) # robofab if hasattr(glyph, "box"): bounds = glyph.box # others else: bounds = glyph.bounds if bounds is not None: xMin, yMin, xMax, yMax = bounds else: xMin = 0 xMax = 0 extent = left + (xMax - xMin) # equation from spec for calculating xMaxExtent: Max(lsb + (xMax - xMin)) extents.append(extent) hhea.advanceWidthMax = _roundInt(max(widths)) hhea.minLeftSideBearing = _roundInt(min(lefts)) hhea.minRightSideBearing = _roundInt(min(rights)) hhea.xMaxExtent = _roundInt(max(extents)) # misc hhea.caretSlopeRise = getAttrWithFallback(font.info, "openTypeHheaCaretSlopeRise") hhea.caretSlopeRun = getAttrWithFallback(font.info, "openTypeHheaCaretSlopeRun") hhea.caretOffset = _roundInt(getAttrWithFallback(font.info, "openTypeHheaCaretOffset")) hhea.reserved0 = 0 hhea.reserved1 = 0 hhea.reserved2 = 0 hhea.reserved3 = 0 hhea.metricDataFormat = 0 # glyph count hhea.numberOfHMetrics = len(self.allGlyphs)
def setupTable_head(self): """ Make the head table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["head"] = head = newTable("head") font = self.ufo head.checkSumAdjustment = 0 head.tableVersion = 1.0 versionMajor = getAttrWithFallback(font.info, "versionMajor") versionMinor = getAttrWithFallback(font.info, "versionMinor") * .001 head.fontRevision = versionMajor + versionMinor head.magicNumber = 0x5F0F3CF5 # upm head.unitsPerEm = getAttrWithFallback(font.info, "unitsPerEm") # times head.created = dateStringToTimeValue( getAttrWithFallback(font.info, "openTypeHeadCreated")) - mac_epoch_diff head.modified = dateStringToTimeValue( dateStringForNow()) - mac_epoch_diff # bounding box xMin, yMin, xMax, yMax = self.fontBoundingBox head.xMin = xMin head.yMin = yMin head.xMax = xMax head.yMax = yMax # style mapping styleMapStyleName = getAttrWithFallback(font.info, "styleMapStyleName") macStyle = [] if styleMapStyleName == "bold": macStyle = [0] elif styleMapStyleName == "bold italic": macStyle = [0, 1] elif styleMapStyleName == "italic": macStyle = [1] head.macStyle = intListToNum(macStyle, 0, 16) # misc head.flags = intListToNum( getAttrWithFallback(font.info, "openTypeHeadFlags"), 0, 16) head.lowestRecPPEM = _roundInt( getAttrWithFallback(font.info, "openTypeHeadLowestRecPPEM")) head.fontDirectionHint = 2 head.indexToLocFormat = 0 head.glyphDataFormat = 0
def getCharStringForGlyph(self, glyph, private, globalSubrs): """ Get a Type2CharString for the *glyph* **This should not be called externally.** Subclasses may override this method to handle the charstring creation in a different way if desired. """ width = glyph.width # subtract the nominal width postscriptNominalWidthX = getAttrWithFallback(self.ufo.info, "postscriptNominalWidthX") if postscriptNominalWidthX: width = width - postscriptNominalWidthX # round width = _roundInt(width) pen = T2CharStringPen(width, self.allGlyphs) glyph.draw(pen) charString = pen.getCharString(private, globalSubrs) return charString
def getCharStringForGlyph(self, glyph, private, globalSubrs): """ Get a Type2CharString for the *glyph* **This should not be called externally.** Subclasses may override this method to handle the charstring creation in a different way if desired. """ width = glyph.width # subtract the nominal width postscriptNominalWidthX = getAttrWithFallback( self.ufo.info, "postscriptNominalWidthX") if postscriptNominalWidthX: width = width - postscriptNominalWidthX # round width = _roundInt(width) pen = T2CharStringPen(width, self.allGlyphs) glyph.draw(pen) charString = pen.getCharString(private, globalSubrs) return charString
def setupTable_head(self): """ Make the head table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["head"] = head = newTable("head") font = self.ufo head.checkSumAdjustment = 0 head.tableVersion = 1.0 versionMajor = getAttrWithFallback(font.info, "versionMajor") versionMinor = getAttrWithFallback(font.info, "versionMinor") * .001 head.fontRevision = versionMajor + versionMinor head.magicNumber = 0x5F0F3CF5 # upm head.unitsPerEm = getAttrWithFallback(font.info, "unitsPerEm") # times head.created = dateStringToTimeValue(getAttrWithFallback(font.info, "openTypeHeadCreated")) - mac_epoch_diff head.modified = dateStringToTimeValue(dateStringForNow()) - mac_epoch_diff # bounding box xMin, yMin, xMax, yMax = self.fontBoundingBox head.xMin = xMin head.yMin = yMin head.xMax = xMax head.yMax = yMax # style mapping styleMapStyleName = getAttrWithFallback(font.info, "styleMapStyleName") macStyle = [] if styleMapStyleName == "bold": macStyle = [0] elif styleMapStyleName == "bold italic": macStyle = [0, 1] elif styleMapStyleName == "italic": macStyle = [1] head.macStyle = intListToNum(macStyle, 0, 16) # misc head.flags = intListToNum(getAttrWithFallback(font.info, "openTypeHeadFlags"), 0, 16) head.lowestRecPPEM = _roundInt(getAttrWithFallback(font.info, "openTypeHeadLowestRecPPEM")) head.fontDirectionHint = 2 head.indexToLocFormat = 0 head.glyphDataFormat = 0
def setupTable_CFF(self): """ Make the CFF table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["CFF "] = cff = newTable("CFF ") cff = cff.cff # set up the basics cff.major = 1 cff.minor = 0 cff.hdrSize = 4 cff.offSize = 4 cff.fontNames = [] strings = IndexedStrings() cff.strings = strings private = PrivateDict(strings=strings) private.rawDict.update(private.defaults) globalSubrs = GlobalSubrsIndex(private=private) topDict = TopDict(GlobalSubrs=globalSubrs, strings=strings) topDict.Private = private charStrings = topDict.CharStrings = CharStrings( file=None, charset=None, globalSubrs=globalSubrs, private=private, fdSelect=None, fdArray=None) charStrings.charStringsAreIndexed = True topDict.charset = [] charStringsIndex = charStrings.charStringsIndex = SubrsIndex( private=private, globalSubrs=globalSubrs) cff.topDictIndex = topDictIndex = TopDictIndex() topDictIndex.append(topDict) topDictIndex.strings = strings cff.GlobalSubrs = globalSubrs # populate naming data info = self.ufo.info psName = getAttrWithFallback(info, "postscriptFontName") cff.fontNames.append(psName) topDict = cff.topDictIndex[0] topDict.version = "%d.%d" % (getAttrWithFallback( info, "versionMajor"), getAttrWithFallback(info, "versionMinor")) trademark = getAttrWithFallback(info, "trademark") if trademark: trademark = normalizeStringForPostscript( trademark.replace(u"\u00A9", "Copyright")) if trademark != self.ufo.info.trademark: self.log.append( "[Warning] The trademark was normalized for storage in the CFF table and consequently some characters were dropped: '%s'" % trademark) if trademark is None: trademark = "" topDict.Notice = trademark copyright = getAttrWithFallback(info, "copyright") if copyright: copyright = normalizeStringForPostscript( copyright.replace(u"\u00A9", "Copyright")) if copyright != self.ufo.info.copyright: self.log.append( "[Warning] The copyright was normalized for storage in the CFF table and consequently some characters were dropped: '%s'" % copyright) if copyright is None: copyright = "" topDict.Copyright = copyright topDict.FullName = getAttrWithFallback(info, "postscriptFullName") topDict.FamilyName = getAttrWithFallback( info, "openTypeNamePreferredFamilyName") topDict.Weight = getAttrWithFallback(info, "postscriptWeightName") topDict.FontName = getAttrWithFallback(info, "postscriptFontName") # populate various numbers topDict.isFixedPitch = getAttrWithFallback(info, "postscriptIsFixedPitch") topDict.ItalicAngle = getAttrWithFallback(info, "italicAngle") underlinePosition = getAttrWithFallback(info, "postscriptUnderlinePosition") if underlinePosition is None: underlinePosition = 0 topDict.UnderlinePosition = _roundInt(underlinePosition) underlineThickness = getAttrWithFallback( info, "postscriptUnderlineThickness") if underlineThickness is None: underlineThickness = 0 topDict.UnderlineThickness = _roundInt(underlineThickness) # populate font matrix unitsPerEm = _roundInt(getAttrWithFallback(info, "unitsPerEm")) topDict.FontMatrix = [1.0 / unitsPerEm, 0, 0, 1.0 / unitsPerEm, 0, 0] # populate the width values defaultWidthX = _roundInt( getAttrWithFallback(info, "postscriptDefaultWidthX")) if defaultWidthX: private.rawDict["defaultWidthX"] = defaultWidthX nominalWidthX = _roundInt( getAttrWithFallback(info, "postscriptNominalWidthX")) if nominalWidthX: private.rawDict["nominalWidthX"] = nominalWidthX # populate hint data blueFuzz = _roundInt(getAttrWithFallback(info, "postscriptBlueFuzz")) blueShift = _roundInt(getAttrWithFallback(info, "postscriptBlueShift")) blueScale = getAttrWithFallback(info, "postscriptBlueScale") forceBold = getAttrWithFallback(info, "postscriptForceBold") blueValues = getAttrWithFallback(info, "postscriptBlueValues") if isinstance(blueValues, list): blueValues = [_roundInt(i) for i in blueValues] otherBlues = getAttrWithFallback(info, "postscriptOtherBlues") if isinstance(otherBlues, list): otherBlues = [_roundInt(i) for i in otherBlues] familyBlues = getAttrWithFallback(info, "postscriptFamilyBlues") if isinstance(familyBlues, list): familyBlues = [_roundInt(i) for i in familyBlues] familyOtherBlues = getAttrWithFallback(info, "postscriptFamilyOtherBlues") if isinstance(familyOtherBlues, list): familyOtherBlues = [_roundInt(i) for i in familyOtherBlues] stemSnapH = getAttrWithFallback(info, "postscriptStemSnapH") if isinstance(stemSnapH, list): stemSnapH = [_roundInt(i) for i in stemSnapH] stemSnapV = getAttrWithFallback(info, "postscriptStemSnapV") if isinstance(stemSnapV, list): stemSnapV = [_roundInt(i) for i in stemSnapV] # only write the blues data if some blues are defined. if (blueValues or otherBlues): private.rawDict["BlueFuzz"] = blueFuzz private.rawDict["BlueShift"] = blueShift private.rawDict["BlueScale"] = blueScale private.rawDict["ForceBold"] = forceBold private.rawDict["BlueValues"] = blueValues private.rawDict["OtherBlues"] = otherBlues private.rawDict["FamilyBlues"] = familyBlues private.rawDict["FamilyOtherBlues"] = familyOtherBlues # only write the stems if both are defined. if (stemSnapH and stemSnapV): private.rawDict["StemSnapH"] = stemSnapH private.rawDict["StdHW"] = stemSnapH[0] private.rawDict["StemSnapV"] = stemSnapV private.rawDict["StdVW"] = stemSnapV[0] # populate glyphs for glyphName in self.glyphOrder: glyph = self.allGlyphs[glyphName] unicodes = glyph.unicodes charString = self.getCharStringForGlyph(glyph, private, globalSubrs) # add to the font exists = charStrings.has_key(glyphName) if exists: # XXX a glyph already has this name. should we choke? glyphID = charStrings.charStrings[glyphName] charStringsIndex.items[glyphID] = charString else: charStringsIndex.append(charString) glyphID = len(topDict.charset) charStrings.charStrings[glyphName] = glyphID topDict.charset.append(glyphName) topDict.FontBBox = self.fontBoundingBox # write the glyph order self.otf.setGlyphOrder(self.glyphOrder)
def writeFeatures_OS2(self): """ Write the OS/2 to a string and return it. This gets the values for the file using the fallback system as described below: ============= === FSType openTypeOS2Type Panose openTypeOS2Panose UnicodeRange openTypeOS2UnicodeRanges CodePageRange openTypeOS2CodePageRanges TypoAscender openTypeOS2TypoAscender TypoDescender openTypeOS2TypoDescender TypoLineGap openTypeOS2TypoLineGap winAscent openTypeOS2WinAscent winDescent openTypeOS2WinDescent XHeight xHeight CapHeight capHeight WeightClass openTypeOS2WeightClass WidthClass openTypeOS2WidthClass Vendor openTypeOS2VendorID ============= === **This should not be called externally.** Subclasses may override this method to handle the string creation in a different way if desired. """ codePageBitTranslation = { 0 : "1252", 1 : "1250", 2 : "1251", 3 : "1253", 4 : "1254", 5 : "1255", 6 : "1256", 7 : "1257", 8 : "1258", 16 : "874", 17 : "932", 18 : "936", 19 : "949", 20 : "950", 21 : "1361", 48 : "869", 49 : "866", 50 : "865", 51 : "864", 52 : "863", 53 : "862", 54 : "861", 55 : "860", 56 : "857", 57 : "855", 58 : "852", 59 : "775", 60 : "737", 61 : "708", 62 : "850", 63 : "437" } # writer writer = FeatureTableWriter("OS/2") # type writer.addLineWithKeyValue("FSType", intListToNum(getAttrWithFallback(self.font.info, "openTypeOS2Type"), 0, 16)) # panose panose = [str(i) for i in getAttrWithFallback(self.font.info, "openTypeOS2Panose")] writer.addLineWithKeyValue("Panose", " ".join(panose)) # unicode ranges unicodeRange = [str(i) for i in getAttrWithFallback(self.font.info, "openTypeOS2UnicodeRanges")] if unicodeRange: writer.addLineWithKeyValue("UnicodeRange", " ".join(unicodeRange)) # code page ranges codePageRange = [codePageBitTranslation[i] for i in getAttrWithFallback(self.font.info, "openTypeOS2CodePageRanges") if i in codePageBitTranslation] if codePageRange: writer.addLineWithKeyValue("CodePageRange", " ".join(codePageRange)) # vertical metrics writer.addLineWithKeyValue("TypoAscender", _roundInt(getAttrWithFallback(self.font.info, "openTypeOS2TypoAscender"))) writer.addLineWithKeyValue("TypoDescender", _roundInt(getAttrWithFallback(self.font.info, "openTypeOS2TypoDescender"))) writer.addLineWithKeyValue("TypoLineGap", _roundInt(getAttrWithFallback(self.font.info, "openTypeOS2TypoLineGap"))) writer.addLineWithKeyValue("winAscent", _roundInt(getAttrWithFallback(self.font.info, "openTypeOS2WinAscent"))) writer.addLineWithKeyValue("winDescent", abs(_roundInt(getAttrWithFallback(self.font.info, "openTypeOS2WinDescent")))) writer.addLineWithKeyValue("XHeight", _roundInt(getAttrWithFallback(self.font.info, "xHeight"))) writer.addLineWithKeyValue("CapHeight", _roundInt(getAttrWithFallback(self.font.info, "capHeight"))) writer.addLineWithKeyValue("WeightClass", getAttrWithFallback(self.font.info, "openTypeOS2WeightClass")) writer.addLineWithKeyValue("WidthClass", getAttrWithFallback(self.font.info, "openTypeOS2WidthClass")) writer.addLineWithKeyValue("Vendor", '"%s"' % getAttrWithFallback(self.font.info, "openTypeOS2VendorID")) return writer.write()
def setupTable_OS2(self): """ Make the OS/2 table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["OS/2"] = os2 = newTable("OS/2") font = self.ufo os2.version = 0x0004 # average glyph width widths = [glyph.width for glyph in self.allGlyphs.values() if glyph.width > 0] os2.xAvgCharWidth = _roundInt(sum(widths) / len(widths)) # weight and width classes os2.usWeightClass = getAttrWithFallback(font.info, "openTypeOS2WeightClass") os2.usWidthClass = getAttrWithFallback(font.info, "openTypeOS2WidthClass") # embedding os2.fsType = intListToNum(getAttrWithFallback(font.info, "openTypeOS2Type"), 0, 16) # subscript v = getAttrWithFallback(font.info, "openTypeOS2SubscriptXSize") if v is None: v = 0 os2.ySubscriptXSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptYSize") if v is None: v = 0 os2.ySubscriptYSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptXOffset") if v is None: v = 0 os2.ySubscriptXOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptYOffset") if v is None: v = 0 os2.ySubscriptYOffset = _roundInt(v) # superscript v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptXSize") if v is None: v = 0 os2.ySuperscriptXSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptYSize") if v is None: v = 0 os2.ySuperscriptYSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptXOffset") if v is None: v = 0 os2.ySuperscriptXOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptYOffset") if v is None: v = 0 os2.ySuperscriptYOffset = _roundInt(v) # strikeout v = getAttrWithFallback(font.info, "openTypeOS2StrikeoutSize") if v is None: v = 0 os2.yStrikeoutSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2StrikeoutPosition") if v is None: v = 0 os2.yStrikeoutPosition = _roundInt(v) # family class os2.sFamilyClass = 0 # XXX not sure how to create the appropriate value # panose data = getAttrWithFallback(font.info, "openTypeOS2Panose") panose = Panose() panose.bFamilyType = data[0] panose.bSerifStyle = data[1] panose.bWeight = data[2] panose.bProportion = data[3] panose.bContrast = data[4] panose.bStrokeVariation = data[5] panose.bArmStyle = data[6] panose.bLetterForm = data[7] panose.bMidline = data[8] panose.bXHeight = data[9] os2.panose = panose # Unicode ranges uniRanges = getAttrWithFallback(font.info, "openTypeOS2UnicodeRanges") os2.ulUnicodeRange1 = intListToNum(uniRanges, 0, 32) os2.ulUnicodeRange2 = intListToNum(uniRanges, 32, 32) os2.ulUnicodeRange3 = intListToNum(uniRanges, 64, 32) os2.ulUnicodeRange4 = intListToNum(uniRanges, 96, 32) # codepage ranges codepageRanges = getAttrWithFallback(font.info, "openTypeOS2CodePageRanges") os2.ulCodePageRange1 = intListToNum(codepageRanges, 0, 32) os2.ulCodePageRange2 = intListToNum(codepageRanges, 32, 32) # vendor id os2.achVendID = str(getAttrWithFallback(font.info, "openTypeOS2VendorID").decode("ascii", "ignore")) # vertical metrics os2.sxHeight = _roundInt(getAttrWithFallback(font.info, "xHeight")) os2.sCapHeight = _roundInt(getAttrWithFallback(font.info, "capHeight")) os2.sTypoAscender = _roundInt(getAttrWithFallback(font.info, "openTypeOS2TypoAscender")) os2.sTypoDescender = _roundInt(getAttrWithFallback(font.info, "openTypeOS2TypoDescender")) os2.sTypoLineGap = _roundInt(getAttrWithFallback(font.info, "openTypeOS2TypoLineGap")) os2.usWinAscent = _roundInt(getAttrWithFallback(font.info, "openTypeOS2WinAscent")) os2.usWinDescent = _roundInt(getAttrWithFallback(font.info, "openTypeOS2WinDescent")) # style mapping selection = list(getAttrWithFallback(font.info, "openTypeOS2Selection")) styleMapStyleName = getAttrWithFallback(font.info, "styleMapStyleName") if styleMapStyleName == "regular": selection.append(6) elif styleMapStyleName == "bold": selection.append(5) elif styleMapStyleName == "italic": selection.append(0) elif styleMapStyleName == "bold italic": selection += [0, 5] os2.fsSelection = intListToNum(selection, 0, 16) # characetr indexes unicodes = [i for i in self.unicodeToGlyphNameMapping.keys() if i is not None] if unicodes: minIndex = min(unicodes) maxIndex = max(unicodes) else: # the font may have *no* unicode values # (it really happens!) so there needs # to be a fallback. use space for this. minIndex = 0x0020 maxIndex = 0x0020 if maxIndex > 0xFFFF: # the spec says that 0xFFFF should be used # as the max if the max exceeds 0xFFFF maxIndex = 0xFFFF os2.fsFirstCharIndex = minIndex os2.fsLastCharIndex = maxIndex os2.usBreakChar = 32 os2.usDefaultChar = 0 # maximum contextual lookup length os2.usMaxContex = 0
def writeFeatures_OS2(self): """ Write the OS/2 to a string and return it. This gets the values for the file using the fallback system as described below: ============= === FSType openTypeOS2Type Panose openTypeOS2Panose UnicodeRange openTypeOS2UnicodeRanges CodePageRange openTypeOS2CodePageRanges TypoAscender openTypeOS2TypoAscender TypoDescender openTypeOS2TypoDescender TypoLineGap openTypeOS2TypoLineGap winAscent openTypeOS2WinAscent winDescent openTypeOS2WinDescent XHeight xHeight CapHeight capHeight WeightClass openTypeOS2WeightClass WidthClass openTypeOS2WidthClass Vendor openTypeOS2VendorID ============= === **This should not be called externally.** Subclasses may override this method to handle the string creation in a different way if desired. """ codePageBitTranslation = { 0: "1252", 1: "1250", 2: "1251", 3: "1253", 4: "1254", 5: "1255", 6: "1256", 7: "1257", 8: "1258", 16: "874", 17: "932", 18: "936", 19: "949", 20: "950", 21: "1361", 48: "869", 49: "866", 50: "865", 51: "864", 52: "863", 53: "862", 54: "861", 55: "860", 56: "857", 57: "855", 58: "852", 59: "775", 60: "737", 61: "708", 62: "850", 63: "437" } # writer writer = FeatureTableWriter("OS/2") # type writer.addLineWithKeyValue( "FSType", intListToNum( getAttrWithFallback(self.font.info, "openTypeOS2Type"), 0, 16)) # panose panose = [ str(i) for i in getAttrWithFallback(self.font.info, "openTypeOS2Panose") ] writer.addLineWithKeyValue("Panose", " ".join(panose)) # unicode ranges unicodeRange = [ str(i) for i in getAttrWithFallback(self.font.info, "openTypeOS2UnicodeRanges") ] if unicodeRange: writer.addLineWithKeyValue("UnicodeRange", " ".join(unicodeRange)) # code page ranges codePageRange = [ codePageBitTranslation[i] for i in getAttrWithFallback( self.font.info, "openTypeOS2CodePageRanges") if i in codePageBitTranslation ] if codePageRange: writer.addLineWithKeyValue("CodePageRange", " ".join(codePageRange)) # vertical metrics writer.addLineWithKeyValue( "TypoAscender", _roundInt( getAttrWithFallback(self.font.info, "openTypeOS2TypoAscender"))) writer.addLineWithKeyValue( "TypoDescender", _roundInt( getAttrWithFallback(self.font.info, "openTypeOS2TypoDescender"))) writer.addLineWithKeyValue( "TypoLineGap", _roundInt( getAttrWithFallback(self.font.info, "openTypeOS2TypoLineGap"))) writer.addLineWithKeyValue( "winAscent", _roundInt( getAttrWithFallback(self.font.info, "openTypeOS2WinAscent"))) writer.addLineWithKeyValue( "winDescent", abs( _roundInt( getAttrWithFallback(self.font.info, "openTypeOS2WinDescent")))) writer.addLineWithKeyValue( "XHeight", _roundInt(getAttrWithFallback(self.font.info, "xHeight"))) writer.addLineWithKeyValue( "CapHeight", _roundInt(getAttrWithFallback(self.font.info, "capHeight"))) writer.addLineWithKeyValue( "WeightClass", getAttrWithFallback(self.font.info, "openTypeOS2WeightClass")) writer.addLineWithKeyValue( "WidthClass", getAttrWithFallback(self.font.info, "openTypeOS2WidthClass")) writer.addLineWithKeyValue( "Vendor", '"%s"' % getAttrWithFallback(self.font.info, "openTypeOS2VendorID")) return writer.write()
def writeFeatures_name(self): """ Write the name to a string and return it. This gets the values for the file using the fallback system as described below: ========= === nameid 0 copyright nameid 7 trademark nameid 8 openTypeNameManufacturer nameid 9 openTypeNameDesigner nameid 10 openTypeNameDescription nameid 11 openTypeNameManufacturerURL nameid 12 openTypeNameDesignerURL nameid 13 openTypeNameLicense nameid 14 openTypeNameLicenseURL nameid 19 openTypeNameSampleText ========= === **This should not be called externally.** Subclasses may override this method to handle the string creation in a different way if desired. """ idToAttr = [(0, "copyright"), (7, "trademark"), (8, "openTypeNameManufacturer"), (9, "openTypeNameDesigner"), (10, "openTypeNameDescription"), (11, "openTypeNameManufacturerURL"), (12, "openTypeNameDesignerURL"), (13, "openTypeNameLicense"), (14, "openTypeNameLicenseURL"), (19, "openTypeNameSampleText")] multilineNameTableEntries = {} lines = [] for id, attr in idToAttr: value = getAttrWithFallback(self.font.info, attr) if value is None: continue s = 'nameid %d "%s";' % (id, winStr(value)) lines.append(s) s = 'nameid %d 1 "%s";' % (id, macStr(value)) lines.append(s) if self.font.info.openTypeNameRecords is not None: for record in self.font.info.openTypeNameRecords: nameID = record["nameID"] if nameID >= 1 and nameID <= 6: continue platformID = record["platformID"] encodingID = record["encodingID"] languageID = record["languageID"] string = record["string"] if platformID == 0: string = macStr(string) else: string = winStr(string) s = 'nameid %d %d %d %d "%s";' % ( nameID, platformID, encodingID, languageID, string) lines.append(s) if not lines: return "" writer = FeatureTableWriter("name") for line in lines: writer.addLine(line) return writer.write()
def setupTable_CFF(self): """ Make the CFF table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["CFF "] = cff = newTable("CFF ") cff = cff.cff # set up the basics cff.major = 1 cff.minor = 0 cff.hdrSize = 4 cff.offSize = 4 cff.fontNames = [] strings = IndexedStrings() cff.strings = strings private = PrivateDict(strings=strings) private.rawDict.update(private.defaults) globalSubrs = GlobalSubrsIndex(private=private) topDict = TopDict(GlobalSubrs=globalSubrs, strings=strings) topDict.Private = private charStrings = topDict.CharStrings = CharStrings(file=None, charset=None, globalSubrs=globalSubrs, private=private, fdSelect=None, fdArray=None) charStrings.charStringsAreIndexed = True topDict.charset = [] charStringsIndex = charStrings.charStringsIndex = SubrsIndex(private=private, globalSubrs=globalSubrs) cff.topDictIndex = topDictIndex = TopDictIndex() topDictIndex.append(topDict) topDictIndex.strings = strings cff.GlobalSubrs = globalSubrs # populate naming data info = self.ufo.info psName = getAttrWithFallback(info, "postscriptFontName") cff.fontNames.append(psName) topDict = cff.topDictIndex[0] topDict.version = "%d.%d" % (getAttrWithFallback(info, "versionMajor"), getAttrWithFallback(info, "versionMinor")) trademark = getAttrWithFallback(info, "trademark") if trademark: trademark = normalizeStringForPostscript(trademark.replace(u"\u00A9", "Copyright")) if trademark != self.ufo.info.trademark: self.log.append("[Warning] The trademark was normalized for storage in the CFF table and consequently some characters were dropped: '%s'" % trademark) if trademark is None: trademark = "" topDict.Notice = trademark copyright = getAttrWithFallback(info, "copyright") if copyright: copyright = normalizeStringForPostscript(copyright.replace(u"\u00A9", "Copyright")) if copyright != self.ufo.info.copyright: self.log.append("[Warning] The copyright was normalized for storage in the CFF table and consequently some characters were dropped: '%s'" % copyright) if copyright is None: copyright = "" topDict.Copyright = copyright topDict.FullName = getAttrWithFallback(info, "postscriptFullName") topDict.FamilyName = getAttrWithFallback(info, "openTypeNamePreferredFamilyName") topDict.Weight = getAttrWithFallback(info, "postscriptWeightName") topDict.FontName = getAttrWithFallback(info, "postscriptFontName") # populate various numbers topDict.isFixedPitch = getAttrWithFallback(info, "postscriptIsFixedPitch") topDict.ItalicAngle = getAttrWithFallback(info, "italicAngle") underlinePosition = getAttrWithFallback(info, "postscriptUnderlinePosition") if underlinePosition is None: underlinePosition = 0 topDict.UnderlinePosition = _roundInt(underlinePosition) underlineThickness = getAttrWithFallback(info, "postscriptUnderlineThickness") if underlineThickness is None: underlineThickness = 0 topDict.UnderlineThickness = _roundInt(underlineThickness) # populate font matrix unitsPerEm = _roundInt(getAttrWithFallback(info, "unitsPerEm")) topDict.FontMatrix = [1.0 / unitsPerEm, 0, 0, 1.0 / unitsPerEm, 0, 0] # populate the width values defaultWidthX = _roundInt(getAttrWithFallback(info, "postscriptDefaultWidthX")) if defaultWidthX: private.rawDict["defaultWidthX"] = defaultWidthX nominalWidthX = _roundInt(getAttrWithFallback(info, "postscriptNominalWidthX")) if nominalWidthX: private.rawDict["nominalWidthX"] = nominalWidthX # populate hint data blueFuzz = _roundInt(getAttrWithFallback(info, "postscriptBlueFuzz")) blueShift = _roundInt(getAttrWithFallback(info, "postscriptBlueShift")) blueScale = getAttrWithFallback(info, "postscriptBlueScale") forceBold = getAttrWithFallback(info, "postscriptForceBold") blueValues = getAttrWithFallback(info, "postscriptBlueValues") if isinstance(blueValues, list): blueValues = [_roundInt(i) for i in blueValues] otherBlues = getAttrWithFallback(info, "postscriptOtherBlues") if isinstance(otherBlues, list): otherBlues = [_roundInt(i) for i in otherBlues] familyBlues = getAttrWithFallback(info, "postscriptFamilyBlues") if isinstance(familyBlues, list): familyBlues = [_roundInt(i) for i in familyBlues] familyOtherBlues = getAttrWithFallback(info, "postscriptFamilyOtherBlues") if isinstance(familyOtherBlues, list): familyOtherBlues = [_roundInt(i) for i in familyOtherBlues] stemSnapH = getAttrWithFallback(info, "postscriptStemSnapH") if isinstance(stemSnapH, list): stemSnapH = [_roundInt(i) for i in stemSnapH] stemSnapV = getAttrWithFallback(info, "postscriptStemSnapV") if isinstance(stemSnapV, list): stemSnapV = [_roundInt(i) for i in stemSnapV] # only write the blues data if some blues are defined. if (blueValues or otherBlues): private.rawDict["BlueFuzz"] = blueFuzz private.rawDict["BlueShift"] = blueShift private.rawDict["BlueScale"] = blueScale private.rawDict["ForceBold"] = forceBold private.rawDict["BlueValues"] = blueValues private.rawDict["OtherBlues"] = otherBlues private.rawDict["FamilyBlues"] = familyBlues private.rawDict["FamilyOtherBlues"] = familyOtherBlues # only write the stems if both are defined. if (stemSnapH and stemSnapV): private.rawDict["StemSnapH"] = stemSnapH private.rawDict["StdHW"] = stemSnapH[0] private.rawDict["StemSnapV"] = stemSnapV private.rawDict["StdVW"] = stemSnapV[0] # populate glyphs for glyphName in self.glyphOrder: glyph = self.allGlyphs[glyphName] unicodes = glyph.unicodes charString = self.getCharStringForGlyph(glyph, private, globalSubrs) # add to the font exists = charStrings.has_key(glyphName) if exists: # XXX a glyph already has this name. should we choke? glyphID = charStrings.charStrings[glyphName] charStringsIndex.items[glyphID] = charString else: charStringsIndex.append(charString) glyphID = len(topDict.charset) charStrings.charStrings[glyphName] = glyphID topDict.charset.append(glyphName) topDict.FontBBox = self.fontBoundingBox # write the glyph order self.otf.setGlyphOrder(self.glyphOrder)
def setupTable_hhea(self): """ Make the hhea table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["hhea"] = hhea = newTable("hhea") font = self.ufo hhea.tableVersion = 1.0 # vertical metrics hhea.ascent = _roundInt( getAttrWithFallback(font.info, "openTypeHheaAscender")) hhea.descent = _roundInt( getAttrWithFallback(font.info, "openTypeHheaDescender")) hhea.lineGap = _roundInt( getAttrWithFallback(font.info, "openTypeHheaLineGap")) # horizontal metrics widths = [] lefts = [] rights = [] extents = [] for glyph in self.allGlyphs.values(): left = glyph.leftMargin right = glyph.rightMargin if left is None: left = 0 if right is None: right = 0 widths.append(glyph.width) lefts.append(left) rights.append(right) # robofab if hasattr(glyph, "box"): bounds = glyph.box # others else: bounds = glyph.bounds if bounds is not None: xMin, yMin, xMax, yMax = bounds else: xMin = 0 xMax = 0 extent = left + ( xMax - xMin ) # equation from spec for calculating xMaxExtent: Max(lsb + (xMax - xMin)) extents.append(extent) hhea.advanceWidthMax = _roundInt(max(widths)) hhea.minLeftSideBearing = _roundInt(min(lefts)) hhea.minRightSideBearing = _roundInt(min(rights)) hhea.xMaxExtent = _roundInt(max(extents)) # misc hhea.caretSlopeRise = getAttrWithFallback( font.info, "openTypeHheaCaretSlopeRise") hhea.caretSlopeRun = getAttrWithFallback(font.info, "openTypeHheaCaretSlopeRun") hhea.caretOffset = _roundInt( getAttrWithFallback(font.info, "openTypeHheaCaretOffset")) hhea.reserved0 = 0 hhea.reserved1 = 0 hhea.reserved2 = 0 hhea.reserved3 = 0 hhea.metricDataFormat = 0 # glyph count hhea.numberOfHMetrics = len(self.allGlyphs)
def setupTable_OS2(self): """ Make the OS/2 table. **This should not be called externally.** Subclasses may override or supplement this method to handle the table creation in a different way if desired. """ self.otf["OS/2"] = os2 = newTable("OS/2") font = self.ufo os2.version = 0x0004 # average glyph width widths = [ glyph.width for glyph in self.allGlyphs.values() if glyph.width > 0 ] os2.xAvgCharWidth = _roundInt(sum(widths) / len(widths)) # weight and width classes os2.usWeightClass = getAttrWithFallback(font.info, "openTypeOS2WeightClass") os2.usWidthClass = getAttrWithFallback(font.info, "openTypeOS2WidthClass") # embedding os2.fsType = intListToNum( getAttrWithFallback(font.info, "openTypeOS2Type"), 0, 16) # subscript v = getAttrWithFallback(font.info, "openTypeOS2SubscriptXSize") if v is None: v = 0 os2.ySubscriptXSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptYSize") if v is None: v = 0 os2.ySubscriptYSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptXOffset") if v is None: v = 0 os2.ySubscriptXOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SubscriptYOffset") if v is None: v = 0 os2.ySubscriptYOffset = _roundInt(v) # superscript v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptXSize") if v is None: v = 0 os2.ySuperscriptXSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptYSize") if v is None: v = 0 os2.ySuperscriptYSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptXOffset") if v is None: v = 0 os2.ySuperscriptXOffset = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2SuperscriptYOffset") if v is None: v = 0 os2.ySuperscriptYOffset = _roundInt(v) # strikeout v = getAttrWithFallback(font.info, "openTypeOS2StrikeoutSize") if v is None: v = 0 os2.yStrikeoutSize = _roundInt(v) v = getAttrWithFallback(font.info, "openTypeOS2StrikeoutPosition") if v is None: v = 0 os2.yStrikeoutPosition = _roundInt(v) # family class os2.sFamilyClass = 0 # XXX not sure how to create the appropriate value # panose data = getAttrWithFallback(font.info, "openTypeOS2Panose") panose = Panose() panose.bFamilyType = data[0] panose.bSerifStyle = data[1] panose.bWeight = data[2] panose.bProportion = data[3] panose.bContrast = data[4] panose.bStrokeVariation = data[5] panose.bArmStyle = data[6] panose.bLetterForm = data[7] panose.bMidline = data[8] panose.bXHeight = data[9] os2.panose = panose # Unicode ranges uniRanges = getAttrWithFallback(font.info, "openTypeOS2UnicodeRanges") os2.ulUnicodeRange1 = intListToNum(uniRanges, 0, 32) os2.ulUnicodeRange2 = intListToNum(uniRanges, 32, 32) os2.ulUnicodeRange3 = intListToNum(uniRanges, 64, 32) os2.ulUnicodeRange4 = intListToNum(uniRanges, 96, 32) # codepage ranges codepageRanges = getAttrWithFallback(font.info, "openTypeOS2CodePageRanges") os2.ulCodePageRange1 = intListToNum(codepageRanges, 0, 32) os2.ulCodePageRange2 = intListToNum(codepageRanges, 32, 32) # vendor id os2.achVendID = str( getAttrWithFallback(font.info, "openTypeOS2VendorID").decode( "ascii", "ignore")) # vertical metrics os2.sxHeight = _roundInt(getAttrWithFallback(font.info, "xHeight")) os2.sCapHeight = _roundInt(getAttrWithFallback(font.info, "capHeight")) os2.sTypoAscender = _roundInt( getAttrWithFallback(font.info, "openTypeOS2TypoAscender")) os2.sTypoDescender = _roundInt( getAttrWithFallback(font.info, "openTypeOS2TypoDescender")) os2.sTypoLineGap = _roundInt( getAttrWithFallback(font.info, "openTypeOS2TypoLineGap")) os2.usWinAscent = _roundInt( getAttrWithFallback(font.info, "openTypeOS2WinAscent")) os2.usWinDescent = _roundInt( getAttrWithFallback(font.info, "openTypeOS2WinDescent")) # style mapping selection = list(getAttrWithFallback(font.info, "openTypeOS2Selection")) styleMapStyleName = getAttrWithFallback(font.info, "styleMapStyleName") if styleMapStyleName == "regular": selection.append(6) elif styleMapStyleName == "bold": selection.append(5) elif styleMapStyleName == "italic": selection.append(0) elif styleMapStyleName == "bold italic": selection += [0, 5] os2.fsSelection = intListToNum(selection, 0, 16) # characetr indexes unicodes = [ i for i in self.unicodeToGlyphNameMapping.keys() if i is not None ] if unicodes: minIndex = min(unicodes) maxIndex = max(unicodes) else: # the font may have *no* unicode values # (it really happens!) so there needs # to be a fallback. use space for this. minIndex = 0x0020 maxIndex = 0x0020 if maxIndex > 0xFFFF: # the spec says that 0xFFFF should be used # as the max if the max exceeds 0xFFFF maxIndex = 0xFFFF os2.fsFirstCharIndex = minIndex os2.fsLastCharIndex = maxIndex os2.usBreakChar = 32 os2.usDefaultChar = 0 # maximum contextual lookup length os2.usMaxContex = 0