diff options
author | Stephan Altmueller <stephana@google.com> | 2017-05-09 15:56:06 -0400 |
---|---|---|
committer | Skia Commit-Bot <skia-commit-bot@chromium.org> | 2017-05-10 15:32:19 +0000 |
commit | efa48d599de15d960d7335a4a93a6bbeb97d3c41 (patch) | |
tree | 6b95700087faeaaec0ea030d0fa5e17b515cebc1 /experimental | |
parent | 05fd8cf08970763832d6690ca1823168dd6f071f (diff) |
Experimental Go bindings for Skia
This CL implements Go bindings for a subset of the functions in the C API.
It implements a Go version of the C demo program in
experimental/c-api-example/skia-c-example.c and the output is identical.
(Checked by hand).
The main purpose is to establish a pattern of calling the Skia C API that
is memory safe and provides a idiomatic Go interface to Skia.
Follow up CLs will cover the entire C API, add documentation and establish
a pattern to distribute the bindings more easily.
BUG=
Change-Id: I96ff7c3715164c533202ce300ab0312b1b07f884
Change-Id: I96ff7c3715164c533202ce300ab0312b1b07f884
Reviewed-on: https://skia-review.googlesource.com/10032
Reviewed-by: Mike Klein <mtklein@chromium.org>
Commit-Queue: Stephan Altmueller <stephana@google.com>
Diffstat (limited to 'experimental')
-rw-r--r-- | experimental/go-demo/main.go | 76 | ||||
-rw-r--r-- | experimental/go-skia/ctypes.go | 58 | ||||
-rw-r--r-- | experimental/go-skia/skia.go | 223 | ||||
-rw-r--r-- | experimental/go-skia/types.go | 65 |
4 files changed, 398 insertions, 24 deletions
diff --git a/experimental/go-demo/main.go b/experimental/go-demo/main.go new file mode 100644 index 0000000000..7df64d6e40 --- /dev/null +++ b/experimental/go-demo/main.go @@ -0,0 +1,76 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +package main + +/* + This is a translation of the example code in + "experimental/c-api-example/skia-c-example.c" to test the + go-skia package. +*/ + +import ( + "log" + "os" + + skia "skia.googlesource.com/skia/experimental/go-skia" +) + +func main() { + imgInfo := &skia.ImageInfo{ + Width: 640, + Height: 480, + ColorType: skia.GetDefaultColortype(), + AlphaType: skia.PREMUL_ALPHATYPE, + } + + surface, err := skia.NewRasterSurface(imgInfo) + if err != nil { + log.Fatalln(err) + } + + canvas := surface.Canvas() + + fillPaint := skia.NewPaint() + fillPaint.SetColor(0xFF0000FF) + canvas.DrawPaint(fillPaint) + fillPaint.SetColor(0xFF00FFFF) + + rect := skia.NewRect(100, 100, 540, 380) + canvas.DrawRect(rect, fillPaint) + + strokePaint := skia.NewPaint() + strokePaint.SetColor(0xFFFF0000) + strokePaint.SetAntiAlias(true) + strokePaint.SetStroke(true) + strokePaint.SetStrokeWidth(5.0) + + path := skia.NewPath() + path.MoveTo(50, 50) + path.LineTo(590, 50) + path.CubicTo(-490, 50, 1130, 430, 50, 430) + path.LineTo(590, 430) + canvas.DrawPath(path, strokePaint) + + fillPaint.SetColor(0x8000FF00) + canvas.DrawOval(skia.NewRect(120, 120, 520, 360), fillPaint) + + // // Get a skia image from the surface. + skImg := surface.Image() + + // Write new image to file if we have one. + if skImg != nil { + out, err := os.Create("testimage.png") + if err != nil { + log.Fatal(err) + } + defer out.Close() + + if err := skImg.WritePNG(out); err != nil { + log.Fatalf("Unable to write png: %s", err) + } + } +} diff --git a/experimental/go-skia/ctypes.go b/experimental/go-skia/ctypes.go new file mode 100644 index 0000000000..64953edc37 --- /dev/null +++ b/experimental/go-skia/ctypes.go @@ -0,0 +1,58 @@ +//+build ignore + +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +package skia + +// This file is used to generate 'types.go' +// from the corresponding type definitions in the C API. +// Any C struct for which we would like to generate a +// Go struct with the same memory layout should defined defined here. +// Any enum that is used in Go should also be listed here, together +// with the enum values that we want to use. + +/* +#cgo CFLAGS: -I../../include/c +#include "../../include/c/sk_types.h" +*/ +import "C" + +type Color C.sk_color_t + +type ColorType C.sk_colortype_t + +const ( + UNKNOWN_COLORTYPE ColorType = C.UNKNOWN_SK_COLORTYPE + RGBA_8888_COLORTYPE ColorType = C.RGBA_8888_SK_COLORTYPE + BGRA_8888_COLORTYPE ColorType = C.BGRA_8888_SK_COLORTYPE + ALPHA_8_COLORTYPE ColorType = C.ALPHA_8_SK_COLORTYPE +) + +type AlphaType C.sk_alphatype_t + +const ( + OPAQUE_ALPHATYPE AlphaType = C.OPAQUE_SK_ALPHATYPE + PREMUL_ALPHATYPE AlphaType = C.PREMUL_SK_ALPHATYPE + UNPREMUL_ALPHATYPE AlphaType = C.UNPREMUL_SK_ALPHATYPE +) + +type PixelGeometry C.sk_pixelgeometry_t + +const ( + UNKNOWN_SK_PIXELGEOMETRY PixelGeometry = C.UNKNOWN_SK_PIXELGEOMETRY + RGB_H_SK_PIXELGEOMETRY PixelGeometry = C.RGB_H_SK_PIXELGEOMETRY + BGR_H_SK_PIXELGEOMETRY PixelGeometry = C.BGR_H_SK_PIXELGEOMETRY + RGB_V_SK_PIXELGEOMETRY PixelGeometry = C.RGB_V_SK_PIXELGEOMETRY + BGR_V_SK_PIXELGEOMETRY PixelGeometry = C.BGR_V_SK_PIXELGEOMETRY +) + +type ImageInfo C.sk_imageinfo_t + +type SurfaceProps C.sk_surfaceprops_t + +type Rect C.sk_rect_t diff --git a/experimental/go-skia/skia.go b/experimental/go-skia/skia.go index 30730578a7..e477593dc8 100644 --- a/experimental/go-skia/skia.go +++ b/experimental/go-skia/skia.go @@ -1,38 +1,213 @@ -package main - -// First, build Skia this way: -// ./gyp_skia -Dskia_shared_lib=1 && ninja -C out/Debug +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ +package skia /* -#cgo LDFLAGS: -lGL -#cgo LDFLAGS: -lGLU -#cgo LDFLAGS: -lX11 -#cgo LDFLAGS: -ldl -#cgo LDFLAGS: -lfontconfig -#cgo LDFLAGS: -lfreetype -#cgo LDFLAGS: -lgif -#cgo LDFLAGS: -lm -#cgo LDFLAGS: -lpng -#cgo LDFLAGS: -lstdc++ -#cgo LDFLAGS: -lz - -#cgo LDFLAGS: -L ../../out/Debug/lib -#cgo LDFLAGS: -Wl,-rpath=../../out/Debug/lib +#cgo LDFLAGS: -L${SRCDIR}/../../out/Shared +#cgo LDFLAGS: -Wl,-rpath=${SRCDIR}/../../out/Shared #cgo LDFLAGS: -lskia - #cgo CFLAGS: -I../../include/c +#include "sk_canvas.h" +#include "sk_data.h" +#include "sk_image.h" +#include "sk_paint.h" +#include "sk_path.h" #include "sk_surface.h" */ import "C" import ( "fmt" + "io" + "runtime" + "unsafe" ) -func main() { - p := C.sk_paint_new() - defer C.sk_paint_delete(p) - fmt.Println("OK!") +// TODO(stephana): Add proper documentation to the types defined here. + +////////////////////////////////////////////////////////////////////////// +// Surface +////////////////////////////////////////////////////////////////////////// +type Surface struct { + ptr *C.sk_surface_t +} + +// func NewRasterSurface(width, height int32, alphaType AlphaType) (*Surface, error) { +func NewRasterSurface(imgInfo *ImageInfo) (*Surface, error) { + ptr := C.sk_surface_new_raster(imgInfo.cPointer(), (*C.sk_surfaceprops_t)(nil)) + if ptr == nil { + return nil, fmt.Errorf("Unable to create raster surface.") + } + + ret := &Surface{ptr: ptr} + runtime.SetFinalizer(ret, func(s *Surface) { + C.sk_surface_unref(s.ptr) + }) + return ret, nil +} + +func (s *Surface) Canvas() *Canvas { + return &Canvas{ + ptr: C.sk_surface_get_canvas(s.ptr), + keepParentAlive: s, + } +} + +func (s *Surface) Image() *Image { + ret := &Image{ + ptr: C.sk_surface_new_image_snapshot(s.ptr), + keepParentAlive: s, + } + runtime.SetFinalizer(ret, func(i *Image) { + C.sk_image_unref(i.ptr) + }) + return ret +} + +////////////////////////////////////////////////////////////////////////// +// Image +////////////////////////////////////////////////////////////////////////// +type Image struct { + ptr *C.sk_image_t + keepParentAlive *Surface +} + +func (i *Image) WritePNG(w io.Writer) error { + data := C.sk_image_encode(i.ptr) + defer C.sk_data_unref(data) + + dataPtr := C.sk_data_get_data(data) + dataSize := C.sk_data_get_size(data) + byteSlice := C.GoBytes(dataPtr, C.int(dataSize)) + _, err := w.Write(byteSlice) + if err != nil { + return err + } + return nil } -// TODO: replace this with an idiomatic interface to Skia. +////////////////////////////////////////////////////////////////////////// +// Canvas +////////////////////////////////////////////////////////////////////////// +type Canvas struct { + ptr *C.sk_canvas_t + keepParentAlive *Surface +} + +func (c *Canvas) DrawPaint(paint *Paint) { + C.sk_canvas_draw_paint(c.ptr, paint.ptr) +} + +func (c *Canvas) DrawOval(rect *Rect, paint *Paint) { + // C.sk_canvas_draw_oval(c.ptr, (*C.sk_rect_t)(unsafe.Pointer(rect)), (*C.sk_paint_t)(paint.ptr)) + C.sk_canvas_draw_oval(c.ptr, rect.cPointer(), paint.ptr) +} + +func (c *Canvas) DrawRect(rect *Rect, paint *Paint) { + // C.sk_canvas_draw_rect(c.ptr, (*C.sk_rect_t)(unsafe.Pointer(rect)), (*C.sk_paint_t)(paint.ptr)) + C.sk_canvas_draw_rect(c.ptr, rect.cPointer(), paint.ptr) +} + +func (c *Canvas) DrawPath(path *Path, paint *Paint) { + // C.sk_canvas_draw_path(c.ptr, (*C.sk_path_t)(path.ptr), (*C.sk_paint_t)(paint.ptr)) + C.sk_canvas_draw_path(c.ptr, path.ptr, paint.ptr) +} + +////////////////////////////////////////////////////////////////////////// +// Paint +////////////////////////////////////////////////////////////////////////// +type Paint struct { + ptr *C.sk_paint_t +} + +func NewPaint() *Paint { + ret := &Paint{ptr: C.sk_paint_new()} + runtime.SetFinalizer(ret, func(p *Paint) { + C.sk_paint_delete(p.ptr) + }) + return ret +} + +func (p *Paint) SetColor(color Color) { + C.sk_paint_set_color(p.ptr, C.sk_color_t(color)) +} + +func (p *Paint) SetAntiAlias(antiAlias bool) { + C.sk_paint_set_antialias(p.ptr, C._Bool(antiAlias)) +} + +func (p *Paint) SetStroke(val bool) { + C.sk_paint_set_stroke(p.ptr, C._Bool(val)) +} + +func (p *Paint) SetStrokeWidth(width float32) { + C.sk_paint_set_stroke_width(p.ptr, C.float(width)) +} + +////////////////////////////////////////////////////////////////////////// +// Path +////////////////////////////////////////////////////////////////////////// +type Path struct { + ptr *C.sk_path_t +} + +func NewPath() *Path { + ret := &Path{ptr: C.sk_path_new()} + runtime.SetFinalizer(ret, func(p *Path) { + C.sk_path_delete(p.ptr) + }) + return ret +} + +func (p *Path) MoveTo(x, y float32) { + C.sk_path_move_to(p.ptr, C.float(x), C.float(y)) +} + +func (p *Path) LineTo(x, y float32) { + C.sk_path_line_to(p.ptr, C.float(x), C.float(y)) +} + +func (p *Path) QuadTo(x0, y0, x1, y1 float32) { + C.sk_path_quad_to(p.ptr, C.float(x0), C.float(y0), C.float(x1), C.float(y1)) +} + +func (p *Path) ConicTo(x0, y0, x1, y1, w float32) { + C.sk_path_conic_to(p.ptr, C.float(x0), C.float(y0), C.float(x1), C.float(y1), C.float(w)) +} + +func (p *Path) CubicTo(x0, y0, x1, y1, x2, y2 float32) { + C.sk_path_cubic_to(p.ptr, C.float(x0), C.float(y0), C.float(x1), C.float(y1), C.float(x2), C.float(y2)) +} + +func (p *Path) Close() { + C.sk_path_close(p.ptr) +} + +// NewRect is a convenience function to define a Rect in a single line. +func NewRect(left, top, right, bottom float32) *Rect { + return &Rect{ + Left: left, + Top: top, + Right: right, + Bottom: bottom, + } +} + +// cPointer casts the pointer to Rect to the corresponding C pointer. +func (r *Rect) cPointer() *C.sk_rect_t { + return (*C.sk_rect_t)(unsafe.Pointer(r)) +} + +// cPointer casts the pointer to ImageInfo to the corresponding C pointer. +func (i *ImageInfo) cPointer() *C.sk_imageinfo_t { + return (*C.sk_imageinfo_t)(unsafe.Pointer(i)) +} + +// Utility functions. +func GetDefaultColortype() ColorType { + return ColorType(C.sk_colortype_get_default_8888()) +} diff --git a/experimental/go-skia/types.go b/experimental/go-skia/types.go new file mode 100644 index 0000000000..637eceea96 --- /dev/null +++ b/experimental/go-skia/types.go @@ -0,0 +1,65 @@ +/* + * Copyright 2015 Google Inc. + * + * Use of this source code is governed by a BSD-style license that can be + * found in the LICENSE file. + */ + +// Created by cgo -godefs. Enum fields in structs were fixed by hand. +// command: go tool cgo -godefs ctypes.go > types.go +// +// The purpose of this file is to have Go structs with the same memory +// layout as their C counterparts. For enums we want the underlying primitive +// types to match. +// +// TODO(stephan): Add tests that allow to detect failure on platforms other +// than Linux and changes in the underlying C types. + +package skia + +type Color uint32 + +type ColorType uint32 + +const ( + UNKNOWN_COLORTYPE ColorType = 0x0 + RGBA_8888_COLORTYPE ColorType = 0x1 + BGRA_8888_COLORTYPE ColorType = 0x2 + ALPHA_8_COLORTYPE ColorType = 0x3 +) + +type AlphaType uint32 + +const ( + OPAQUE_ALPHATYPE AlphaType = 0x0 + PREMUL_ALPHATYPE AlphaType = 0x1 + UNPREMUL_ALPHATYPE AlphaType = 0x2 +) + +type PixelGeometry uint32 + +const ( + UNKNOWN_SK_PIXELGEOMETRY PixelGeometry = 0x0 + RGB_H_SK_PIXELGEOMETRY PixelGeometry = 0x1 + BGR_H_SK_PIXELGEOMETRY PixelGeometry = 0x2 + RGB_V_SK_PIXELGEOMETRY PixelGeometry = 0x3 + BGR_V_SK_PIXELGEOMETRY PixelGeometry = 0x4 +) + +type ImageInfo struct { + Width int32 + Height int32 + ColorType ColorType + AlphaType AlphaType +} + +type SurfaceProps struct { + PixelGeometry PixelGeometry +} + +type Rect struct { + Left float32 + Top float32 + Right float32 + Bottom float32 +} |