def __init__(self,width=100.0,height=100.0,*args,**kw): Drawing.__init__(self,width,height,*args,**kw) self.transform = (1,0,0,1,0,0) v0=self._nn(Group()) v0.transform = (1,0,0,-1,0,100) v0.add(Path(points=[30,1,70,1,99,30,99,70,70,99,30,99,1,70,1,30],operators=[0,1,1,1,1,1,1,1,3],isClipPath=0,autoclose='svg',fillMode=1,strokeDashArray=None,strokeWidth=1,strokeMiterLimit=0,strokeOpacity=None,strokeLineJoin=0,fillOpacity=1,strokeColor=Color(0,0,0,1),strokeLineCap=0,fillColor=Color(0,0,0,1))) v0.add(Path(points=[31,3,69,3,97,31,97,69,69,97,31,97,3,69,3,31],operators=[0,1,1,1,1,1,1,1,3],isClipPath=0,autoclose='svg',fillMode=1,strokeDashArray=None,strokeWidth=1,strokeMiterLimit=0,strokeOpacity=None,strokeLineJoin=0,fillOpacity=1,strokeColor=None,strokeLineCap=0,fillColor=Color(.666667,.133333,.2,1))) v1=v0._nn(Group()) v1.transform = (1,0,0,-1,0,136) v1.add(String(50,68,u'410',textAnchor=u'middle',fontName='Helvetica',fontSize=48,fillColor=Color(1,1,1,1)))
def __init__(self, width=100.0, height=100.0, autoclose='', *args, **kw): Drawing.__init__(self, width, height, *args, **kw) self.transform = (1, 0, 0, 1, 0, 0) v0 = self._nn(Group()) v0.transform = (1, 0, 0, -1, 0, 100) v1 = v0._nn(Group()) v1.transform = (1, 0, 0, -1, 0, 100) v1.add( Path(points=[ 10, 10, 10, 90, 20, 90, 20, 10, 30, 10, 30, 90, 40, 90, 40, 10, 50, 10, 50, 90, 60, 90, 60, 10, 70, 10, 70, 90, 80, 90, 80, 10 ], operators=[ 0, 1, 1, 1, 3, 0, 1, 1, 1, 0, 1, 1, 1, 3, 0, 1, 1, 1 ], isClipPath=0, autoclose=autoclose, fillMode=1, strokeDashArray=None, strokeWidth=2, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillOpacity=1, strokeColor=Color(1, 0, 0, 1), strokeLineCap=0, fillColor=Color(0, 0, 1, 1)))
def generate_pic(glyphname, font: TTFont, size=120, scale=0.1): """ 生成图片 -> 预处理 -> 保存到本地 Args: glyphname: font: file_suffix: size: scale: Returns: """ gs = font.getGlyphSet() pen = ReportLabPen(gs, Path(fillColor=colors.black, strokeWidth=1)) g = gs[glyphname] g.draw(pen) w, h = size, size # Everything is wrapped in a group to allow transformations. g = Group(pen.path) # g.translate(10, 20) g.scale(scale, scale) d = Drawing(w, h) d.add(g) return renderPM.drawToPIL(d)
def img_save(): img_path = PATH.rsplit('.', 1)[0] font = TTFont( PATH) # it would work just as well with fontTools.t1Lib.T1Font glyf = font['glyf'] if not os.path.exists(img_path): os.makedirs(img_path) for glyphName in glyf.keys(): gs = font.getGlyphSet() pen = ReportLabPen(gs, Path(fillColor=colors.black, strokeWidth=1)) g = gs[glyphName] g.draw(pen) # 调整图片大小 w, h = 800, 800 g = Group(pen.path) g.translate(10, 200) g.scale(0.3, 0.3) d = Drawing(w, h) d.add(g) image = renderPM.drawToPIL(d) little_image = image.resize((180, 180)) fromImage = Image.new('RGBA', (360, 360), color=(255, 255, 255)) fromImage.paste(little_image, (0, 0)) # fromImage.show() glyphName = glyphName.replace('uni', '&#x') imageFile = img_path + "/%s.png" % glyphName fromImage.save(imageFile) break
def ttf_to_image(self): """ 将ttf字体文件的字体绘制在Image对象上 :return: """ glyphset = self.font.getGlyphSet() size = (BASE_BACKGOUND_WIDTH * FONT_NUMS_PER_LINE, ceil(len(self.glyphnames) / FONT_NUMS_PER_LINE) * BASE_BACKGOUND_HEIGHT) # 背景图片尺寸 image = Image.new("RGB", size=size, color=(255, 255, 255)) # 初始化背景图片 name_list, image_dict = [], {} for index, glyphname in enumerate(self.glyphnames): if glyphname[0] in ['.', 'g'] or glyphname in self.ignore_names: # 跳过'.notdef', '.null' continue g = glyphset[glyphname] pen = ReportLabPen(self.glyphnames, Path(fillColor=colors.black, strokeWidth=1)) g.draw(pen) # w, h = g.width, g.width w, h = g.width if g.width > 1000 else 1000, g.width if g.width > 1000 else 1000 g = Group(pen.path) g.translate(0, 200) d = Drawing(w, h) d.add(g) im = renderPM.drawToPIL(d, dpi=72).resize((FONT_WIDTH, FONT_HEIGHT)) box = ( (index % FONT_NUMS_PER_LINE) * BASE_BACKGOUND_WIDTH, (index // FONT_NUMS_PER_LINE) * BASE_BACKGOUND_HEIGHT) image.paste(im, box=box) name_list.append(glyphname) image_dict[glyphname] = im return image, name_list, image_dict
def getProperties(self, *args, **kwargs): # __getattribute__ wouldn't suit, as RL is directly accessing self.__dict__ props = Path.getProperties(self, *args, **kwargs) if 'strokeWidth' in props: props['strokeWidth'] = 0 if 'strokeColor' in props: props['strokeColor'] = None return props
def pdfpath(pdf='', **kwds): if pdf: pdf = pdf.strip() if pdf: p = definePath(pathSegs=list(_getSegs(pdf.split())), **kwds) else: p = Path(**kwds) return p
def test_stroke(self): converter = svglib.Svg2RlgShapeConverter(None) node = etree.XML('<path d="m0,6.5h27m0,5H0" stroke="#FFF" stroke-opacity="0.5"/>') path = Path() converter.applyStyleOnShape(path, node) assert path.strokeColor == colors.white assert path.strokeOpacity == 0.5 assert path.strokeWidth == 1
def getProperties(self, *args, **kwargs): # __getattribute__ wouldn't suit, as RL is directly accessing self.__dict__ props = Path.getProperties(self, *args, **kwargs) if 'strokeWidth' in props: props['strokeWidth'] = 0 if 'strokeColor' in props: props['strokeColor'] = None return props
def one_to_image(self, glyph_name): glyphset = self.font.getGlyphSet() try: glyph = glyphset[glyph_name] except KeyError as e: raise KeyError("{} dont't in {}".format(glyph_name, self.font_file_name)) pen = ReportLabPen(self.glyphnames, Path(fillColor=colors.black, strokeWidth=1)) glyph.draw(pen) w, h = glyph.width if glyph.width > 1000 else 1000, glyph.width if glyph.width > 1000 else 1000 d = Drawing(w, h) g = Group(pen.path) g.translate(0, 150) d.add(g) im = renderPM.drawToPIL(d, dpi=72).resize((FONT_WIDTH, FONT_HEIGHT)) return im
def draw_one(self, unicode, font_io): ttf_font = TTFont(font_io) glyphSet = ttf_font.getGlyphSet() if unicode not in glyphSet: return None glyph = glyphSet[unicode] pen = reportLabPen.ReportLabPen( glyphSet, Path(fillColor=colors.black, strokeWidth=1)) glyph.draw(pen) w, h = glyph.width, glyph._glyph.yMax - glyph._glyph.yMin yOffset = -glyph._glyph.yMin * \ self.font_scale + h * (1 - self.font_scale) / 2 glyph = Group(pen.path) glyph.translate(w * (1 - self.font_scale) / 2, yOffset) glyph.scale(self.font_scale, self.font_scale) draw = Drawing(w, h) draw.add(glyph) PIL_image = renderPM.drawToPIL(draw) return PIL_image
def ttfToImage(fontName, imagePath, fmt="png"): font = TTFont(fontName) gs = font.getGlyphSet() glyphNames = font.getGlyphNames() for i in glyphNames: if i[0] == '.': #Ìø¹ý'.notdef', '.null' continue g = gs[i] pen = ReportLabPen(gs, Path(fillColor=colors.red, strokeWidth=5)) g.draw(pen) w, h = g.width, g.width g = Group(pen.path) g.translate(0, 200) d = Drawing(w, h) d.add(g) imageFile = imagePath + "/" + i + ".png" renderPM.drawToFile(d, imageFile, fmt) print(i)
def _draw(self): """ :param font_path: 下载的web 字体所在目录 :param image_path: 转换为image后所在目录 :return:返回font 对应的编码列表 """ import os import shutil shutil.rmtree(os.path.join(os.path.abspath('.'), "web_font", "image")) # 能删除该文件夹和文件夹下所有文件 os.mkdir(os.path.join(os.path.abspath('.'), "web_font", "image")) from fontTools.ttLib import TTFont from reportlab.lib import colors font = TTFont( os.path.join(os.path.abspath('.'), "web_font", "stonefont.woff") ) # it would work just as well with fontTools.t1Lib.T1Font gs = font.getGlyphSet() w, h = 40, 40 keys = gs.keys()[2:] for glyphName in keys: pen = FontPen(gs, Path(fillColor=colors.red, strokeWidth=0.01)) imageFile = "%s.png" % glyphName g = gs[glyphName] g.draw(pen) from reportlab.graphics import renderPM from reportlab.graphics.shapes import Group, Drawing g = Group(pen.path) g.translate(10, 13) g.scale(0.02, 0.02) d = Drawing(w, h) d.add(g) renderPM.drawToFile(d, os.path.join(os.path.abspath('.'), "web_font", "image", imageFile), fmt="PNG", dpi=100) return keys
def ttfToImage(fontName, imagePath, fmt="png"): font = TTFont(fontName) gs = font.getGlyphSet() glyphNames = font.getGlyphNames() m_dict = font.getBestCmap() unicode_list = [] gs_key=[] for key, value in m_dict.items(): unicode_list.append(key) gs_key.append(value) char_list = [chr(ch_unicode) for ch_unicode in unicode_list] #2500-29000 FZSONG_ZhongHuaSongPlane00_2021120120211201171438.ttf # 275 FZSONG_ZhongHuaSongPlane02_2021120120211201171459.ttf for i in range(len(char_list)): if fontName=='FZSONG_ZhongHuaSongPlane00_2021120120211201171438.ttf' and (i<2500 or i>29000): continue if fontName=='FZSONG_ZhongHuaSongPlane02_2021120120211201171459.ttf' and (i<275 or i>100000000): continue thechr=char_list[i] print(thechr) gs_ind=gs_key[i] if gs_ind[0] == '.': # 跳过'.notdef', '.null' continue g = gs[gs_ind] pen = ReportLabPen(gs, Path(fillColor=colors.black, strokeWidth=5)) g.draw(pen) w, h = g.width, g.width # w = 4048 # h = 4048 g = Group(pen.path) g.translate(0, 170) d = Drawing(w, h) d.add(g) imageFile = imagePath + "/" + thechr + ".png" renderPM.drawToFile(d, imageFile, fmt)
def draw_all(self, font_io): ttf_font = TTFont(font_io) glyphSet = ttf_font.getGlyphSet() font_image_dict = {} for glyphName in glyphSet.keys(): if (not glyphName.startswith('uni')): continue pen = reportLabPen.ReportLabPen( glyphSet, Path(fillColor=colors.black, strokeWidth=1)) glyph = glyphSet[glyphName] glyph.draw(pen) w, h = glyph.width, glyph._glyph.yMax - glyph._glyph.yMin yOffset = -glyph._glyph.yMin * \ self.font_scale + h * (1 - self.font_scale) / 2 glyph = Group(pen.path) glyph.translate(w * (1 - self.font_scale) / 2, yOffset) glyph.scale(self.font_scale, self.font_scale) draw = Drawing(w, h) draw.add(glyph) PIL_image = renderPM.drawToPIL(draw) font_image_dict[glyphName] = PIL_image return font_image_dict
def draw(self, dx=5, dy=300, auto_width=500, auto_height=500): """ 绘图操作 :param dx: 图片绘图位置 :param dy: 图片绘图位置 :param auto_width: 自适应图片宽度(调节字体) :param auto_height: 自适应图片高度(调节字体) :return: """ def reverse_dict(data: dict): out = {} for k, v in data.items(): out[str(v)] = str(k) return out font = TTFont(self.fontName) img_dict = font['cmap'].tables[2].ttFont.tables['cmap'].tables[1].cmap img_dict = reverse_dict(img_dict) gs = font.getGlyphSet() glyphNames = font.getGlyphNames() for i in glyphNames: name = self.key(img_dict.get(i)) if name == None: continue g = gs[i] pen = ReportLabPen(gs, Path(fillColor=colors.black, strokeWidth=10)) g.draw(pen) w, h = g.width, g.width g = Group(pen.path) g.translate(dx, dy) d = Drawing(w + auto_width, h + auto_height) d.add(g) imageFile = self.imagePath + "/" + str(name) + "." + self.fmt renderPM.drawToFile(d, imageFile, self.fmt)
def convertPath(self, node): d = node.getAttribute('d') if not d: return None normPath = normalise_svg_path(d) path = Path() points = path.points # Track subpaths needing to be closed later unclosed_subpath_pointers = [] subpath_start = [] lastop = '' for i in range(0, len(normPath), 2): op, nums = normPath[i:i+2] if op in ('m', 'M') and i > 0 and path.operators[-1] != _CLOSEPATH: unclosed_subpath_pointers.append(len(path.operators)) # moveto absolute if op == 'M': path.moveTo(*nums) subpath_start = points[-2:] # lineto absolute elif op == 'L': path.lineTo(*nums) # moveto relative elif op == 'm': if len(points) >= 2: if lastop in ('Z', 'z'): starting_point = subpath_start else: starting_point = points[-2:] xn, yn = starting_point[0] + nums[0], starting_point[1] + nums[1] path.moveTo(xn, yn) else: path.moveTo(*nums) subpath_start = points[-2:] # lineto relative elif op == 'l': xn, yn = points[-2] + nums[0], points[-1] + nums[1] path.lineTo(xn, yn) # horizontal/vertical line absolute elif op == 'H': path.lineTo(nums[0], points[-1]) elif op == 'V': path.lineTo(points[-2], nums[0]) # horizontal/vertical line relative elif op == 'h': path.lineTo(points[-2] + nums[0], points[-1]) elif op == 'v': path.lineTo(points[-2], points[-1] + nums[0]) # cubic bezier, absolute elif op == 'C': path.curveTo(*nums) elif op == 'S': x2, y2, xn, yn = nums if len(points) < 4 or lastop not in {'c', 'C', 's', 'S'}: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) path.curveTo(xi, yi, x2, y2, xn, yn) # cubic bezier, relative elif op == 'c': xp, yp = points[-2:] x1, y1, x2, y2, xn, yn = nums path.curveTo(xp + x1, yp + y1, xp + x2, yp + y2, xp + xn, yp + yn) elif op == 's': x2, y2, xn, yn = nums if len(points) < 4 or lastop not in {'c', 'C', 's', 'S'}: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) path.curveTo(xi, yi, x0 + x2, y0 + y2, x0 + xn, y0 + yn) # quadratic bezier, absolute elif op == 'Q': x0, y0 = points[-2:] x1, y1, xn, yn = nums (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (x1, y1), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) elif op == 'T': if len(points) < 4: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) xn, yn = nums (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (xi, yi), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) # quadratic bezier, relative elif op == 'q': x0, y0 = points[-2:] x1, y1, xn, yn = nums x1, y1, xn, yn = x0 + x1, y0 + y1, x0 + xn, y0 + yn (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (x1, y1), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) elif op == 't': if len(points) < 4: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] x0, y0 = points[-2:] xn, yn = nums xn, yn = x0 + xn, y0 + yn xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (xi, yi), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) # elliptical arc elif op in ('A', 'a'): rx, ry, phi, fA, fS, x2, y2 = nums x1, y1 = points[-2:] if op == 'a': x2 += x1 y2 += y1 if abs(rx) <= 1e-10 or abs(ry) <= 1e-10: path.lineTo(x2, y2) else: bp = bezier_arc_from_end_points(x1, y1, rx, ry, phi, fA, fS, x2, y2) for _, _, x1, y1, x2, y2, xn, yn in bp: path.curveTo(x1, y1, x2, y2, xn, yn) # close path elif op in ('Z', 'z'): path.closePath() else: logger.debug("Suspicious path operator: %s" % op) lastop = op gr = Group() self.applyStyleOnShape(path, node) if path.operators[-1] != _CLOSEPATH: unclosed_subpath_pointers.append(len(path.operators)) if unclosed_subpath_pointers and path.fillColor is not None: # ReportLab doesn't fill unclosed paths, so we are creating a copy # of the path with all subpaths closed, but without stroke. # https://bitbucket.org/rptlab/reportlab/issues/99/ closed_path = NoStrokePath(copy_from=path) for pointer in reversed(unclosed_subpath_pointers): closed_path.operators.insert(pointer, _CLOSEPATH) gr.add(closed_path) path.fillColor = None gr.add(path) return gr
def getProperties(self, *args, **kwargs): props = Path.getProperties(self, *args, **kwargs) if 'fillColor' in props: props['fillColor'] = None return props
def __init__(self, *args, **kwargs): copy_from = kwargs.pop('copy_from', None) Path.__init__(self, *args, **kwargs) if copy_from: self.__dict__.update(copy.deepcopy(copy_from.__dict__)) self.isClipPath = 1
def __init__(self, ref=None): Path.__init__(self) self._ref = ref
def __init__(self, *args, **kwargs): copy_from = kwargs.pop('copy_from', None) Path.__init__(self, *args, **kwargs) # we're old-style class on PY2 if copy_from: self.__dict__.update(copy.deepcopy(copy_from.__dict__))
def getProperties(self, *args, **kwargs): props = Path.getProperties(self, *args, **kwargs) if 'fillColor' in props: props['fillColor'] = None return props
from fontemon_blender_addon.fontTools.ttLib import TTFont from reportlab.lib import colors path = sys.argv[1] glyphName = sys.argv[2] if (len(sys.argv) > 3): imageFile = sys.argv[3] else: imageFile = "%s.png" % glyphName font = TTFont( path ) # it would work just as well with fontemon_blender_addon.fontTools.t1Lib.T1Font gs = font.getGlyphSet() pen = ReportLabPen(gs, Path(fillColor=colors.red, strokeWidth=5)) g = gs[glyphName] g.draw(pen) w, h = g.width, 1000 from reportlab.graphics import renderPM from reportlab.graphics.shapes import Group, Drawing, scale # Everything is wrapped in a group to allow transformations. g = Group(pen.path) g.translate(0, 200) g.scale(0.3, 0.3) d = Drawing(w, h) d.add(g)
def __init__(self, width=600.0, height=200.0, fillMode='even-odd', *args, **kw): Drawing.__init__(self, width, height, *args, **kw) self.transform = (1, 0, 0, 1, 0, 0) v0 = self._nn(Group()) v0.transform = (1, 0, 0, -1, 0, 200) v0.add( Rect(1, 1, 599, 199, rx=0, ry=0, strokeDashArray=None, strokeWidth=2, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillOpacity=1, strokeColor=Color(0, 0, 1, 1), strokeLineCap=0, fillColor=None)) v1 = v0._nn(Group()) v1.transform = (.5, 0, 0, .5, 0, 0) v1.add( Path(points=[250, 75, 323, 301, 131, 161, 369, 161, 177, 301], operators=[0, 1, 1, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=fillMode, strokeDashArray=None, strokeWidth=3, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillOpacity=1, strokeColor=Color(0, 0, 0, 1), strokeLineCap=0, fillColor=Color(1, 0, 0, 1))) v2 = v1._nn(Group()) v2.transform = (.309017, .951057, -0.951057, .309017, 306.21, 249) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (-0.809017, -0.587785, .587785, -0.809017, 175.16, 193.2) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (1, 0, 0, 1, 314.26, 161) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (-0.809017, .587785, -0.587785, -0.809017, 221.16, 268.8) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (.309017, -0.951057, .951057, .309017, 233.21, 126.98) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v1.add( Path(points=[ 600, 81, 659.0945, 81, 707, 128.9055, 707, 188, 707, 247.0945, 659.0945, 295, 600, 295, 540.9055, 295, 493, 247.0945, 493, 188, 493, 128.9055, 540.9055, 81, 600, 81, 600, 139, 627.062, 139, 649, 160.938, 649, 188, 649, 215.062, 627.062, 237, 600, 237, 572.938, 237, 551, 215.062, 551, 188, 551, 160.938, 572.938, 139, 600, 139 ], operators=[0, 2, 2, 2, 2, 3, 0, 2, 2, 2, 2, 3], isClipPath=0, autoclose='svg', fillMode=fillMode, strokeDashArray=None, strokeWidth=3, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillOpacity=1, strokeColor=Color(0, 0, 0, 1), strokeLineCap=0, fillColor=Color(1, 0, 0, 1))) v2 = v1._nn(Group()) v2.transform = (0, 1, -1, 0, 707, 188) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (-0.866025, -0.5, .5, -0.866025, 546.5, 280.6647) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (.866025, -0.5, .5, .866025, 546.5, 95.33528) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (-0.866025, .5, -0.5, -0.866025, 624.5, 230.4352) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (0, -1, 1, 0, 551, 188) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (.866025, .5, -0.5, .866025, 624.5, 145.5648) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v1.add( Path(points=[ 950, 81, 1009.094, 81, 1057, 128.9055, 1057, 188, 1057, 247.0945, 1009.094, 295, 950, 295, 890.9055, 295, 843, 247.0945, 843, 188, 843, 128.9055, 890.9055, 81, 950, 81, 950, 139, 922.938, 139, 901, 160.938, 901, 188, 901, 215.062, 922.938, 237, 950, 237, 977.062, 237, 999, 215.062, 999, 188, 999, 160.938, 977.062, 139, 950, 139 ], operators=[0, 2, 2, 2, 2, 3, 0, 2, 2, 2, 2, 3], isClipPath=0, autoclose='svg', fillMode=fillMode, strokeDashArray=None, strokeWidth=3, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillOpacity=1, strokeColor=Color(0, 0, 0, 1), strokeLineCap=0, fillColor=Color(1, 0, 0, 1))) v2 = v1._nn(Group()) v2.transform = (0, 1, -1, 0, 1057, 188) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (-0.866025, -0.5, .5, -0.866025, 896.5, 280.6647) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (.866025, -0.5, .5, .866025, 896.5, 95.33528) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (.866025, -0.5, .5, .866025, 974.5, 230.4352) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (0, 1, -1, 0, 901, 188) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1)) v2 = v1._nn(Group()) v2.transform = (-0.866025, -0.5, .5, -0.866025, 974.5, 145.5648) v2.add( Path(points=[16, 0, -8, 9, -8, -9], operators=[0, 1, 1, 3], isClipPath=0, autoclose='svg', fillMode=1, strokeDashArray=None, strokeWidth=1, strokeMiterLimit=0, strokeOpacity=None, strokeLineJoin=0, fillColor=Color(0, 0, 0, 1), strokeColor=None, strokeLineCap=0, fillOpacity=1))
def render(self, node, parent=None): if parent is None: parent = self.mainGroup # ignore if display = none display = node.get('display') if display == "none": return if node.tag == self.SVG_ROOT: self.level += 1 if not self.drawing is None: raise SVGError('drawing already created!') self.root = node # default styles style = { 'color': 'none', 'fill': 'none', 'stroke': 'none', 'font-family': 'Helvetica', 'font-size': '12' } self.styles[self.level] = style # iterate children for child in node: self.render(child, self.mainGroup) # create drawing width = node.get('width', '100%') height = node.get('height', '100%') if node.get("viewBox"): try: minx, miny, width, height = node.get("viewBox").split() except ValueError: raise SVGError("viewBox values not valid") if width.endswith('%') and height.endswith('%'): # handle relative size wscale = parseLength(width) / 100. hscale = parseLength(height) / 100. xL, yL, xH, yH = self.mainGroup.getBounds() self.drawing = Drawing(xH * wscale + xL, yH * hscale + yL) else: self.drawing = Drawing(parseLength(width), parseLength(height)) height = self.drawing.height self.mainGroup.scale(1, -1) self.mainGroup.translate(0, -height) self.drawing.add(self.mainGroup) self.level -= 1 return self.drawing elif node.tag in (self.SVG_G, self.SVG_A): self.level += 1 # set this levels style style = self.styles[self.level - 1].copy() style = self.nodeStyle(node, style) self.styles[self.level] = style group = Group() # iterate children for child in node: self.render(child, group) parent.add(group) transforms = node.get('transform') if transforms: for op in parseTransform.iterparse(transforms): self.applyTransformOnGroup(group, op) self.level -= 1 elif node.tag == self.SVG_USE: self.level += 1 # set this levels style style = self.styles[self.level - 1].copy() style = self.nodeStyle(node, style) self.styles[self.level] = style group = Group() # link id link_id = node.get(self.LINK).lstrip('#') # find linked node in defs or symbol section target = None for defs in self.root.getiterator(self.SVG_DEFS): for element in defs: if element.get('id') == link_id: target = element break if target is None: for defs in self.root.getiterator(self.SVG_SYMBOL): for element in defs: if element.get('id') == link_id: target = element break if target is None: msg = "Could not find use node '%s'" % link_id raise SVGError(msg) self.render(target, group) parent.add(group) # apply transform transforms = node.get('transform') if transforms: for op in parseTransform.iterparse(transforms): self.applyTransformOnGroup(group, op) # apply 'x' and 'y' attribute as translation of defs object if node.get('x') or node.get('y'): dx = parseLength(node.get('x', '0')) dy = parseLength(node.get('y', '0')) self.applyTransformOnGroup(group, ('translate', (dx, dy))) self.level -= 1 elif node.tag == self.SVG_LINE: # get coordinates x1 = parseLength(node.get('x1', '0')) y1 = parseLength(node.get('y1', '0')) x2 = parseLength(node.get('x2', '0')) y2 = parseLength(node.get('y2', '0')) shape = Line(x1, y1, x2, y2) self.addShape(parent, node, shape) elif node.tag == self.SVG_RECT: # get coordinates x = parseLength(node.get('x', '0')) y = parseLength(node.get('y', '0')) width = parseLength(node.get('width')) height = parseLength(node.get('height')) rx = parseLength(node.get('rx', '0')) ry = parseLength(node.get('ry', '0')) shape = Rect(x, y, width, height, rx=rx, ry=ry) self.addShape(parent, node, shape) elif node.tag == self.SVG_CIRCLE: cx = parseLength(node.get('cx', '0')) cy = parseLength(node.get('cy', '0')) r = parseLength(node.get('r')) if r > 0.: shape = Circle(cx, cy, r) self.addShape(parent, node, shape) elif node.tag == self.SVG_ELLIPSE: cx = parseLength(node.get('cx', '0')) cy = parseLength(node.get('cy', '0')) rx = parseLength(node.get('rx')) ry = parseLength(node.get('ry')) if rx > 0. and ry > 0.: shape = Ellipse(cx, cy, rx, ry) self.addShape(parent, node, shape) elif node.tag == self.SVG_POLYLINE: # convert points points = node.get('points').strip() if len(points) == 0: return points = list(map(parseLength, re.split('[ ,]+', points))) # Need to use two shapes, because standard RLG polylines # do not support filling... group = Group() shape = Polygon(points) self.applyStyleToShape(shape, node) shape.strokeColor = None group.add(shape) shape = PolyLine(points) self.applyStyleToShape(shape, node) group.add(shape) self.addShape(parent, node, group) elif node.tag == self.SVG_POLYGON: # convert points points = node.get('points').strip() if len(points) == 0: return points = list(map(parseLength, re.split('[ ,]+', points))) shape = Polygon(points) self.addShape(parent, node, shape) elif node.tag == self.SVG_IMAGE: x = parseLength(node.get('x', '0')) y = parseLength(node.get('y', '0')) width = parseLength(node.get('width', '0')) height = parseLength(node.get('height', '0')) # link id link_id = node.get(self.LINK) filename = os.path.join(os.path.dirname(self.filename), link_id) shape = Image(x, y, width, height, filename) self.addShape(parent, node, shape) elif node.tag == self.SVG_TEXT: # Todo: # - rotation not handled # - baseshift not handled # - embedded span node not handled # def parsePos(node, subnode, name, default='0'): values = subnode.get(name) if values is None: if node is not None: values = node.get(name, default) else: values = default return list(map(parseLength, values.split())) def getPos(values, i, default=None): if i >= len(values): if default is None: return values[-1] else: return default else: return values[i] def handleText(node, subnode, text): # get position variables xs = parsePos(node, subnode, 'x') dxs = parsePos(node, subnode, 'dx') ys = parsePos(node, subnode, 'y') dys = parsePos(node, subnode, 'dy') if sum(map(len, (xs, ys, dxs, dys))) == 4: # single value shape = String(xs[0] + dxs[0], -ys[0] - dys[0], text) self.applyStyleToShape(shape, subnode) group.add(shape) else: # multiple values for i, c in enumerate(text): x = getPos(xs, i) dx = getPos(dxs, i, 0) y = getPos(ys, i) dy = getPos(dys, i, 0) shape = String(x + dx, -y - dy, c) self.applyStyleToShape(shape, subnode) group.add(shape) if node.text and node.text.strip(): group = Group() handleText(None, node, node.text.strip()) group.scale(1, -1) self.addShape(parent, node, group) if len(node) > 0: group = Group() self.level += 1 # set this levels style style = self.styles[self.level - 1].copy() nodestylestyle = self.nodeStyle(node, style) self.styles[self.level] = nodestylestyle for subnode in node: if subnode.tag == self.SVG_TSPAN: handleText(node, subnode, subnode.text.strip()) self.level -= 1 group.scale(1, -1) self.addShape(parent, node, group) elif node.tag == self.SVG_PATH: def convertQuadratic(Q0, Q1, Q2): C1 = (Q0[0] + 2. / 3 * (Q1[0] - Q0[0]), Q0[1] + 2. / 3 * (Q1[1] - Q0[1])) C2 = (C1[0] + 1. / 3 * (Q2[0] - Q0[0]), C1[1] + 1. / 3 * (Q2[1] - Q0[1])) C3 = Q2 return C1[0], C1[1], C2[0], C2[1], C3[0], C3[1] def prevCtrl(lastOp, lastArgs, currentX, currentY): # fetch last controll point if lastOp in 'CScsQqTt': x, y = lastArgs[-2] # mirror about current point return currentX + (currentX - x), currentY + (currentY - y) else: # defaults to current point return currentX, currentY # store sub paths in 'paths' list shape = Path() # keep track of current point and path start point startX, startY = 0., 0. currentX, currentY = 0., 0. # keep track of last operation lastOp = None lastArgs = None # avoid empty path data data = node.get('d') if data is None or len(data) == 0: return for op, args in parsePath.iterparse(data): if op == 'z' or op == 'Z': # close path or subpath shape.closePath() # next sub path starts at begining of current path currentX, currentY = startX, startY elif op == 'M': # moveto absolute if lastOp is not None and lastOp not in ('z', 'Z'): # close sub path shape.closePath() x, y = args[0] shape.moveTo(x, y) startX, startY = x, y # multiple moveto arge result in line for x, y in args[1:]: shape.lineTo(x, y) currentX, currentY = x, y elif op == 'm': if lastOp is not None and lastOp not in ('z', 'Z'): # close sub path shape.closePath() # moveto relative rx, ry = args[0] x, y = currentX + rx, currentY + ry shape.moveTo(x, y) startX, startY = x, y currentX, currentY = x, y # multiple moveto arge result in line for rx, ry in args[1:]: x, y = currentX + rx, currentY + ry shape.lineTo(x, y) currentX, currentY = x, y elif op == 'L': # lineto absolute for x, y in args: shape.lineTo(x, y) currentX, currentY = x, y elif op == 'l': # lineto relative for rx, ry in args: x, y = currentX + rx, currentY + ry shape.lineTo(x, y) currentX, currentY = x, y elif op == 'V': # vertical line absolute for y in args: shape.lineTo(currentX, y) currentY = y elif op == 'v': # vertical line relative for ry in args: y = currentY + ry shape.lineTo(currentX, y) currentY = y elif op == 'H': # horisontal line absolute for x in args: shape.lineTo(x, currentY) currentX = x elif op == 'h': # horisontal line relative for rx in args: x = currentX + rx shape.lineTo(x, currentY) currentX = x elif op == 'C': # cubic bezier absolute for p1, p2, p3 in zip(*([iter(args)] * 3)): shape.curveTo(*(p1 + p2 + p3)) currentX, currentY = p3 elif op == 'c': # cubic bezier relative for pnts in zip(*([iter(args)] * 3)): (x1, y1), (x2, y2), (x3, y3) = pnts pnts = tuple( (p[0] + currentX, p[1] + currentY) for p in pnts) shape.curveTo(*(pnts[0] + pnts[1] + pnts[2])) currentX, currentY = pnts[2] lastOp = op lastArgs = pnts continue elif op == 'S': # shorthand cubic bezier absolute for p2, p3 in zip(*([iter(args)] * 2)): x1, y1 = prevCtrl(lastOp, lastArgs, currentX, currentY) x2, y2 = p2 x3, y3 = p3 shape.curveTo(x1, y1, x2, y2, x3, y3) lastOp = op lastArgs = (x2, y2), (x3, y3) currentX, currentY = x3, y3 continue elif op == 's': # shorthand cubic bezier relative for p2, p3 in zip(*([iter(args)] * 2)): x1, y1 = prevCtrl(lastOp, lastArgs, currentX, currentY) x2, y2 = p2 x2, y2 = x2 + currentX, y2 + currentY x3, y3 = p3 x3, y3 = x3 + currentX, y3 + currentY shape.curveTo(x1, y1, x2, y2, x3, y3) currentX, currentY = x3, y3 lastOp = op lastArgs = (x1, y1), (x2, y2), (x3, y3) continue elif op == 'Q': # quadratic bezier absolute for p2, p3 in zip(*([iter(args)] * 2)): x1, y1 = currentX, currentY x2, y2 = p2 x3, y3 = p3 ctrls = convertQuadratic((x1, y1), (x2, y2), (x3, y3)) shape.curveTo(*ctrls) currentX, currentY = x3, y3 lastOp = op lastArgs = (x2, y2), (x3, y3) continue elif op == 'q': # quadratic bezier relative for p2, p3 in zip(*([iter(args)] * 2)): x1, y1 = currentX, currentY x2, y2 = p2 x2, y2 = x2 + currentX, y2 + currentY x3, y3 = p3 x3, y3 = x3 + currentX, y3 + currentY ctrls = convertQuadratic((x1, y1), (x2, y2), (x3, y3)) shape.curveTo(*ctrls) currentX, currentY = x3, y3 lastOp = op lastArgs = (x2, y2), (x3, y3) continue elif op == 'T': # shorthand quadratic bezier absolute for i in range(len(args)): x1, y1 = currentX, currentY x2, y2 = prevCtrl(lastOp, lastArgs, currentX, currentY) x3, y3 = args[i] ctrls = convertQuadratic((x1, y1), (x2, y2), (x3, y3)) shape.curveTo(*ctrls) currentX, currentY = x3, y3 lastOp = op lastArgs = (x2, y2), (x3, y3) continue elif op == 't': # shorthand quadratic bezier relative for i in range(len(args)): x1, y1 = currentX, currentY x2, y2 = prevCtrl(lastOp, lastArgs, currentX, currentY) x3, y3 = args[i] x3, y3 = x3 + currentX, y3 + currentY ctrls = convertQuadratic((x1, y1), (x2, y2), (x3, y3)) shape.curveTo(*ctrls) currentX, currentY = x3, y3 lastOp = op lastArgs = (x2, y2), (x3, y3) continue elif op == 'A' or op == 'a': # elliptic arc missing continue lastOp = op lastArgs = args # check if fill applies to path fill = None if node.get('fill'): # inline style fill = node.get('fill') else: # try local style if node.get('style'): style = parseStyle.parse(node.get('style')) if 'fill' in style: fill = style['fill'] # try global style if fill is None: style = self.styles[self.level] if 'fill' in style: fill = style['fill'] else: fill = 'none' # hack because RLG has no "semi-closed" paths... if lastOp == 'z' or lastOp == 'Z' or fill == 'none': self.addShape(parent, node, shape) else: group = Group() strokeshape = shape.copy() self.addShape(group, node, strokeshape, fill='none') shape.closePath() self.addShape(group, node, shape, stroke='none') self.addShape(parent, node, group) elif node.tag == self.SVG_TITLE or node.tag == self.SVG_DESC: # Skip non-graphics elements return
def __init__(self, glyphSet, path=None): BasePen.__init__(self, glyphSet) if path is None: from reportlab.graphics.shapes import Path path = Path() self.path = path
def __init__(self, *args, **kwargs): copy_from = kwargs.pop('copy_from', None) Path.__init__(self, *args, **kwargs) # we're old-style class on PY2 if copy_from: self.__dict__.update(copy.deepcopy(copy_from.__dict__))
def convertPath(self, node): d = node.getAttribute('d') normPath = normalise_svg_path(d) path = Path() points = path.points # Track subpaths needing to be closed later unclosed_subpath_pointers = [] subpath_start = [] lastop = '' for i in xrange(0, len(normPath), 2): op, nums = normPath[i:i+2] if op in ('m', 'M') and i > 0 and path.operators[-1] != _CLOSEPATH: unclosed_subpath_pointers.append(len(path.operators)) # moveto absolute if op == 'M': path.moveTo(*nums) subpath_start = points[-2:] # lineto absolute elif op == 'L': path.lineTo(*nums) # moveto relative elif op == 'm': if len(points) >= 2: if lastop in ('Z', 'z'): starting_point = subpath_start else: starting_point = points[-2:] xn, yn = starting_point[0] + nums[0], starting_point[1] + nums[1] path.moveTo(xn, yn) else: path.moveTo(*nums) subpath_start = points[-2:] # lineto relative elif op == 'l': xn, yn = points[-2] + nums[0], points[-1] + nums[1] path.lineTo(xn, yn) # horizontal/vertical line absolute elif op == 'H': path.lineTo(nums[0], points[-1]) elif op == 'V': path.lineTo(points[-2], nums[0]) # horizontal/vertical line relative elif op == 'h': path.lineTo(points[-2] + nums[0], points[-1]) elif op == 'v': path.lineTo(points[-2], points[-1] + nums[0]) # cubic bezier, absolute elif op == 'C': path.curveTo(*nums) elif op == 'S': x2, y2, xn, yn = nums if len(points) < 4 or lastop not in {'c', 'C', 's', 'S'}: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) path.curveTo(xi, yi, x2, y2, xn, yn) # cubic bezier, relative elif op == 'c': xp, yp = points[-2:] x1, y1, x2, y2, xn, yn = nums path.curveTo(xp + x1, yp + y1, xp + x2, yp + y2, xp + xn, yp + yn) elif op == 's': x2, y2, xn, yn = nums if len(points) < 4 or lastop not in {'c', 'C', 's', 'S'}: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) path.curveTo(xi, yi, x0 + x2, y0 + y2, x0 + xn, y0 + yn) # quadratic bezier, absolute elif op == 'Q': x0, y0 = points[-2:] x1, y1, xn, yn = nums (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (x1, y1), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) elif op == 'T': if len(points) < 4: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) xn, yn = nums (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (xi, yi), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) # quadratic bezier, relative elif op == 'q': x0, y0 = points[-2:] x1, y1, xn, yn = nums x1, y1, xn, yn = x0 + x1, y0 + y1, x0 + xn, y0 + yn (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (x1, y1), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) elif op == 't': if len(points) < 4: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] x0, y0 = points[-2:] xn, yn = nums xn, yn = x0 + xn, y0 + yn xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (xi, yi), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) # elliptical arc elif op in ('A', 'a'): rx, ry, phi, fA, fS, x2, y2 = nums x1, y1 = points[-2:] if op == 'a': x2 += x1 y2 += y1 if abs(rx) <= 1e-10 or abs(ry) <= 1e-10: path.lineTo(x2, y2) else: bp = bezier_arc_from_end_points(x1, y1, rx, ry, phi, fA, fS, x2, y2) for _, _, x1, y1, x2, y2, xn, yn in bp: path.curveTo(x1, y1, x2, y2, xn, yn) # close path elif op in ('Z', 'z'): path.closePath() else: logger.debug("Suspicious path operator: %s" % op) lastop = op gr = Group() self.applyStyleOnShape(path, node) if path.operators[-1] != _CLOSEPATH: unclosed_subpath_pointers.append(len(path.operators)) if unclosed_subpath_pointers and path.fillColor is not None: # ReportLab doesn't fill unclosed paths, so we are creating a copy # of the path with all subpaths closed, but without stroke. # https://bitbucket.org/rptlab/reportlab/issues/99/ closed_path = NoStrokePath(copy_from=path) for pointer in reversed(unclosed_subpath_pointers): closed_path.operators.insert(pointer, _CLOSEPATH) gr.add(closed_path) path.fillColor = None gr.add(path) return gr
def convertPath(self, node): d = node.getAttribute('d') if not d: return None normPath = normalise_svg_path(d) path = Path(autoclose='svg') points = path.points # Track subpaths needing to be closed later subpath_start = [] lastop = '' for i in xrange(0, len(normPath), 2): op, nums = normPath[i:i + 2] # moveto absolute if op == 'M': path.moveTo(*nums) subpath_start = points[-2:] # lineto absolute elif op == 'L': path.lineTo(*nums) # moveto relative elif op == 'm': if len(points) >= 2: if lastop in ('Z', 'z'): starting_point = subpath_start else: starting_point = points[-2:] xn, yn = starting_point[0] + nums[0], starting_point[ 1] + nums[1] path.moveTo(xn, yn) else: path.moveTo(*nums) subpath_start = points[-2:] # lineto relative elif op == 'l': xn, yn = points[-2] + nums[0], points[-1] + nums[1] path.lineTo(xn, yn) # horizontal/vertical line absolute elif op == 'H': path.lineTo(nums[0], points[-1]) elif op == 'V': path.lineTo(points[-2], nums[0]) # horizontal/vertical line relative elif op == 'h': path.lineTo(points[-2] + nums[0], points[-1]) elif op == 'v': path.lineTo(points[-2], points[-1] + nums[0]) # cubic bezier, absolute elif op == 'C': path.curveTo(*nums) elif op == 'S': x2, y2, xn, yn = nums if len(points) < 4 or lastop not in {'c', 'C', 's', 'S'}: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) path.curveTo(xi, yi, x2, y2, xn, yn) # cubic bezier, relative elif op == 'c': xp, yp = points[-2:] x1, y1, x2, y2, xn, yn = nums path.curveTo(xp + x1, yp + y1, xp + x2, yp + y2, xp + xn, yp + yn) elif op == 's': x2, y2, xn, yn = nums if len(points) < 4 or lastop not in {'c', 'C', 's', 'S'}: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) path.curveTo(xi, yi, x0 + x2, y0 + y2, x0 + xn, y0 + yn) # quadratic bezier, absolute elif op == 'Q': x0, y0 = points[-2:] x1, y1, xn, yn = nums (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (x1, y1), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) elif op == 'T': if len(points) < 4: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) xn, yn = nums (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (xi, yi), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) # quadratic bezier, relative elif op == 'q': x0, y0 = points[-2:] x1, y1, xn, yn = nums x1, y1, xn, yn = x0 + x1, y0 + y1, x0 + xn, y0 + yn (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (x1, y1), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) elif op == 't': if len(points) < 4: xp, yp, x0, y0 = points[-2:] * 2 else: xp, yp, x0, y0 = points[-4:] x0, y0 = points[-2:] xn, yn = nums xn, yn = x0 + xn, y0 + yn xi, yi = x0 + (x0 - xp), y0 + (y0 - yp) (x0, y0), (x1, y1), (x2, y2), (xn, yn) = \ convert_quadratic_to_cubic_path((x0, y0), (xi, yi), (xn, yn)) path.curveTo(x1, y1, x2, y2, xn, yn) # elliptical arc elif op in ('A', 'a'): rx, ry, phi, fA, fS, x2, y2 = nums x1, y1 = points[-2:] if op == 'a': x2 += x1 y2 += y1 if abs(rx) <= 1e-10 or abs(ry) <= 1e-10: path.lineTo(x2, y2) else: bp = bezier_arc_from_end_points(x1, y1, rx, ry, phi, fA, fS, x2, y2) for _, _, x1, y1, x2, y2, xn, yn in bp: path.curveTo(x1, y1, x2, y2, xn, yn) # close path elif op in ('Z', 'z'): path.closePath() else: logger.debug("Suspicious path operator: %s" % op) lastop = op gr = Group() self.applyStyleOnShape(path, node) gr.add(path) return gr
print(" (The file format will be PNG, regardless of the image file name supplied)") sys.exit(0) from fontTools.ttLib import TTFont from reportlab.lib import colors path = sys.argv[1] glyphName = sys.argv[2] if (len(sys.argv) > 3): imageFile = sys.argv[3] else: imageFile = "%s.png" % glyphName font = TTFont(path) # it would work just as well with fontTools.t1Lib.T1Font gs = font.getGlyphSet() pen = ReportLabPen(gs, Path(fillColor=colors.black, strokeWidth=0)) #pen = ReportLabPen(gs, Path(fillColor=colors.red, strokeWidth=5)) g = gs[glyphName] g.draw(pen) w, h = g.width, 1000 from reportlab.graphics import renderPM from reportlab.graphics.shapes import Group, Drawing, scale # Everything is wrapped in a group to allow transformations. g = Group(pen.path) g.translate(10, 10) #g.scale(0.9, 0.9) #g.scale(0.3, 0.3) g.scale(0.8, 0.8)
def draw(self): self.qr.make() g = Group() color = self.barFillColor border = self.barBorder width = self.barWidth height = self.barHeight x = self.x y = self.y g.add(SRect(x, y, width, height, fillColor=None)) path = Path(fillColor=colors.black, strokeColor=None) moduleCount = self.qr.getModuleCount() minwh = float(min(width, height)) boxsize = minwh / (moduleCount + border * 2) offsetX = (width - minwh) / 2 offsetY = (minwh - height) / 2 for r, row in enumerate(self.qr.modules): c = 0 for t, tt in itertools.groupby(row): isDark = t count = len(list(tt)) if isDark: x = (c + border) * boxsize y = (r + border + 1) * boxsize path.moveTo(offsetX + x, offsetY + height - y) path.lineTo(offsetX + x + count * boxsize, offsetY + height - y) path.lineTo(offsetX + x + count * boxsize, offsetY + height - y + boxsize) path.lineTo(offsetX + x, offsetY + height - y + boxsize) path.closePath() c += count g.add(path) return g
def __init__(self, glyphSet, path=None): BasePen.__init__(self, glyphSet) if path is None: path = Path() self.path = path
def __init__(self, *args, **kwargs): copy_from = kwargs.pop('copy_from', None) Path.__init__(self, *args, **kwargs) if copy_from: self.__dict__.update(copy.deepcopy(copy_from.__dict__)) self.isClipPath = 1