-
Notifications
You must be signed in to change notification settings - Fork 546
SkiaSharp with Python
One of the popular requests with skia is a Python API. I am no Python expert - I literally know nothing, and Bing-ed everything - but using the same native C libraries that SkiaSharp uses, we can create a Python script.
Forgive this awful code I am sure I have just released on the world, but here is one way in which to make use of the native skia bits in your Python app. You can just build the native bits you need:
# Windows
.\bootstrapper.ps1 -Target externals-windows
# macOS
./bootstrapper.sh -t externals-mac
# Linux
./bootstrapper.sh -t externals-linux
This will pop out the native bits in the <skiasharp-root>/output/<platform>/libSkiaSharp.xxx
path. These are just plain old C/C++ binaries that anyone should be able to use from any language. Note: you can also download and extract the NuGet (http://www.nuget.org/packages/SkiaSharp). All the binaries are in the runtimes
folder in the root of the zip.
Here is a sample script that will draw a nice little image:
# create the surface
info = SKImageInfo(512, 512, SKPlatformColorType, SKAlphaType.Premul)
surface = SKSurface(info)
# get and clear the canvas for drawing
canvas = surface.canvas()
canvas.clear(0xFF3498DB) # "Xamarin Light Blue"
# create the paint fill
paint = SKPaint()
paint.setAntiAlias(True)
paint.setStyle(SKPaintStyle.Fill)
# draw a circle
paint.setColor(0xFF2C3E50) # "Xamarin Dark Blue"
canvas.drawCircle(256, 256, 200, paint)
# draw text
center_text = 256 + 16
paint.setTextSize(64)
paint.setTextAlign(SKTextAlign.Center)
paint.setColor(0xFFFFFFFF) # "White"
canvas.drawText("SkiaSharp", 256, center_text - 64, paint)
canvas.drawText("+", 256, center_text, paint)
canvas.drawText("Python", 256, center_text + 64, paint)
# create a PNG from the surface
image = surface.snapshot()
data = image.encode()
# save the PNG to disk
stream = SKFileWStream("image.png")
stream.writeData(data)
stream.flush()
# clean up
del paint
del stream
del data
del image
del canvas
del surface
The definitions part of the script is very simple - just like the SkiaSharp C# API:
from ctypes import *
def enum(**enums):
return type('Enum', (), enums)
'''
SkiaApi.cs
'''
libSkiaSharp = cdll.LoadLibrary("libSkiaSharp.dll")
'''
Declarations.cs
'''
SKAlphaType = enum(Unknown = 0, Opaque = 1, Premul = 2, Unpremul = 3)
SKTextAlign = enum(Left = 0, Center = 1, Right = 2)
SKPaintStyle = enum(Fill = 0, Stroke = 1, StrokeAndFill = 2)
SKPlatformColorType = libSkiaSharp.sk_colortype_get_default_8888()
class SKImageInfo(Structure):
_fields_ = [("width", c_int),
("height", c_int),
("colorType", c_int),
("alphaType", c_int)]
class SKSurface(object):
def __init__(self, info):
self.__HANDLE = libSkiaSharp.sk_surface_new_raster(byref(info), 0)
def handle(self):
return self.__HANDLE
def canvas(self):
cnv = libSkiaSharp.sk_surface_get_canvas(self.__HANDLE)
return SKCanvas(cnv)
def snapshot(self):
img = libSkiaSharp.sk_surface_new_image_snapshot(self.__HANDLE)
return SKImage(img)
def __del__(self):
libSkiaSharp.sk_surface_unref(self.__HANDLE)
class SKCanvas(object):
def __init__(self, handle):
self.__HANDLE = handle
def handle(self):
return self.__HANDLE
def clear(self, color):
libSkiaSharp.sk_canvas_draw_color(self.__HANDLE, color)
def drawCircle(self, cx, cy, radius, paint):
libSkiaSharp.sk_canvas_draw_circle(self.__HANDLE, c_float(cx), c_float(cy), c_float(radius), paint.handle())
def drawText(self, text, x, y, paint):
libSkiaSharp.sk_canvas_draw_text(self.__HANDLE, text, len(text), c_float(x), c_float(y), paint.handle())
def __del__(self):
# do nothing
return False
class SKPaint(object):
def __init__(self):
self.__HANDLE = libSkiaSharp.sk_paint_new()
def handle(self):
return self.__HANDLE
def setAntiAlias(self, value):
libSkiaSharp.sk_paint_set_antialias(self.__HANDLE, c_bool(value))
def setStyle(self, style):
libSkiaSharp.sk_paint_set_style(self.__HANDLE, style)
def setColor(self, color):
libSkiaSharp.sk_paint_set_color(self.__HANDLE, color)
def setTextSize(self, size):
libSkiaSharp.sk_paint_set_textsize(self.__HANDLE, c_float(size))
def setTextAlign(self, alignment):
libSkiaSharp.sk_paint_set_text_align(self.__HANDLE, alignment)
def __del__(self):
libSkiaSharp.sk_paint_delete(self.__HANDLE)
class SKImage(object):
def __init__(self, handle):
self.__HANDLE = handle
def handle(self):
return self.__HANDLE
def encode(self):
data = libSkiaSharp.sk_image_encode(self.__HANDLE)
return SKData(data)
def __del__(self):
libSkiaSharp.sk_image_unref(self.__HANDLE)
class SKData(object):
def __init__(self, handle):
self.__HANDLE = handle
def handle(self):
return self.__HANDLE
def data(self):
return libSkiaSharp.sk_data_get_data(self.__HANDLE)
def size(self):
return libSkiaSharp.sk_data_get_size(self.__HANDLE)
def __del__(self):
libSkiaSharp.sk_data_unref(self.__HANDLE)
class SKFileWStream(object):
def __init__(self, filename):
self.__HANDLE = libSkiaSharp.sk_filewstream_new(filename)
def handle(self):
return self.__HANDLE
def writeData(self, data):
return self.write(data.data(), data.size())
def write(self, data, size):
return libSkiaSharp.sk_wstream_write(self.__HANDLE, data, size)
def flush(self):
libSkiaSharp.sk_wstream_flush(self.__HANDLE)
def __del__(self):
libSkiaSharp.sk_filewstream_destroy(self.__HANDLE)
The full script can be found here: https://gist.github.com/mattleibow/d4fa01931b2f8e283b61f5fa294dd894