def fromwalker(cls, w, **kwArgs): """ Creates and returns a TTSimpleGlyph object from the specified walker. >>> _testingValues[1] == TTSimpleGlyph.frombytes(_testingValues[1].binaryString()) True >>> _testingValues[2] == TTSimpleGlyph.frombytes(_testingValues[2].binaryString()) True """ numContours = w.unpack("H") assert numContours != 0xFFFF, "Composite glyph passed to simple glyph walker!" b = ttbounds.TTBounds.fromwalker(w, **kwArgs) if numContours == 0 and b == ttbounds.TTBounds(): # special case b = None if numContours: endPoints = w.group("H", numContours) h = w.chunk(w.unpack("H")) if numContours: kwArgs.pop('endPoints', None) c = ttcontours.TTContours.fromwalker(w, endPoints=endPoints, **kwArgs) else: c = ttcontours.TTContours() return cls(b, c, h)
def fromscaleroutline(cls, outl, **kwArgs): """ Constructs and returns a TTSimpleglyph using the specified outline data. The outline data must conform to the ScalerInterface outline format (see ScalerInterface.getOutline() for details). Accepts kwArg 'hints', which will be stored as hintBytes if present. """ ctrs = [] ctr = None ird = lambda x: int(round(x)) TTP = ttpoint.TTPoint n = len(outl) - 1 hintBytes = kwArgs.get('hints') or '' for i, pt in enumerate(outl): last = (i == n) or (i < n and outl[i+1].kind == 'move') if pt.kind == 'move': if ctr: ctrs.append(ctr) npt = TTP(ird(pt.x), ird(pt.y), onCurve=True) ctr = ttcontour.TTContour() ctr.append(npt) if pt.kind == 'line': npt = TTP(ird(pt.x), ird(pt.y), onCurve=True) if last and npt.x == ctr[0].x and npt.y == ctr[0].y: pass # explicit contour close; don't add else: ctr.append(npt) if pt.kind == 'quad': offpt = TTP( ird(pt.offCurvePoint.x), ird(pt.offCurvePoint.y), onCurve=False) onpt = TTP( ird(pt.onCurvePoint.x), ird(pt.onCurvePoint.y), onCurve=True) ctr.append(offpt) if last and onpt.x == ctr[0].x and onpt.y == ctr[0].y: pass # explicit contour close; don't add. else: ctr.append(onpt) if ctr: ctrs.append(ctr) return cls( bounds=ttbounds.TTBounds.fromcontours(ctrs), contours=ttcontours.TTContours(ctrs), hintBytes=hintBytes)
def _makeTestContours(): from fontio3.glyf import ttcontour, ttcontours, ttpoint P = ttpoint.TTPoint C = ttcontour.TTContour return ttcontours.TTContours([ C([P(100, 100), P(100, 1100), P(1900, 1100), P(1900, 100)]), # 0 C([P(200, 200), P(1400, 200), P(1400, 1000), P(200, 1000)]), # 1 C([P(1500, 200), P(1800, 200), P(1800, 1000), P(1500, 1000)]), # 2 C([P(300, 300), P(300, 900), P(1000, 900), P(1000, 300)]), # 3 C([P(1100, 300), P(1100, 900), P(1300, 900), P(1300, 300)]), # 4 C([P(400, 400), P(500, 400), P(500, 500), P(400, 500)]), # 5 C([P(1550, 700), P(1550, 900), P(1650, 900), P(1650, 700)]), # 6 C([P(1650, 300), P(1650, 500), P(1750, 500), P(1750, 300)]), # 7 C([P(2000, 500), P(2000, 600), P(2100, 600), P(2100, 500)]) ]) # 8
def fromcompositeglyph(cls, compositeGlyph, **kwArgs): """ Constructs and returns a TTSimpleGlyph using the specified composite glyph as a "template." The kwArgs must contain an editor. """ try: v = list(compositeGlyph.pieceIterator(**kwArgs)) except: v = None if v is None: return cls() vx = [c.transformed(m) for obj, m in v for c in obj] return cls( bounds = ttbounds.TTBounds.fromcontours(vx), contours = ttcontours.TTContours(vx), hintBytes = compositeGlyph.hintBytes)
def fromvalidatedwalker(cls, w, **kwArgs): """ Like fromwalker(), this method returns a new TTSimpleGlyph. However, it also does extensive validation via the logging module (the client should have done a logging.basicConfig call prior to calling this method, unless a logger is passed in via the 'logger' keyword argument). >>> logger = utilities.makeDoctestLogger('test') >>> s = _testingValues[2].binaryString() >>> TTSimpleGlyph.fromvalidatedbytes(s, logger=logger).pprint() test.ttsimpleglyph - DEBUG - Walker has 44 remaining bytes. test.ttsimpleglyph.ttbounds - DEBUG - Walker has 42 remaining bytes. test.ttsimpleglyph.ttcontours - DEBUG - Walker has 26 remaining bytes. Bounds: Minimum X: 620 Minimum Y: 610 Maximum X: 980 Maximum Y: 1090 Contours: Contour 0: Point 0: (620, 610), on-curve Point 1: (620, 1090), on-curve Point 2: (980, 1090), on-curve Point 3: (980, 610), on-curve Contour 1: Point 0: (750, 750), on-curve Point 1: (850, 700), off-curve Point 2: (950, 750), on-curve Point 3: (850, 1000), on-curve Hints: 0000 (0x000000): SVTCA[y] 0001 (0x000001): SVTCA[x] >>> fvb = TTSimpleGlyph.fromvalidatedbytes >>> obj = fvb(s[:-1], logger=logger) test.ttsimpleglyph - DEBUG - Walker has 43 remaining bytes. test.ttsimpleglyph.ttbounds - DEBUG - Walker has 41 remaining bytes. test.ttsimpleglyph.ttcontours - DEBUG - Walker has 25 remaining bytes. test.ttsimpleglyph.ttcontours - ERROR - Insufficient bytes for y-delta. >>> _testingValues[1] == fvb(_testingValues[1].binaryString(), logger=logger) test.ttsimpleglyph - DEBUG - Walker has 14 remaining bytes. test.ttsimpleglyph.ttbounds - DEBUG - Walker has 12 remaining bytes. True """ logger = kwArgs.pop('logger', None) if logger is None: logger = logging.getLogger().getChild('ttsimpleglyph') else: logger = logger.getChild('ttsimpleglyph') logger.debug(( 'V0001', (w.length(),), "Walker has %d remaining bytes.")) if w.length() < 2: logger.error(('V0004', (), "Insufficient bytes.")) return None numContours = w.unpack("H") if numContours == 0xFFFF: logger.error(( 'V0002', (), "Composite glyph passed to TTSimpleGlyph.")) return None b = ttbounds.TTBounds.fromvalidatedwalker(w, logger=logger, **kwArgs) if b is None: return None if numContours == 0 and b == ttbounds.TTBounds(): # special-case b = None if numContours: if w.length() < 2 * numContours: logger.error(('V0187', (), "Insufficient bytes for endPoints.")) return None endPoints = w.group("H", numContours) if sorted(set(endPoints)) != list(endPoints): logger.error(( 'V0987', (), "Endpoints have duplicates or are out-of-order.")) return None if w.length() < 2: logger.error(('V0188', (), "Insufficient bytes for hint length.")) return None hintLength = w.unpack("H") if hintLength: if w.length() < hintLength: logger.error(('V0189', (), "Insufficient bytes for hints.")) return None h = w.chunk(hintLength) else: h = b'' if numContours: kwArgs.pop('endPoints', None) c = ttcontours.TTContours.fromvalidatedwalker( w, endPoints = endPoints, logger = logger, **kwArgs) if c is None: c = ttcontours.TTContours() else: c = ttcontours.TTContours() if w.length(): pad = w.rest() if len(pad) > 3: logger.error(('V1007', (), "More than 3 pad bytes following glyph data.")) if any(pad): logger.error(('V1008', (), "Non-zero pad bytes following glyph data.")) return cls(b, c, h)