| 1 | """ |
|---|
| 2 | This file provides fallback data for info attributes |
|---|
| 3 | that are required for building OTFs. There are two main |
|---|
| 4 | functions that are important: |
|---|
| 5 | |
|---|
| 6 | * :func:`~getAttrWithFallback` |
|---|
| 7 | * :func:`~preflightInfo` |
|---|
| 8 | |
|---|
| 9 | There are a set of other functions that are used internally |
|---|
| 10 | for synthesizing values for specific attributes. These can be |
|---|
| 11 | used externally as well. |
|---|
| 12 | """ |
|---|
| 13 | |
|---|
| 14 | import time |
|---|
| 15 | import unicodedata |
|---|
| 16 | from fontTools.misc.textTools import binary2num |
|---|
| 17 | from fontTools.misc.arrayTools import unionRect |
|---|
| 18 | import ufoLib |
|---|
| 19 | try: |
|---|
| 20 | set |
|---|
| 21 | except NameError: |
|---|
| 22 | from sets import Set as set |
|---|
| 23 | |
|---|
| 24 | # ----------------- |
|---|
| 25 | # Special Fallbacks |
|---|
| 26 | # ----------------- |
|---|
| 27 | |
|---|
| 28 | # generic |
|---|
| 29 | |
|---|
| 30 | def styleMapFamilyNameFallback(info): |
|---|
| 31 | """ |
|---|
| 32 | Fallback to *openTypeNamePreferredFamilyName openTypeNamePreferredSubfamilyName*. |
|---|
| 33 | """ |
|---|
| 34 | familyName = getAttrWithFallback(info, "openTypeNamePreferredFamilyName") |
|---|
| 35 | styleName = getAttrWithFallback(info, "openTypeNamePreferredSubfamilyName") |
|---|
| 36 | if styleName is None: |
|---|
| 37 | styleName = u"" |
|---|
| 38 | return (familyName + u" " + styleName).strip() |
|---|
| 39 | |
|---|
| 40 | # head |
|---|
| 41 | |
|---|
| 42 | def dateStringForNow(): |
|---|
| 43 | year, month, day, hour, minute, second, weekDay, yearDay, isDST = time.localtime() |
|---|
| 44 | year = str(year) |
|---|
| 45 | month = str(month).zfill(2) |
|---|
| 46 | day = str(day).zfill(2) |
|---|
| 47 | hour = str(hour).zfill(2) |
|---|
| 48 | minute = str(minute).zfill(2) |
|---|
| 49 | second = str(second).zfill(2) |
|---|
| 50 | return "%s/%s/%s %s:%s:%s" % (year, month, day, hour, minute, second) |
|---|
| 51 | |
|---|
| 52 | def openTypeHeadCreatedFallback(info): |
|---|
| 53 | """ |
|---|
| 54 | Fallback to now. |
|---|
| 55 | """ |
|---|
| 56 | return dateStringForNow() |
|---|
| 57 | |
|---|
| 58 | # hhea |
|---|
| 59 | |
|---|
| 60 | def openTypeHheaAscenderFallback(info): |
|---|
| 61 | """ |
|---|
| 62 | Fallback to *unitsPerEm + descender*. |
|---|
| 63 | """ |
|---|
| 64 | return info.unitsPerEm + info.descender |
|---|
| 65 | |
|---|
| 66 | def openTypeHheaDescenderFallback(info): |
|---|
| 67 | """ |
|---|
| 68 | Fallback to *descender*. |
|---|
| 69 | """ |
|---|
| 70 | return info.descender |
|---|
| 71 | |
|---|
| 72 | # name |
|---|
| 73 | |
|---|
| 74 | def openTypeNameVersionFallback(info): |
|---|
| 75 | """ |
|---|
| 76 | Fallback to *versionMajor.versionMinor* in the form 0.000. |
|---|
| 77 | """ |
|---|
| 78 | versionMajor = getAttrWithFallback(info, "versionMajor") |
|---|
| 79 | versionMinor = getAttrWithFallback(info, "versionMinor") |
|---|
| 80 | return "%d.%s" % (versionMajor, str(versionMinor).zfill(3)) |
|---|
| 81 | |
|---|
| 82 | def openTypeNameUniqueIDFallback(info): |
|---|
| 83 | """ |
|---|
| 84 | Fallback to *openTypeNameVersion;openTypeOS2VendorID;styleMapFamilyName styleMapStyleName*. |
|---|
| 85 | """ |
|---|
| 86 | version = getAttrWithFallback(info, "openTypeNameVersion") |
|---|
| 87 | vendor = getAttrWithFallback(info, "openTypeOS2VendorID") |
|---|
| 88 | familyName = getAttrWithFallback(info, "styleMapFamilyName") |
|---|
| 89 | styleName = getAttrWithFallback(info, "styleMapStyleName").title() |
|---|
| 90 | return u"%s;%s;%s %s" % (version, vendor, familyName, styleName) |
|---|
| 91 | |
|---|
| 92 | def openTypeNamePreferredFamilyNameFallback(info): |
|---|
| 93 | """ |
|---|
| 94 | Fallback to *familyName*. |
|---|
| 95 | """ |
|---|
| 96 | return info.familyName |
|---|
| 97 | |
|---|
| 98 | def openTypeNamePreferredSubfamilyNameFallback(info): |
|---|
| 99 | """ |
|---|
| 100 | Fallback to *styleName*. |
|---|
| 101 | """ |
|---|
| 102 | return info.styleName |
|---|
| 103 | |
|---|
| 104 | def openTypeNameCompatibleFullNameFallback(info): |
|---|
| 105 | """ |
|---|
| 106 | Fallback to *styleMapFamilyName styleMapStyleName*. |
|---|
| 107 | If *styleMapStyleName* is *regular* this will not add |
|---|
| 108 | the style name. |
|---|
| 109 | """ |
|---|
| 110 | familyName = getAttrWithFallback(info, "styleMapFamilyName") |
|---|
| 111 | styleMapStyleName = getAttrWithFallback(info, "styleMapStyleName") |
|---|
| 112 | if styleMapStyleName != "regular": |
|---|
| 113 | familyName += " " + styleMapStyleName.title() |
|---|
| 114 | return familyName |
|---|
| 115 | |
|---|
| 116 | def openTypeNameWWSFamilyNameFallback(info): |
|---|
| 117 | # not yet supported |
|---|
| 118 | return None |
|---|
| 119 | |
|---|
| 120 | def openTypeNameWWSSubfamilyNameFallback(info): |
|---|
| 121 | # not yet supported |
|---|
| 122 | return None |
|---|
| 123 | |
|---|
| 124 | # OS/2 |
|---|
| 125 | |
|---|
| 126 | def openTypeOS2TypoAscenderFallback(info): |
|---|
| 127 | """ |
|---|
| 128 | Fallback to *unitsPerEm + descender*. |
|---|
| 129 | """ |
|---|
| 130 | return info.unitsPerEm + info.descender |
|---|
| 131 | |
|---|
| 132 | def openTypeOS2TypoDescenderFallback(info): |
|---|
| 133 | """ |
|---|
| 134 | Fallback to *descender*. |
|---|
| 135 | """ |
|---|
| 136 | return info.descender |
|---|
| 137 | |
|---|
| 138 | def openTypeOS2WinAscentFallback(info): |
|---|
| 139 | """ |
|---|
| 140 | Fallback to the maximum y value of the font's bounding box. |
|---|
| 141 | If that is not available, fallback to *ascender*. |
|---|
| 142 | """ |
|---|
| 143 | font = info.getParent() |
|---|
| 144 | if font is None: |
|---|
| 145 | return getAttrWithFallback(info, "ascender") |
|---|
| 146 | bounds = getFontBounds(font) |
|---|
| 147 | xMin, yMin, xMax, yMax = bounds |
|---|
| 148 | return yMax |
|---|
| 149 | |
|---|
| 150 | def openTypeOS2WinDescentFallback(info): |
|---|
| 151 | """ |
|---|
| 152 | Fallback to the minimum y value of the font's bounding box. |
|---|
| 153 | If that is not available, fallback to *descender*. |
|---|
| 154 | """ |
|---|
| 155 | font = info.getParent() |
|---|
| 156 | if font is None: |
|---|
| 157 | return abs(getAttrWithFallback(info, "descender")) |
|---|
| 158 | bounds = getFontBounds(font) |
|---|
| 159 | if bounds is None: |
|---|
| 160 | return abs(getAttrWithFallback(info, "descender")) |
|---|
| 161 | xMin, yMin, xMax, yMax = bounds |
|---|
| 162 | return abs(yMin) |
|---|
| 163 | |
|---|
| 164 | # postscript |
|---|
| 165 | |
|---|
| 166 | _postscriptFontNameExceptions = set(" [](){}<>/%") |
|---|
| 167 | _postscriptFontNameAllowed = set([unichr(i) for i in xrange(33, 137)]) |
|---|
| 168 | |
|---|
| 169 | def normalizeNameForPostscript(name): |
|---|
| 170 | normalized = [] |
|---|
| 171 | for c in name: |
|---|
| 172 | if c in _postscriptFontNameExceptions: |
|---|
| 173 | continue |
|---|
| 174 | if c not in _postscriptFontNameAllowed: |
|---|
| 175 | c = unicodedata.normalize("NFKD", c).encode("ascii", "ignore") |
|---|
| 176 | normalized.append(c) |
|---|
| 177 | return "".join(normalized) |
|---|
| 178 | |
|---|
| 179 | def postscriptFontNameFallback(info): |
|---|
| 180 | """ |
|---|
| 181 | Fallback to a string containing only valid characters |
|---|
| 182 | as defined in the specification. This will draw from |
|---|
| 183 | *openTypeNamePreferredFamilyName* and *openTypeNamePreferredSubfamilyName*. |
|---|
| 184 | """ |
|---|
| 185 | name = u"%s-%s" % (getAttrWithFallback(info, "openTypeNamePreferredFamilyName"), getAttrWithFallback(info, "openTypeNamePreferredSubfamilyName")) |
|---|
| 186 | return normalizeNameForPostscript(name) |
|---|
| 187 | |
|---|
| 188 | def postscriptFullNameFallback(info): |
|---|
| 189 | """ |
|---|
| 190 | Fallback to *openTypeNamePreferredFamilyName openTypeNamePreferredSubfamilyName*. |
|---|
| 191 | """ |
|---|
| 192 | return u"%s %s" % (getAttrWithFallback(info, "openTypeNamePreferredFamilyName"), getAttrWithFallback(info, "openTypeNamePreferredSubfamilyName")) |
|---|
| 193 | |
|---|
| 194 | def postscriptSlantAngleFallback(info): |
|---|
| 195 | """ |
|---|
| 196 | Fallback to *italicAngle*. |
|---|
| 197 | """ |
|---|
| 198 | return getAttrWithFallback(info, "italicAngle") |
|---|
| 199 | |
|---|
| 200 | _postscriptWeightNameOptions = { |
|---|
| 201 | 100 : "Thin", |
|---|
| 202 | 200 : "Extra-light", |
|---|
| 203 | 300 : "Light", |
|---|
| 204 | 400 : "Normal", |
|---|
| 205 | 500 : "Medium", |
|---|
| 206 | 600 : "Semi-bold", |
|---|
| 207 | 700 : "Bold", |
|---|
| 208 | 800 : "Extra-bold", |
|---|
| 209 | 900 : "Black" |
|---|
| 210 | } |
|---|
| 211 | |
|---|
| 212 | def postscriptWeightNameFallback(info): |
|---|
| 213 | """ |
|---|
| 214 | Fallback to the closest match of the *openTypeOS2WeightClass* |
|---|
| 215 | in this table: |
|---|
| 216 | |
|---|
| 217 | === =========== |
|---|
| 218 | 100 Thin |
|---|
| 219 | 200 Extra-light |
|---|
| 220 | 300 Light |
|---|
| 221 | 400 Normal |
|---|
| 222 | 500 Medium |
|---|
| 223 | 600 Semi-bold |
|---|
| 224 | 700 Bold |
|---|
| 225 | 800 Extra-bold |
|---|
| 226 | 900 Black |
|---|
| 227 | === =========== |
|---|
| 228 | """ |
|---|
| 229 | value = getAttrWithFallback(info, "openTypeOS2WeightClass") |
|---|
| 230 | value = int(round(value * .01) * 100) |
|---|
| 231 | if value < 100: |
|---|
| 232 | value = 100 |
|---|
| 233 | elif value > 900: |
|---|
| 234 | value = 900 |
|---|
| 235 | name = _postscriptWeightNameOptions[value] |
|---|
| 236 | return name |
|---|
| 237 | |
|---|
| 238 | # -------------- |
|---|
| 239 | # Attribute Maps |
|---|
| 240 | # -------------- |
|---|
| 241 | |
|---|
| 242 | staticFallbackData = dict( |
|---|
| 243 | styleMapStyleName="regular", |
|---|
| 244 | versionMajor=0, |
|---|
| 245 | versionMinor=0, |
|---|
| 246 | copyright=None, |
|---|
| 247 | trademark=None, |
|---|
| 248 | italicAngle=0, |
|---|
| 249 | # not needed |
|---|
| 250 | year=None, |
|---|
| 251 | note=None, |
|---|
| 252 | |
|---|
| 253 | openTypeHeadLowestRecPPEM=6, |
|---|
| 254 | openTypeHeadFlags=[0, 1], |
|---|
| 255 | |
|---|
| 256 | openTypeHheaLineGap=200, |
|---|
| 257 | openTypeHheaCaretSlopeRise=1, |
|---|
| 258 | openTypeHheaCaretSlopeRun=0, |
|---|
| 259 | openTypeHheaCaretOffset=0, |
|---|
| 260 | |
|---|
| 261 | openTypeNameDesigner=None, |
|---|
| 262 | openTypeNameDesignerURL=None, |
|---|
| 263 | openTypeNameManufacturer=None, |
|---|
| 264 | openTypeNameManufacturerURL=None, |
|---|
| 265 | openTypeNameLicense=None, |
|---|
| 266 | openTypeNameLicenseURL=None, |
|---|
| 267 | openTypeNameDescription=None, |
|---|
| 268 | openTypeNameSampleText=None, |
|---|
| 269 | |
|---|
| 270 | openTypeOS2WidthClass=5, |
|---|
| 271 | openTypeOS2WeightClass=400, |
|---|
| 272 | openTypeOS2Selection=[], |
|---|
| 273 | openTypeOS2VendorID="NONE", |
|---|
| 274 | openTypeOS2Panose=[0, 0, 0, 0, 0, 0, 0, 0, 0, 0], |
|---|
| 275 | openTypeOS2FamilyClass=[0, 0], |
|---|
| 276 | openTypeOS2UnicodeRanges=[], |
|---|
| 277 | openTypeOS2CodePageRanges=[], |
|---|
| 278 | openTypeOS2TypoLineGap=200, |
|---|
| 279 | openTypeOS2Type=[2], |
|---|
| 280 | # let the FDK fallback on these |
|---|
| 281 | openTypeOS2SubscriptXSize=None, |
|---|
| 282 | openTypeOS2SubscriptYSize=None, |
|---|
| 283 | openTypeOS2SubscriptXOffset=None, |
|---|
| 284 | openTypeOS2SubscriptYOffset=None, |
|---|
| 285 | openTypeOS2SuperscriptXSize=None, |
|---|
| 286 | openTypeOS2SuperscriptYSize=None, |
|---|
| 287 | openTypeOS2SuperscriptXOffset=None, |
|---|
| 288 | openTypeOS2SuperscriptYOffset=None, |
|---|
| 289 | openTypeOS2StrikeoutSize=None, |
|---|
| 290 | openTypeOS2StrikeoutPosition=None, |
|---|
| 291 | |
|---|
| 292 | # fallback to None on these |
|---|
| 293 | # as the user should be in |
|---|
| 294 | # complete control |
|---|
| 295 | openTypeVheaVertTypoAscender=None, |
|---|
| 296 | openTypeVheaVertTypoDescender=None, |
|---|
| 297 | openTypeVheaVertTypoLineGap=None, |
|---|
| 298 | openTypeVheaCaretSlopeRise=None, |
|---|
| 299 | openTypeVheaCaretSlopeRun=None, |
|---|
| 300 | openTypeVheaCaretOffset=None, |
|---|
| 301 | |
|---|
| 302 | postscriptUniqueID=None, |
|---|
| 303 | postscriptUnderlineThickness=None, |
|---|
| 304 | postscriptUnderlinePosition=None, |
|---|
| 305 | postscriptIsFixedPitch=False, |
|---|
| 306 | postscriptBlueValues=[], |
|---|
| 307 | postscriptOtherBlues=[], |
|---|
| 308 | postscriptFamilyBlues=[], |
|---|
| 309 | postscriptFamilyOtherBlues=[], |
|---|
| 310 | postscriptStemSnapH=[], |
|---|
| 311 | postscriptStemSnapV=[], |
|---|
| 312 | postscriptBlueFuzz=1, |
|---|
| 313 | postscriptBlueShift=7, |
|---|
| 314 | postscriptBlueScale=.039625, |
|---|
| 315 | postscriptForceBold=False, |
|---|
| 316 | postscriptDefaultWidthX=200, |
|---|
| 317 | postscriptNominalWidthX=0, |
|---|
| 318 | |
|---|
| 319 | # not used in OTF |
|---|
| 320 | postscriptDefaultCharacter=None, |
|---|
| 321 | postscriptWindowsCharacterSet=None, |
|---|
| 322 | |
|---|
| 323 | # not used in OTF |
|---|
| 324 | macintoshFONDFamilyID=None, |
|---|
| 325 | macintoshFONDName=None |
|---|
| 326 | ) |
|---|
| 327 | |
|---|
| 328 | specialFallbacks = dict( |
|---|
| 329 | styleMapFamilyName=styleMapFamilyNameFallback, |
|---|
| 330 | openTypeHeadCreated=openTypeHeadCreatedFallback, |
|---|
| 331 | openTypeHheaAscender=openTypeHheaAscenderFallback, |
|---|
| 332 | openTypeHheaDescender=openTypeHheaDescenderFallback, |
|---|
| 333 | openTypeNameVersion=openTypeNameVersionFallback, |
|---|
| 334 | openTypeNameUniqueID=openTypeNameUniqueIDFallback, |
|---|
| 335 | openTypeNamePreferredFamilyName=openTypeNamePreferredFamilyNameFallback, |
|---|
| 336 | openTypeNamePreferredSubfamilyName=openTypeNamePreferredSubfamilyNameFallback, |
|---|
| 337 | openTypeNameCompatibleFullName=openTypeNameCompatibleFullNameFallback, |
|---|
| 338 | openTypeNameWWSFamilyName=openTypeNameWWSFamilyNameFallback, |
|---|
| 339 | openTypeNameWWSSubfamilyName=openTypeNameWWSSubfamilyNameFallback, |
|---|
| 340 | openTypeOS2TypoAscender=openTypeOS2TypoAscenderFallback, |
|---|
| 341 | openTypeOS2TypoDescender=openTypeOS2TypoDescenderFallback, |
|---|
| 342 | openTypeOS2WinAscent=openTypeOS2WinAscentFallback, |
|---|
| 343 | openTypeOS2WinDescent=openTypeOS2WinDescentFallback, |
|---|
| 344 | postscriptFontName=postscriptFontNameFallback, |
|---|
| 345 | postscriptFullName=postscriptFullNameFallback, |
|---|
| 346 | postscriptSlantAngle=postscriptSlantAngleFallback, |
|---|
| 347 | postscriptWeightName=postscriptWeightNameFallback |
|---|
| 348 | ) |
|---|
| 349 | |
|---|
| 350 | requiredAttributes = set(ufoLib.fontInfoAttributesVersion2) - (set(staticFallbackData.keys()) | set(specialFallbacks.keys())) |
|---|
| 351 | |
|---|
| 352 | recommendedAttributes = set([ |
|---|
| 353 | "styleMapFamilyName", |
|---|
| 354 | "versionMajor", |
|---|
| 355 | "versionMinor", |
|---|
| 356 | "copyright", |
|---|
| 357 | "trademark", |
|---|
| 358 | "openTypeHeadCreated", |
|---|
| 359 | "openTypeNameDesigner", |
|---|
| 360 | "openTypeNameDesignerURL", |
|---|
| 361 | "openTypeNameManufacturer", |
|---|
| 362 | "openTypeNameManufacturerURL", |
|---|
| 363 | "openTypeNameLicense", |
|---|
| 364 | "openTypeNameLicenseURL", |
|---|
| 365 | "openTypeNameDescription", |
|---|
| 366 | "openTypeNameSampleText", |
|---|
| 367 | "openTypeOS2WidthClass", |
|---|
| 368 | "openTypeOS2WeightClass", |
|---|
| 369 | "openTypeOS2VendorID", |
|---|
| 370 | "openTypeOS2Panose", |
|---|
| 371 | "openTypeOS2FamilyClass", |
|---|
| 372 | "openTypeOS2UnicodeRanges", |
|---|
| 373 | "openTypeOS2CodePageRanges", |
|---|
| 374 | "openTypeOS2TypoLineGap", |
|---|
| 375 | "openTypeOS2Type", |
|---|
| 376 | "postscriptBlueValues", |
|---|
| 377 | "postscriptOtherBlues", |
|---|
| 378 | "postscriptFamilyBlues", |
|---|
| 379 | "postscriptFamilyOtherBlues", |
|---|
| 380 | "postscriptStemSnapH", |
|---|
| 381 | "postscriptStemSnapV" |
|---|
| 382 | ]) |
|---|
| 383 | |
|---|
| 384 | # ------------ |
|---|
| 385 | # Main Methods |
|---|
| 386 | # ------------ |
|---|
| 387 | |
|---|
| 388 | def getAttrWithFallback(info, attr): |
|---|
| 389 | """ |
|---|
| 390 | Get the value for *attr* from the *info* object. |
|---|
| 391 | If the object does not have the attribute or the value |
|---|
| 392 | for the atribute is None, this will either get a |
|---|
| 393 | value from a predefined set of attributes or it |
|---|
| 394 | will synthesize a value from the available data. |
|---|
| 395 | """ |
|---|
| 396 | if hasattr(info, attr) and getattr(info, attr) is not None: |
|---|
| 397 | value = getattr(info, attr) |
|---|
| 398 | else: |
|---|
| 399 | if attr in specialFallbacks: |
|---|
| 400 | value = specialFallbacks[attr](info) |
|---|
| 401 | else: |
|---|
| 402 | value = staticFallbackData[attr] |
|---|
| 403 | return value |
|---|
| 404 | |
|---|
| 405 | def preflightInfo(info): |
|---|
| 406 | """ |
|---|
| 407 | Returns a dict containing two items. The value for each |
|---|
| 408 | item will be a list of info attribute names. |
|---|
| 409 | |
|---|
| 410 | ================== === |
|---|
| 411 | missingRequired Required data that is missing. |
|---|
| 412 | missingRecommended Recommended data that is missing. |
|---|
| 413 | ================== === |
|---|
| 414 | """ |
|---|
| 415 | missingRequired = set() |
|---|
| 416 | missingRecommended = set() |
|---|
| 417 | for attr in requiredAttributes: |
|---|
| 418 | if not hasattr(info, attr) or getattr(info, attr) is None: |
|---|
| 419 | missingRequired.add(attr) |
|---|
| 420 | for attr in recommendedAttributes: |
|---|
| 421 | if not hasattr(info, attr) or getattr(info, attr) is None: |
|---|
| 422 | missingRecommended.add(attr) |
|---|
| 423 | return dict(missingRequired=missingRequired, missingRecommended=missingRecommended) |
|---|
| 424 | |
|---|
| 425 | def getFontBounds(font): |
|---|
| 426 | """ |
|---|
| 427 | Get a tuple of (xMin, yMin, xMax, yMax) for all |
|---|
| 428 | glyphs in the given *font*. |
|---|
| 429 | """ |
|---|
| 430 | rect = None |
|---|
| 431 | # defcon |
|---|
| 432 | if hasattr(font, "bounds"): |
|---|
| 433 | rect = font.bounds |
|---|
| 434 | # others |
|---|
| 435 | else: |
|---|
| 436 | for glyph in font: |
|---|
| 437 | # robofab |
|---|
| 438 | if hasattr(glyph,"box"): |
|---|
| 439 | bounds = glyph.box |
|---|
| 440 | # others |
|---|
| 441 | else: |
|---|
| 442 | bounds = glyph.bounds |
|---|
| 443 | if rect is None: |
|---|
| 444 | rect = bounds |
|---|
| 445 | continue |
|---|
| 446 | if rect is not None and bounds is not None: |
|---|
| 447 | rect = unionRect(rect, bounds) |
|---|
| 448 | if rect is None: |
|---|
| 449 | rect = (0, 0, 0, 0) |
|---|
| 450 | return rect |
|---|
| 451 | |
|---|
| 452 | # ----------------- |
|---|
| 453 | # Low Level Support |
|---|
| 454 | # ----------------- |
|---|
| 455 | |
|---|
| 456 | # these should not be used outside of this package |
|---|
| 457 | |
|---|
| 458 | def intListToNum(intList, start, length): |
|---|
| 459 | all = [] |
|---|
| 460 | bin = "" |
|---|
| 461 | for i in range(start, start+length): |
|---|
| 462 | if i in intList: |
|---|
| 463 | b = "1" |
|---|
| 464 | else: |
|---|
| 465 | b = "0" |
|---|
| 466 | bin = b + bin |
|---|
| 467 | if not (i + 1) % 8: |
|---|
| 468 | all.append(bin) |
|---|
| 469 | bin = "" |
|---|
| 470 | if bin: |
|---|
| 471 | all.append(bin) |
|---|
| 472 | all.reverse() |
|---|
| 473 | all = " ".join(all) |
|---|
| 474 | return binary2num(all) |
|---|
| 475 | |
|---|
| 476 | def dateStringToTimeValue(date): |
|---|
| 477 | try: |
|---|
| 478 | t = time.strptime(date, "%Y/%m/%d %H:%M:%S") |
|---|
| 479 | return long(time.mktime(t)) |
|---|
| 480 | except OverflowError: |
|---|
| 481 | return 0L |
|---|
| 482 | |
|---|
| 483 | # ---- |
|---|
| 484 | # Test |
|---|
| 485 | # ---- |
|---|
| 486 | |
|---|
| 487 | class _TestInfoObject(object): |
|---|
| 488 | |
|---|
| 489 | def __init__(self): |
|---|
| 490 | self.familyName = "Family Name" |
|---|
| 491 | self.styleName = "Style Name" |
|---|
| 492 | self.unitsPerEm = 1000 |
|---|
| 493 | self.descender = -250 |
|---|
| 494 | self.xHeight = 450 |
|---|
| 495 | self.capHeight = 600 |
|---|
| 496 | self.ascender = 650 |
|---|
| 497 | self.bounds = (0, -225, 100, 755) |
|---|
| 498 | |
|---|
| 499 | def getParent(self): |
|---|
| 500 | return self |
|---|
| 501 | |
|---|
| 502 | |
|---|
| 503 | def _test(): |
|---|
| 504 | """ |
|---|
| 505 | >>> info = _TestInfoObject() |
|---|
| 506 | |
|---|
| 507 | >>> getAttrWithFallback(info, "familyName") |
|---|
| 508 | 'Family Name' |
|---|
| 509 | >>> getAttrWithFallback(info, "styleName") |
|---|
| 510 | 'Style Name' |
|---|
| 511 | |
|---|
| 512 | >>> getAttrWithFallback(info, "styleMapFamilyName") |
|---|
| 513 | u'Family Name Style Name' |
|---|
| 514 | >>> info.styleMapFamilyName = "Style Map Family Name" |
|---|
| 515 | >>> getAttrWithFallback(info, "styleMapFamilyName") |
|---|
| 516 | 'Style Map Family Name' |
|---|
| 517 | |
|---|
| 518 | >>> getAttrWithFallback(info, "openTypeNamePreferredFamilyName") |
|---|
| 519 | 'Family Name' |
|---|
| 520 | >>> getAttrWithFallback(info, "openTypeNamePreferredSubfamilyName") |
|---|
| 521 | 'Style Name' |
|---|
| 522 | >>> getAttrWithFallback(info, "openTypeNameCompatibleFullName") |
|---|
| 523 | 'Style Map Family Name' |
|---|
| 524 | |
|---|
| 525 | >>> getAttrWithFallback(info, "openTypeHheaAscender") |
|---|
| 526 | 750 |
|---|
| 527 | >>> getAttrWithFallback(info, "openTypeHheaDescender") |
|---|
| 528 | -250 |
|---|
| 529 | |
|---|
| 530 | >>> getAttrWithFallback(info, "openTypeNameVersion") |
|---|
| 531 | '0.000' |
|---|
| 532 | >>> info.versionMinor = 1 |
|---|
| 533 | >>> info.versionMajor = 1 |
|---|
| 534 | >>> getAttrWithFallback(info, "openTypeNameVersion") |
|---|
| 535 | '1.001' |
|---|
| 536 | |
|---|
| 537 | >>> getAttrWithFallback(info, "openTypeNameUniqueID") |
|---|
| 538 | u'1.001;NONE;Style Map Family Name Regular' |
|---|
| 539 | |
|---|
| 540 | >>> getAttrWithFallback(info, "openTypeOS2TypoAscender") |
|---|
| 541 | 750 |
|---|
| 542 | >>> getAttrWithFallback(info, "openTypeOS2TypoDescender") |
|---|
| 543 | -250 |
|---|
| 544 | >>> getAttrWithFallback(info, "openTypeOS2WinAscent") |
|---|
| 545 | 755 |
|---|
| 546 | >>> getAttrWithFallback(info, "openTypeOS2WinDescent") |
|---|
| 547 | 225 |
|---|
| 548 | |
|---|
| 549 | >>> getAttrWithFallback(info, "postscriptSlantAngle") |
|---|
| 550 | 0 |
|---|
| 551 | >>> getAttrWithFallback(info, "postscriptWeightName") |
|---|
| 552 | 'Normal' |
|---|
| 553 | """ |
|---|
| 554 | |
|---|
| 555 | if __name__ == "__main__": |
|---|
| 556 | import doctest |
|---|
| 557 | doctest.testmod() |
|---|