def draw(self, pen): if self.transform: pen = TransformPen(pen, self.transform) for path in self.paths: current_pos = None for s in path: if current_pos != s.start: if current_pos is not None: pen.closePath() pen.moveTo((s.start.real, s.start.imag)) if isinstance(s, Line): pen.lineTo((s.end.real, s.end.imag)) elif isinstance(s, CubicBezier): pen.curveTo( (s.control1.real, s.control1.imag), (s.control2.real, s.control2.imag), (s.end.real, s.end.imag)) elif isinstance(s, QuadraticBezier): pen.qCurveTo( (s.control.real, s.control.imag), (s.end.real, s.end.imag)) #else: # TODO convert Arc segments to bezier? #raise NotImplementedError(s) current_pos = s.end pen.closePath()
def drawAICBOutlines(data, pen, fitInside=(None, None, None, None), fixedScale=None): """ Draw outline data from an eps. Returns True if the data was drawn, False if not. data = the EPS data (string) pen = a drawing pen fitInside = the maximum size that the outline can be drawn into. the function will transform the eps outlines to fit within this box. if you don't want to transform the data, send it a box of (None, None, None, None). it is also possible to transform based on only horizontal OR vertical parameters. Simply send a box formatted like: (None, -250, None, 750) to base the transform on vertical dimensions or like: (-1000, None, 1000, None) to base the transform on horizontal dimensions. fixedScale = a set scale factor for transforming the outline. If the resulting scaled outline is larger than the fit rect, the outline will be centered on those parameters. """ from fontTools.pens.transformPen import TransformPen from fontTools.misc.arrayTools import calcBounds data = '\n'.join(data.splitlines()) ## ## get the point data # FL follows the EPSF3.0 spec, but AI seems # to be using a different spec. AI puts the outline data # in layers. we can get around this by iterating over all lines # in the data and drawing points as we find them. contours = [] previousOnCurve = None for line in data.splitlines(): movetoMatch = moveto_RE.match(line) if movetoMatch: contours.append([]) x = float(movetoMatch.group(1)) y = float(movetoMatch.group(2)) contours[-1].append(('move', [(x, y)])) previousOnCurve = (x, y) continue linetoMatch = lineto_RE.match(line) if linetoMatch: x = float(linetoMatch.group(1)) y = float(linetoMatch.group(2)) contours[-1].append(('line', [(x, y)])) previousOnCurve = (x, y) continue startCurveToMatch = startCurveTo_RE.match(line) if startCurveToMatch: x1 = float(startCurveToMatch.group(1)) y1 = float(startCurveToMatch.group(2)) x2 = float(startCurveToMatch.group(3)) y2 = float(startCurveToMatch.group(4)) contours[-1].append(('curve', [previousOnCurve, (x1, y1), (x2, y2)])) previousOnCurve = (x2, y2) continue endCurveToMatch = endCurveTo_RE.match(line) if endCurveToMatch: x1 = float(endCurveToMatch.group(1)) y1 = float(endCurveToMatch.group(2)) x2 = float(endCurveToMatch.group(3)) y2 = float(endCurveToMatch.group(4)) contours[-1].append(('curve', [(x1, y1), (x2, y2), (x2, y2)])) previousOnCurve = (x2, y2) continue curvetoMatch = curveto_RE.match(line) if curvetoMatch: x1 = float(curvetoMatch.group(1)) y1 = float(curvetoMatch.group(2)) x2 = float(curvetoMatch.group(3)) y2 = float(curvetoMatch.group(4)) x3 = float(curvetoMatch.group(5)) y3 = float(curvetoMatch.group(6)) contours[-1].append(('curve', [(x1, y1), (x2, y2), (x3, y3)])) previousOnCurve = (x3, y3) continue # no outline data. give up. if not contours: return False ## get the bounding box boundingBox = boundingBox_RE.findall(data) if boundingBox: # rudely assume that there is only one EPS level bounding box # (the spec says that it should be that way) boundingBox = [ int(i.split('.')[0]) # FL writes floats in the bounding box for i in boundingBox[0].split(' ') ] # the EPS does not have a bounding box # or the EPS has a stated box of (0, 0, 0, 0) # (which AI seems to do for open paths!) # so, we get the bounds from a points array if not boundingBox or boundingBox == [0, 0, 0, 0]: points = [] for contour in contours: for tp, pts in contour: points.extend(pts) boundingBox = calcBounds(points) ## ## determine if the outlines need to be transformed ## and set up the transformation pen. transform = _getRectTransform(fitInside, boundingBox, fixedScale) transformPen = TransformPen(pen, transform) ## ## finally, draw the points for contour in contours: haveClosedPath = False if len(contour) > 1: # filter out overlapping points at the # start and the end of the contour start = contour[0] end = contour[-1] if end[0] == 'line': startPoints = start[1] endPoints = end[1] if start[0] == end[0]: contour = contour[:-1] haveClosedPath = True for tp, pts in contour: if tp == 'move': transformPen.moveTo(pts[0]) elif tp == 'line': transformPen.lineTo(pts[0]) elif tp == 'curve': pt1, pt2, pt3 = pts transformPen.curveTo(pt1, pt2, pt3) transformPen.closePath() # XXX #if haveClosedPath: # transformPen.closePath() #else: # transformPen.endPath() return True
def drawAICBOutlines(data, pen, fitInside=(None, None, None, None), fixedScale=None): """ Draw outline data from an eps. Returns True if the data was drawn, False if not. data = the EPS data (string) pen = a drawing pen fitInside = the maximum size that the outline can be drawn into. the function will transform the eps outlines to fit within this box. if you don't want to transform the data, send it a box of (None, None, None, None). it is also possible to transform based on only horizontal OR vertical parameters. Simply send a box formatted like: (None, -250, None, 750) to base the transform on vertical dimensions or like: (-1000, None, 1000, None) to base the transform on horizontal dimensions. fixedScale = a set scale factor for transforming the outline. If the resulting scaled outline is larger than the fit rect, the outline will be centered on those parameters. """ from fontTools.pens.transformPen import TransformPen from fontTools.misc.arrayTools import calcBounds data = '\n'.join(data.splitlines()) ## ## get the point data # FL follows the EPSF3.0 spec, but AI seems # to be using a different spec. AI puts the outline data # in layers. we can get around this by iterating over all lines # in the data and drawing points as we find them. contours = [] previousOnCurve = None for line in data.splitlines(): movetoMatch = moveto_RE.match(line) if movetoMatch: contours.append([]) x = float(movetoMatch.group(1)) y = float(movetoMatch.group(2)) contours[-1].append(('move', [(x, y)])) previousOnCurve = (x, y) continue linetoMatch = lineto_RE.match(line) if linetoMatch: x = float(linetoMatch.group(1)) y = float(linetoMatch.group(2)) contours[-1].append(('line', [(x, y)])) previousOnCurve = (x, y) continue startCurveToMatch = startCurveTo_RE.match(line) if startCurveToMatch: x1 = float(startCurveToMatch.group(1)) y1 = float(startCurveToMatch.group(2)) x2 = float(startCurveToMatch.group(3)) y2 = float(startCurveToMatch.group(4)) contours[-1].append( ('curve', [previousOnCurve, (x1, y1), (x2, y2)])) previousOnCurve = (x2, y2) continue endCurveToMatch = endCurveTo_RE.match(line) if endCurveToMatch: x1 = float(endCurveToMatch.group(1)) y1 = float(endCurveToMatch.group(2)) x2 = float(endCurveToMatch.group(3)) y2 = float(endCurveToMatch.group(4)) contours[-1].append(('curve', [(x1, y1), (x2, y2), (x2, y2)])) previousOnCurve = (x2, y2) continue curvetoMatch = curveto_RE.match(line) if curvetoMatch: x1 = float(curvetoMatch.group(1)) y1 = float(curvetoMatch.group(2)) x2 = float(curvetoMatch.group(3)) y2 = float(curvetoMatch.group(4)) x3 = float(curvetoMatch.group(5)) y3 = float(curvetoMatch.group(6)) contours[-1].append(('curve', [(x1, y1), (x2, y2), (x3, y3)])) previousOnCurve = (x3, y3) continue # no outline data. give up. if not contours: return False ## get the bounding box boundingBox = boundingBox_RE.findall(data) if boundingBox: # rudely assume that there is only one EPS level bounding box # (the spec says that it should be that way) boundingBox = [ int(i.split('.')[0]) # FL writes floats in the bounding box for i in boundingBox[0].split(' ') ] # the EPS does not have a bounding box # or the EPS has a stated box of (0, 0, 0, 0) # (which AI seems to do for open paths!) # so, we get the bounds from a points array if not boundingBox or boundingBox == [0, 0, 0, 0]: points = [] for contour in contours: for tp, pts in contour: points.extend(pts) boundingBox = calcBounds(points) ## ## determine if the outlines need to be transformed ## and set up the transformation pen. transform = _getRectTransform(fitInside, boundingBox, fixedScale) transformPen = TransformPen(pen, transform) ## ## finally, draw the points for contour in contours: haveClosedPath = False if len(contour) > 1: # filter out overlapping points at the # start and the end of the contour start = contour[0] end = contour[-1] if end[0] == 'line': startPoints = start[1] endPoints = end[1] if start[0] == end[0]: contour = contour[:-1] haveClosedPath = True for tp, pts in contour: if tp == 'move': transformPen.moveTo(pts[0]) elif tp == 'line': transformPen.lineTo(pts[0]) elif tp == 'curve': pt1, pt2, pt3 = pts transformPen.curveTo(pt1, pt2, pt3) transformPen.closePath() # XXX #if haveClosedPath: # transformPen.closePath() #else: # transformPen.endPath() return True