Skip to content

Cairo in Go: vector to raster, SVG, PDF, EPS, WASM, OpenGL, Gio, etc.

License

Notifications You must be signed in to change notification settings

tdewolff/canvas

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

Canvas

API reference User guide Go Report Card Coverage Status

API documentation

User guide

Live HTMLCanvas demo

Canvas is a common vector drawing target that can output SVG, PDF, EPS, raster images (PNG, JPG, GIF, ...), HTML Canvas through WASM, OpenGL, and Gio. It has a wide range of path manipulation functionality such as flattening, stroking and dashing implemented. Additionally, it has a text formatter and embeds and subsets fonts (TTF, OTF, WOFF, WOFF2, or EOT) or converts them to outlines. It can be considered a Cairo or node-canvas alternative in Go. See the example below in Figure 1 for an overview of the functionality.

Preview

Figure 1: top-left you can see text being fitted into a box, justified using Donald Knuth's linea breaking algorithm to stretch the spaces between words to fill the whole width. You can observe a variety of styles and text decorations applied, as well as support for LTR/RTL mixing and complex scripts. In the bottom-right the word "stroke" is being stroked and drawn as a path. Top-right we see a LaTeX formula that has been converted to a path. Left of that we see an ellipse showcasing precise dashing, notably the length of e.g. the short dash is equal wherever it is on the curve. Note that the dashes themselves are elliptical arcs as well (thus exactly precise even if magnified greatly). To the right we see a closed polygon of four points being smoothed by cubic Béziers that are smooth along the whole path, and the blue line on the left shows a smoothed open path. On the bottom you can see a rotated rasterized image. The bottom-left shows path boolean operations. The result is equivalent for all renderers (PNG, PDF, SVG, etc.).

Sponsors

I'm actively looking for support in the form of donations or sponsorships to keep developing this library and highly appreciate any gesture. Please see the Sponsors button in GitHub for ways to contribute, or contact me directly.

State

Whether this library is ready for production environments is up to your own judgment. In general, this library is written thoughtfully and complete, but the scope of this work is so big and the implementation can be quite complex that inevitably it must have a great amount of bugs. Effort was put in writing unit and fuzz tests so that I suspect only special use-cases will stumble into bugs, but coverage is still lacking. As time permits, work is done to flesh-out functionality, find bugs, and optimize code. Optimization could be in execution time / reducing code complexity, reducing memory footprint, or reducing the length of paths from operation.

Execution performance is actually really good, especially the rasterizer is highly optimized with ASM. See for example a comparison of an extreme case in #280 (comment), where this library is at least twice as fast as existing solutions, and can handle bigger images than the likes of Inkscape and Cairo.

The path intersection code and path boolean operation code is quite complete and fast, and more importantly has a time complexity of O(n log n). It may suffer from numerical precision which can be avoided using Path.Gridsnap beforehand.

Please issue bug reports or feature requests to help this library mature! All help is appreciated. Also see Wiki - Planning for an inexhaustive list of ideas and TODOs.

Features

  • Path segment types: MoveTo, LineTo, QuadTo, CubeTo, ArcTo, Close (https://github.com/tdewolff/canvas/wiki/Paths)
  • Precise path flattening, stroking, and dashing for all segment type uing papers (see below)
  • Smooth spline generation through points for open and closed paths
  • LaTeX to path conversion (native Go and CGO implementations available)
  • sRGB compliance (use SRGBColorSpace, only available for rasterizer)

Rendering targets

Paths can be exported as or rendered to:

  • Raster images (PNG, GIF, JPEG, TIFF, BMP, WEBP, AVIF, ...)
  • PDF
  • SVG and SVGZ
  • PS and EPS
  • HTMLCanvas
  • OpenGL
  • Gio
  • Fyne

Additionally, it has bindings to be used as renderer for:

See (https://github.com/tdewolff/canvas/wiki/Renderers) for more information.

Stable path boolean operations

Numerically stable (!) path boolean operations, supporting AND, OR, XOR, NOT, and DIV operations in O((n+k) log n), with n the number of segments and k the number of intersections. This is very fast and allows handling huge paths. It uses 64bit floating-point precision for highly accurate computation and employs an additional strategy to ensure numerical stability. In particular:

  • Allows paths, subject or clipping, with any number of contours.
  • Allows contours with any orientation, clockwise or anticlockwise.
  • Contours may self-intersect any number of times.
  • Segments may overlap any number of times by any contour.
  • Points may be crossed any number of times.
  • Segments may be vertical.
  • Clipping path is implicitly closed (it makes no sense if it's an open path).
  • Subject path is currently implicitly closed, but it is WIP to support open paths.
  • Paths are currently flattened, but supporting Bézier or elliptical arcs is a WIP.

Numerical stability refers to cases where two segments are extremely close where floating-point precision can alter the computation whether they intersect or not. This is a very difficult problem to solve, and many libraries cannot handle this properly (nor can they handle 'degenerate' paths in general, see the list of properties above). Note that fixed-point precision suffers from the same problem. This library builds on papers from Bentley & Ottmann, de Berg, Martínez, Hobby, and Hershberger (see bibliography below).

Correctness and performance has been tested by drawing all land masses and islands from OpenStreetMap at various scales, which is a huge input (1 GB of compressed Shape files) with extremely degenerate data (many overlapping segments, overlapping points, vertical segments, self-intersections, extremely close intersections, different contour orientations, and so on).

TODO: add benchmark with other libraries

See (https://github.com/tdewolff/canvas/wiki/Boolean-operations) for more information.

Advanced text rendering

High-quality (comparable to TeX) text rendering and line breaking. It uses HarfBuzz for text shaping (native Go and CGO implementations available) and FriBidi for text bidirectionality (native Go and CGO implementations available), and uses Donald Knuth's line breaking algorithm for text layout. This enables the following features:

  • Align text left, center, right and justified, including indentation.
  • Align text top, middle, bottom in a text box, including setting line spacing.
  • Handle any script, eg. latin, cyrillic, devanagari, arabic, hebrew, han, etc.
  • Handle left-to-right, right-to-left, or top-to-bottom/bottom-to-top writing systems.
  • Mix scripts and fonts in a single line, eg. combine latin and arabic, or bold and regular styles.

Additionally, many font formats are supported (such as TTF, OTF, WOFF, WOFF2, EOT) and rendering can apply a gamma correction of 1.43 for better results. See (https://github.com/tdewolff/canvas/wiki/Fonts-&-Text) for more information.

Examples

Amsterdam city centre: the centre of Amsterdam is drawn from data loaded from the Open Street Map API.

Mauna-Loa CO2 concentration: using data from the Mauna-Loa observatory, carbon dioxide concentrations over time are drawn

Text document: an example of a text document using the PDF backend.

OpenGL: an example using the OpenGL backend.

Gio: an example using the Gio backend.

Fyne: an example using the Fyne backend.

TeX/PGF: an example showing the usage of the PGF (TikZ) LaTeX package as renderer in order to generated a PDF using LaTeX.

go-chart: an example using the go-chart library, plotting a financial graph.

gonum/plot: an example using the gonum/plot library.

HTMLCanvas: an example using the HTMLCanvas backend, see the live demo.

Users

This is a non-exhaustive list of library users I've come across. PRs are welcome to extend the list!

Articles

My own

Papers

License

Released under the MIT license.

Be aware that Fribidi uses the LGPL license.