Canvas is a Go drawing library based on OpenGL or using software rendering that is very similar to the HTML5 canvas API

Go canvas GoDoc

Canvas is a pure Go library that provides drawing functionality as similar as possible to the HTML5 canvas API. It has nothing to do with HTML or Javascript, the functions are just made to be approximately the same.

Most of the functions are supported, but it is still a work in progress. The library aims to accept a lot of different parameters on each function in a similar way as the Javascript API does.

Whereas the Javascript API uses a context that all draw calls go to, here all draw calls are directly on the canvas type. The other difference is that here setters are used instead of properties for things like fonts and line width.

OpenGL backend

The OpenGL backend is intended to provide decent performance. Obviously it will not be able to rival hand coded OpenGL for a given purpose, but for many purposes it will be enough. It can also be combined with hand coded OpenGL.

Software backend

The software backend can also be used if no OpenGL context is available. It will render into a standard Go RGBA image.

There is experimental MSAA anti-aliasing, but it doesn't fully work properly yet. The best option for anti-aliasing currently is to render to a larger image and then scale it down.

SDL/GLFW convenience packages

The sdlcanvas and glfwcanvas subpackages provide a very simple way to get started with just a few lines of code. As the names imply they are based on the SDL library and the GLFW library respectively. They create a window for you and give you a canvas to draw with.

OS support

Both the OpenGL and software backends work on the following operating systems:

  • Linux
  • Windows
  • macOS
  • Android
  • iOS

Using gomobile to build a full Go app using gomobile build now works by using an offscreen texture to render to and then rendering that to the screen. See the example in examples/gomobile. The offscreen texture is necessary since gomobile automatically creates a GL context without a stencil buffer, which this library requires.

Example

Look at the example/drawing package for some drawing examples.

Here is a simple example for how to get started:

package main

import (
	"math"

	"github.com/tfriedel6/canvas/sdlcanvas"
)

func main() {
	wnd, cv, err := sdlcanvas.CreateWindow(1280, 720, "Hello")
	if err != nil {
		panic(err)
	}
	defer wnd.Destroy()

	wnd.MainLoop(func() {
		w, h := float64(cv.Width()), float64(cv.Height())
		cv.SetFillStyle("#000")
		cv.FillRect(0, 0, w, h)

		for r := 0.0; r < math.Pi*2; r += math.Pi * 0.1 {
			cv.SetFillStyle(int(r*10), int(r*20), int(r*40))
			cv.BeginPath()
			cv.MoveTo(w*0.5, h*0.5)
			cv.Arc(w*0.5, h*0.5, math.Min(w, h)*0.4, r, r+0.1*math.Pi, false)
			cv.ClosePath()
			cv.Fill()
		}

		cv.SetStrokeStyle("#FFF")
		cv.SetLineWidth(10)
		cv.BeginPath()
		cv.Arc(w*0.5, h*0.5, math.Min(w, h)*0.4, 0, math.Pi*2, false)
		cv.Stroke()
	})
}

The result:

Implemented features

These features should work just like their HTML5 counterparts, but there are likely to be a lot of edge cases where they don't work exactly the same way.

  • beginPath
  • closePath
  • moveTo
  • lineTo
  • rect
  • arc
  • arcTo
  • quadraticCurveTo
  • bezierCurveTo
  • stroke
  • fill
  • clip
  • save
  • restore
  • scale
  • translate
  • rotate
  • transform
  • setTransform
  • fillText
  • measureText
  • textAlign
  • textBaseline
  • fillStyle
  • strokeText
  • strokeStyle
  • linear gradients
  • radial gradients
  • image patterns with repeat and transform
  • lineWidth
  • lineEnd (square, butt, round)
  • lineJoin (bevel, miter, round)
  • miterLimit
  • lineDash
  • getLineDash
  • lineDashOffset
  • global alpha
  • drawImage
  • getImageData
  • putImageData
  • clearRect
  • shadowColor
  • shadowOffset(X/Y)
  • shadowBlur
  • isPointInPath
  • isPointInStroke
  • self intersecting polygons

