- Notifications
You must be signed in to change notification settings - Fork4
xxao/pero
Folders and files
Name | Name | Last commit message | Last commit date | |
---|---|---|---|---|
Repository files navigation
The main motivation behind thepero library is to provide unified API for multiple drawing backends likePyQt5,PyQt6,PySide2,PySide6,wxPython,PyCairo,PyMuPDF,Pythonista (and possibly more),which is easy to understand and use. Beside the common drawing capabilities, numerous pre-build glyphs are available,as well as an easy-to-use path, matrix transformations etc. Depending on available backend libraries, drawings can beviewed directly or exported into various image formats.
Ever since I discovered the wonderfuld3js JavaScript library, I wanted to have the same amazingconcept of dynamic properties within Python drawings. In fact, this has been the trigger to start working on theperolibrary. Finally, it is now available.
Please see theexamples folder or in-code documentation of classesand functions to learn more about thepero library capabilities.
Consider also checking a small derived library providing some basic plotting functionalities, like profiles, bars, piecharts and Venn diagrams, calledperrot.
importperoimg=pero.Image(width=200,height=200)img.line_cap=pero.ROUNDimg.line_join=pero.ROUND# fillimg.fill("w")# bodyimg.line_width=2img.line_color=pero.colors.Orange.darker(.1)img.fill_color=pero.colors.Orangeimg.draw_circle(100,100,75)# shadowimg.line_color=Noneimg.fill_color=pero.colors.White.darker(.1)img.draw_ellipse(100,185,70,10)# eyesimg.fill_color=pero.colors.Blackimg.draw_circle(70,85,15)img.draw_circle(130,85,15)# eyebrowsimg.line_color=pero.colors.Blackimg.fill_color=Noneimg.line_width=3img.draw_arc(70,85,23,pero.rads(-100),pero.rads(-20))img.draw_arc(130,85,23,pero.rads(200),pero.rads(280))# mouthimg.line_width=5img.draw_arc(100,100,50,pero.rads(40),pero.rads(80))# highlightimg.line_color=pero.colors.Orange.lighter(.3)img.draw_arc(100,100,68,pero.rads(220),pero.rads(260))# hatpath=pero.Path(pero.WINDING)path.ellipse(100,27,40,10)path.ellipse(100,17,30,10)path.rect(85,17,30,10)mat=pero.Matrix().rotate(pero.rads(20),100,100)path.transform(mat)img.line_color=Noneimg.fill_color=pero.colors.Blackimg.draw_path(path)# show imageimg.show()
Thepero library is fully implemented in Python. No additional compiler is necessary. After downloading the sourcecode just run the following command from thepero folder:
$ python setup.py install
or simply use pip
$ pip install pero
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the impliedwarranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
Please note that thepero library is still in an alpha state. Any changes in its API may occur.
If you just want to draw an image using whatever the default backend is (for requested format), or show the imagedirectly (requiresPyQt5,PyQt6,PySide2,PySide6,wxPython orPythonista iOS App),just create animage and use it as any otherpero canvas:
importpero# init sizewidth=200height=200# init imageimg=pero.Image(width=width,height=height)# draw graphicsimg.line_color="b"img.fill_color="w"img.fill()img.draw_circle(100,100,75)# save to fileimg.export('image.png')# show in viewerimg.show()
Inside aQWidget you can create aQPainter and encapsulate it into thepero canvas:
importperofromPyQt5.QtGuiimportQPainter# init sizewidth=200height=200# init painterqp=QPainter()qp.begin(self)qp.setRenderHint(QPainter.RenderHint.Antialiasing)# init canvascanvas=pero.qt.QtCanvas(qp,width=width,height=height)# draw graphicscanvas.line_color="b"canvas.fill_color="w"canvas.fill()canvas.draw_circle(100,100,75)# end drawingqp.end()
Inside awxApp you can use just about anywxDC you want and encapsulate it into thepero canvas:
importperoimportwx# init sizewidth=200height=200# create DCbitmap=wx.Bitmap(width,height)dc=wx.MemoryDC()dc.SelectObject(bitmap)# use GCDCif'wxMac'notinwx.PlatformInfo:dc=wx.GCDC(dc)# init canvascanvas=pero.wx.WXCanvas(dc,width=width,height=height)# draw graphicscanvas.line_color="b"canvas.fill_color="w"canvas.fill()canvas.draw_circle(100,100,75)
Depending on the final image format, choose appropriatecairo surface, get the drawing context and encapsulate it intothepero canvas:
importperoimportcairo# init sizewidth=200height=200# create cairo drawing contextsurface=cairo.PSSurface('image.eps',width,height)dc=cairo.Context(surface)# init canvascanvas=pero.cairo.CairoCanvas(dc,width=width,height=height)# draw graphicscanvas.line_color="b"canvas.fill_color="w"canvas.fill()canvas.draw_circle(100,100,75)# save to filedc.show_page()
Create a document, add new page and encapsulate it into thepero canvas:
importperoimportfitz# init sizewidth=200height=200# init documentdoc=fitz.open()page=doc.newPage(width=width,height=height)# init canvascanvas=pero.mupdf.MuPDFCanvas(page)# draw graphicscanvas.line_color="b"canvas.fill_color="w"canvas.fill()canvas.draw_circle(100,100,75)# save to filedoc.save('image.pdf')doc.close()
Thepero library implements its own way to draw and save SVG files. Just create apero canvas:
importpero# init sizewidth=200height=200# init canvascanvas=pero.svg.SVGCanvas(width=width,height=height)# draw graphicscanvas.line_color="b"canvas.fill_color="w"canvas.fill()canvas.draw_circle(100,100,75)# save to filewithopen('test.svg','w',encoding='utf-8')asf:f.write(canvas.get_xml())
Initialize a newui.ImageContext and create apero canvas:
importperoimportui# init sizewidth=200height=200# open contextwithui.ImageContext(width,height)asctx:# init canvascanvas=pero.pythonista.UICanvas(width=width,height=height)# draw graphicscanvas.line_color="b"canvas.fill_color="w"canvas.fill()canvas.draw_circle(100,100,75)# show imageimg=ctx.get_image()img.show()
Similar tod3js JavaScript library, most of the properties of pre-buildpero.Glyphs objects canbe specified as a function, to which given data source is automatically provided. Together withpero.scales (and maybethepero.Axis) this can be used to make simple plots easily.
importperoimportnumpy# init sizewidth=400height=300padding=50# init datax_data=numpy.linspace(-numpy.pi,numpy.pi,50)y_data=numpy.sin(x_data)# init scalesx_scale=pero.LinScale(in_range= (min(x_data),max(x_data)),out_range= (padding,width-padding))y_scale=pero.LinScale(in_range= (-1,1),out_range= (height-padding,padding))color_scale=pero.GradientScale(in_range= (-1,1),out_range=pero.colors.Spectral)# init markermarker=pero.Circle(size=8,x=lambdad:x_scale.scale(d[0]),y=lambdad:y_scale.scale(d[1]),line_color=lambdad:color_scale.scale(d[1]).darker(.2),fill_color=lambdad:color_scale.scale(d[1]))# init imageimage=pero.Image(width=width,height=height)# fillimage.fill("w")# draw pointsmarker.draw_many(image,zip(x_data,y_data))# show imageimage.show()
In theexamples folder you will find sample codes to generate andunderstand all the following images. Check the image name and find corresponding python draw file.
About
Unified Python drawing API