Missing features

  • globalCompositeOperation
  • imageSmoothingEnabled
  • textBaseline hanging and ideographic (currently work just like top and bottom)
Comments
  • Zoom / Magnify + MouseWheel

    Zoom / Magnify + MouseWheel

    Hi, Based on your event example -- project at: https://github.com/5k3105/tilemap3

    Updated sdlcanvas to include MouseWheelEvent:

    	MouseWheel func(x, y int)
    ...
    		case *sdl.MouseWheelEvent:
    			if wnd.MouseWheel != nil {
    					wnd.MouseWheel(int(e.X), int(e.Y))
    					handled = true
    			}
    

    then included it in project:

    	wnd.MouseWheel = func(x, y int) {
    		action = 1
    		if y == 1 {
    			cscale /= cmultiplier
    		}
    		if y == -1 {
    			cscale *= cmultiplier
    		}
    		cv.Scale(cscale, cscale)
    		println("y:  ", y)
    	}
    

    this does zoom (my code is buggy..) what I've drawn with lines but the Images (from PutImageData) are not zoomed. I believe this is by design based on this article: https://stackoverflow.com/questions/3420975/html5-canvas-zooming#3422425

    Is it possible to include a function which scales the whole canvas/window?

  • [suggestion] Video support?

    [suggestion] Video support?

    Hello, I think it would be great if this lib had some way to play a video on the canvas. Maybe something like in HTML5 Canvas where you can drawImage a video, or something even better w/ sound support? Thoughts?

  • Lines remain on canvas after screen clear

    Lines remain on canvas after screen clear

    Example both here: https://github.com/5k3105/slowdraw1 and here: https://github.com/5k3105/tilemap4

    Artifacts remain on screen after scale/clear/redraw. This is windows 7.

  • Slow text rendering?

    Slow text rendering?

    Hello! I have a somewhat text-heavy use case and I think I'm noticing that text rendering seems to be pretty slow -- with a couple hundred characters on the screen I get about 20fps and it only goes down from there.

    I glanced through the code and it seems it's building up a bitmap of the text to draw every frame with image.Draw, and then copying that to the destination buffer. Is that right? Is there some caching or a fast-path somewhere I can exploit?

  • Error building on macOS

    Error building on macOS

    I'm running the examples on macOS Mojave 10.14.3, and all throw me the same error:

    # github.com/tfriedel6/canvas/backend/gogl/gl
    ld: framework not found OpenGLES
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    

    After changing line 19 of backend/gogl/gl/package.go from

    // #cgo darwin           LDFLAGS: -framework OpenGLES
    

    to

    // #cgo darwin           LDFLAGS: -framework OpenGL
    

    the examples now run successfully. As Apple's OpenGL ES documentation only mentions iOS and tvOS, but no macOS, should OpenGL be used to build on macOS?

  • Anti-aliasing

    Anti-aliasing

    Hi,

    Do you have an option to apply an anti-aliasing filter (like described here: https://learnopengl.com/Advanced-OpenGL/Anti-Aliasing)?

    I'm just trying to display a rectangle like the white line below: anti_alias

    It can be seen here that there is no sufficient anti-aliasing.

    Thank you !

  • Rect shadow broken

    Rect shadow broken

    Hello again, Was just experimenting with rect shadows and found out that:

    • Rendering shadows is really slow (and uses 100% of my GPU)
    • There is a bug when you call DrawImage before rendering the rect

    For the bug, here's a screenshot:

    img

    what's excepted:

    img

    Here's the code used to draw the rect

    cnv.Rect(this.X, this.Y, this.W, this.H)
    cnv.SetFillStyle(this.Color)
    cnv.SetShadowColor(this.ShadowColor)
    cnv.SetShadowBlur(this.ShadowBlur)
    cnv.SetShadowOffsetX(this.ShadowOffX)
    cnv.SetShadowOffsetY(this.ShadowOffY)
    cnv.Fill()
    
  • What's the proper way to use RGBA for something like SetFillStyle?

    What's the proper way to use RGBA for something like SetFillStyle?

    Every thing I've tried (while studying the parseColor function, line 83 color.go) it chokes on the Alpha number.

    I can't quite figure out what type it expects for that fourth value.

    I would love to just send it a string like SetFillStyle("rgba(240, 236, 206, .5)") and it looks like it's supposed to be able to do that, but it doesn't seem to work.

    Sending it a string like "rgb(240, 236, 206)" DOES work, so I'm thinking there might be a problem with line 209 on color.go.

    I don't know if it's a bug or if I'm just stupid.

  • Blank red screen macOS

    Blank red screen macOS

    Hi, I have this blank red screen when I try to render something on screen. Weirdly, the only things that are rendered properly are images (DrawImage) This is a screenshot from the drawing example Screenshot 2020-06-01 at 14 59 42 I'm using go version go1.14 darwin/amd64 macOS Catalina Version 10.15.4 Do you guys have any idea what might be a problem?

  • Fix a panic issue of loading an image from cache

    Fix a panic issue of loading an image from cache

    When calling LoadImage(src interface{}) with a byte array, there will be a panic:

    panic: runtime error: hash of unhashable type []uint8

    that is caused by visiting the map structure of the image cache using the content of the image (byte array) as the key. In order to avoid this issue, we added a condition before visiting the map.

    See the changes. Thanks.

  • Memory Leak in DrawImage()

    Memory Leak in DrawImage()

    If I leave the code bellow running for a while, I can see it has a memory leak... If I replace the DrawImage call with PutImageData, the leakage goes away. It happens with when using glfwcanvas and sdlcanvas.

    OS: macOS Mohave OpenGL: native? (didn't have to install anything) SDL installed with brew install sdl2

    package main
    
    import (
    	"image"
    	"image/color"
    	"math/rand"
    	"time"
    
    	"github.com/tfriedel6/canvas/glfwcanvas"
    )
    
    var (
    	first = true
    	bla   = time.Now()
    	limg  *image.RGBA
    )
    
    func clientScreen() (image.Image, int64) {
    	if !first && rand.Float64() < 0.99 {
    		return limg, bla.UnixNano()
    	}
    	first = false
    	rgba := image.NewRGBA(image.Rect(0, 0, 800, 800))
    	for y := 0; y < 800; y++ {
    		for x := 0; x < 800; x++ {
    			rgba.Set(x, y, color.RGBA{
    				R: byte(rand.Intn(256)),
    				G: byte(rand.Intn(256)),
    				B: byte(rand.Intn(256)),
    				A: 255,
    			})
    		}
    	}
    	bla = time.Now()
    	limg = rgba
    	return rgba, bla.UnixNano()
    }
    
    func main() {
    	win, cv, err := glfwcanvas.CreateWindow(800, 800, "hello")
    	if err != nil {
    		panic(err)
    	}
    	var lastRefresh int64
    	win.MainLoop(func() {
    		// This call returns a new image and the last timestamp it was updated
    		img, lastUpdate := clientScreen()
    
    		// If there were no changes, terminate loop
    		if lastRefresh == lastUpdate {
    			return
    		}
    
    		// Process screen updates
    		// cv.PutImageData(img.(*image.RGBA), 0, 0)
    		cv.DrawImage(img, 0, 0)
    		lastRefresh = lastUpdate
    	})
    }
    
  • support font.Face drawing // font fallbacks

    support font.Face drawing // font fallbacks

    hello o/ my reasoning for this is that i wanted to use this multiface package to support font fallback but realized i couldnt use it since canvas basically only supports truetype.Font and the multiface package implements font.Face

    i'm not sure how hard (or easy) this would be. if you have an alternate way to be able to draw text with fallbacks fonts that would be fine too !!

  • Call CreateWindow function failed on WSL2

    Call CreateWindow function failed on WSL2

    I used canvas in WSL2 on win10.

    When I call sdlcanvas.CreateWindow, it failed with error:

    Error initializing SDL: No available video device
    

    Then I switched to glfwcanvas.CreateWindow

    it also emit an error:

    2022/01/17 15:27:59 PlatformError: X11: The DISPLAY environment variable is missing
    panic: NotInitialized: The GLFW library is not initialized
    
  • How to save canvas as png with  transparent background

    How to save canvas as png with transparent background

    I want save canvas as png photo. But the background is always black.

                    fDst, err := os.Create("out2.png")
    		if err != nil {
    			log.Fatal(err)
    		}
    		defer fDst.Close()
    
    		err = png.Encode(fDst, cv.GetImageData(0, 0, cv.Width(), cv.Height()))
    		if err != nil {
    			log.Fatal(err)
    		}
    		wnd.Close()
    
  • Fix for #29: Failed to compile vertex shader

    Fix for #29: Failed to compile vertex shader

    This pulls in the changes @tfriedel6 suggested in the discussion in #29.

    Also added GetGlobalAlpha() to the Canvas to allow apps a way to set a new global alpha based on the existing global alpha.

  • Failed to compile vertex shader

    Failed to compile vertex shader

    Trying to use this on the latest macOS release (Big Sur) and when running, I get the following error message:

    failed to compile vertex shader:
    
                                      ERROR: 0:2: '' :  #version required and missing.
                                      ERROR: 0:2: 'attribute' : syntax error: syntax error
    

    I'm using an OpenGLView directly, rather than some other framework, like glfw or sdl. Is there some special setup I need to do in order to get things to work that those libraries are doing (I'm assuming they work, but I haven't yet tried them to verify)?

    For reference, here are some code snippets showing the setup being done for the view:

    When creating the view:

    NSViewPtr nsNewOpenGLView() {
    	NSOpenGLPixelFormatAttribute attr[] = {
    		NSOpenGLPFAOpenGLProfile, NSOpenGLProfileVersion3_2Core,
    		NSOpenGLPFAColorSize,     24,
    		NSOpenGLPFADepthSize,     16,
    		NSOpenGLPFAAccelerated,
    		// Opt-in to automatic GPU switching. CGL-only property.
    		kCGLPFASupportsAutomaticGraphicsSwitching,
    		NSOpenGLPFAAllowOfflineRenderers,
    		0
    	};
    	id pixFormat = [[NSOpenGLPixelFormat alloc] initWithAttributes:attr];
    	NSRect frame = NSMakeRect(0, 0, 0, 0);
    	OpenGLView *view = [[OpenGLView alloc] initWithFrame:frame pixelFormat:pixFormat];
    	[view setWantsBestResolutionOpenGLSurface:YES];
    	[view setWantsLayer:YES];
    	return (NSViewPtr)view;
    }
    

    The override for prepareOpenGL:

    -(void)prepareOpenGL {
    	[super prepareOpenGL];
    	// Bind a default VBA to emulate OpenGL ES 2.
    	GLuint defVBA;
    	glGenVertexArrays(1, &defVBA);
    	glBindVertexArray(defVBA);
    	glEnable(GL_FRAMEBUFFER_SRGB);
    }
    
A Pong clone made from scratch with Go and C using OpenGL 3.3

Go-Pong A Pong video game clone made with Go lang and OpenGL 3.3 using C. Gameplay Offline Key bindings are 'w' and 's' for the left player and 'up ar

Feb 10, 2022
Go bindings to OpenGL Utility Library

GLU This package offers minimal bindings for GLU functions. Usage go get github.com/go-gl-legacy/glu License Copyright 2012 The go-gl Authors. All ri

Aug 18, 2018
Go cross-platform glfw library for creating an OpenGL context and receiving events.

glfw Package glfw experimentally provides a glfw-like API with desktop (via glfw) and browser (via HTML5 canvas) backends. It is used for creating a G

Sep 27, 2022
HTML Canvas 2D Context API for mobile, desktop and web

canvas HTML Canvas 2D Context API for mobile, desktop and web Context2D API https://www.w3.org/TR/2dcontext/ native code implement https://github.com/

Apr 22, 2022
golang OpenGL helper functions

glh: golang OpenGL helpers This package contains a number of functions useful for applications using OpenGL. Code Reference Features Textures and Text

Apr 8, 2022
Go bindings for OpenGL (generated via glow)

gl This repository holds Go bindings to various OpenGL versions. They are auto-generated using Glow. Features: Go functions that mirror the C specific

Dec 12, 2022
OpenGL binding generator for Go

GoGL GoGL is an OpenGL binding generator for Go. No external dependencies like GLEW are needed. Install the OpenGL bindings For example, OpenGL 2.1 bi

Dec 25, 2022
Go cross-platform OpenGL bindings.

gl Package gl is a Go cross-platform binding for OpenGL, with an OpenGL ES 2-like API. It supports: macOS, Linux and Windows via OpenGL 2.1 backend, i

Nov 21, 2022
Quake 2 Level Renderer written in Go and OpenGL
Quake 2 Level Renderer written in Go and OpenGL

go-quake2 Quake 2 Map Renderer written in Go and OpenGL. Features Loads any BSP file from Quake 2 Free roam around the environment Renders only a smal

Jan 4, 2023
OpenGL renderer

oglr About oglr is a package for Go to load OpenGL functions and render graphics. It is published on https://github.com/vbsw/oglr. Copyright Copyright

Jun 21, 2022
Go Graphics - 2D rendering in Go with a simple API.
Go Graphics - 2D rendering in Go with a simple API.

Go Graphics gg is a library for rendering 2D graphics in pure Go. Installation go get -u github.com/fogleman/gg Alternatively, you may use gopkg.in t

Dec 29, 2022
Cairo in Go: vector to SVG, PDF, EPS, raster, HTML Canvas, etc.
Cairo in Go: vector to SVG, PDF, EPS, raster, HTML Canvas, etc.

Canvas is a common vector drawing target that can output SVG, PDF, EPS, raster images (PNG, JPG, GIF, ...), HTML Canvas through WASM, and OpenGL. It h

Dec 25, 2022
Image processing library and rendering toolkit for Go.

blend Image processing library and rendering toolkit for Go. (WIP) Installation: This library is compatible with Go1. go get github.com/phrozen/blend

Nov 11, 2022
Very simple SVG to PNG converter library using the Inkscape.

svg2png Description Very simple SVG to PNG converter library using the Inkscape.

Jan 11, 2022
2D rendering for different output (raster, pdf, svg)
2D rendering for different output (raster, pdf, svg)

draw2d Package draw2d is a go 2D vector graphics library with support for multiple outputs such as images (draw2d), pdf documents (draw2dpdf), opengl

Dec 25, 2022
An experiment in rendering images with Slack custom emojis.
An experiment in rendering images with Slack custom emojis.

emojimage An experiment in rendering images with Slack custom emojis. Example Usage 1. Initializing your workspace First, you'll need to upload 1,332

Mar 12, 2022
Generate image plots of processes' memory usage very quickly, within a single binary.
Generate image plots of processes' memory usage very quickly, within a single binary.

memplot A small utility written in golang to quickly plot memory usage of processes. memplot constantly samples memory usage of a process, for a given

Apr 17, 2021
A (very) simple graph package that utilizes the Generics features in Go 1.18

A (very) simple graph package that utilizes the Generics features in Go 1.18

May 11, 2022
A phoenix Chain client based on the go-ethereum fork,the new PoS consensus engine is based on the VRF algorithm.

Phoenix Official Golang implementation of the Phoenix protocol. !!!The current version is for testing and developing purposes only!!! Building the sou

Aug 18, 2022