impasto

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 18, 2026 License: MIT

README

impasto

CI

A pure-Go (CGO=0) library for Photoshop-style layered image compositing: blend modes, masks, vector paths, gradients, blur, and non-destructive layer effects (drop shadow, inner shadow, outer/inner glow, gradient/color overlay, stroke, bevel & emboss).

It is a library, not an application. There is no CLI and no file-format opinion beyond decoding into and encoding out of the standard library's image.Image. It is meant to be as useful to a poster tool or a game's UI renderer as to a template renderer.

Why

Go has scattered pieces (image/draw for basic Porter-Duff, x/image/vector for path filling) but nothing that reproduces Photoshop's blend-mode math, layer-style effects, or dithered gradients. impasto fills that gap without dropping to CGO bindings for Skia or Cairo.

Design

  • Linear light, premultiplied, float32. Source pixels are decoded sRGB to linear on ingest, composited premultiplied to avoid fringing, and re-encoded on output. Compositing in gamma space is not a reachable mistake.
  • Deterministic. The same input produces byte-identical output across runs. Parallelism partitions work into fixed row bands, never by scheduling order, which is what makes golden-image testing possible.
  • Concurrent by default. Every expensive operation splits across GOMAXPROCS goroutines.
  • Immutable inputs. Effects and masks work on copies, so a layer can be re-composited with different settings without surprises.
  • Effects are declarative. A layer effect is a parameter struct, not an imperative call. The renderer decides how and when to rasterize it.

Packages

Lower layers never import higher ones, so each is usable on its own.

Package Responsibility
raster The Buffer type, sRGB/linear conversion, 8/16-bit image ingest and egress with ordered dithering
blend The blend-mode formulas from ISO 32000-2, per-pixel and buffer-level
mask Raster and vector masks, coverage composition
path Bezier construction, anti-aliased fill (nonzero/even-odd), and stroking (joins, caps, dashes)
gradient Linear, radial, angle, reflected, and diamond gradients with per-stop opacity
blur 3-pass box blur as a separable Gaussian approximation
effects The declarative layer styles
canvas Layer stack, groups, and Render

Most callers import only canvas.

Install

go get github.com/odevine/impasto

Requires Go 1.24+. No non-stdlib dependencies, none pulling in CGO.

Quickstart

doc := &canvas.Document{
    Width: 200, Height: 120,
    Root: canvas.Group{
        PassThrough: true, Opacity: 1,
        Layers: []canvas.Node{
            &canvas.Layer{Content: bg, Opacity: 1, Mode: blend.Normal},
            &canvas.Layer{
                Content: logo,
                Opacity: 1,
                Mask:    mask.NewVectorMask(shape, 200, 120, path.NonZero),
                Effects: []effects.Effect{
                    &effects.DropShadow{Color: color.Black, Opacity: 0.75,
                        Angle: 2.36, Distance: 12, BlurRadius: 18, Mode: blend.Multiply},
                    &effects.Stroke{Width: 4, Color: color.White,
                        Alignment: effects.StrokeOutside},
                },
            },
        },
    },
}

out := canvas.MustRender(doc)
png.Encode(w, out.ToImage(8))

Layer content is document-sized. Place a smaller image with canvas.Place.

Examples

The examples/ directory has runnable programs that render PNGs showing off each part of the library. See examples/README.md for a full walk-through of every mode, effect, and gradient.

Showcase poster

Program Renders
blendmodes All 16 blend modes as a chart
gradients The five gradient types plus a transparency fade
effects The eight layer styles on a badge
paths Stroke caps, joins, dashes, fill rules, and beziers
showcase A poster combining gradients, masks, groups, and every effect

Run one with go run ./examples/<name>, or regenerate all of them with make examples.

Text

impasto never shapes text. Rasterize glyph outlines yourself (for example with go-text/typesetting feeding the path package) and hand the resulting buffer to canvas as an ordinary layer. Nothing below canvas needs to know a layer's pixels came from text.

Testing

  • Blend modes are checked against the ISO formulas computed independently, per channel, across a grid that includes the discontinuity points.
  • Path coverage is validated by area conservation (triangles, circles) and exact partial-pixel coverage.
  • Golden image regression via go test ./canvas -update to regenerate.
  • Fuzzing covers the path rasterizer, stroker, and gradient sampling, the places untrusted or degenerate input first reaches numeric code: go test ./path -fuzz=FuzzRasterize.
  • Benchmarks track blend throughput, blur throughput, and full-document render: go test ./... -bench=..

Development

A Makefile wraps the common tasks, and make ci runs exactly what the CI workflow runs:

make ci       # gofmt check, vet, build, race tests
make test     # plain test suite
make cover    # coverage summary
make fuzz     # short fuzz smoke run
make examples # regenerate the example images
make hooks    # enable the pre-commit hook (fmt + vet + test)

Continuous integration runs on every push and pull request (test matrix on the minimum and current Go versions, govulncheck, and a fuzz smoke run). Releases are automated with release-please: commits follow the Conventional Commits format, and merging the release PR tags a semver version and publishes a GitHub Release.

Status

Seven of the eight effects are built to spec-level accuracy. Bevel & emboss is close-and-configurable rather than pixel-exact against Photoshop, by design: it is the one effect with no clean public spec, so it derives a normal map from the layer's alpha and applies a directional lighting model, and it is expected to iterate against real reference renders.

Non-goals (v1)

No font shaping, no CMYK or print color management, no GPU backend, and no animation.

Directories

Path Synopsis
Package blend implements the Photoshop blend modes as pure functions.
Package blend implements the Photoshop blend modes as pure functions.
Package blur provides a fast separable blur used as a primitive by the effects package.
Package blur provides a fast separable blur used as a primitive by the effects package.
Package canvas is the orchestration layer most callers import.
Package canvas is the orchestration layer most callers import.
Package effects implements Photoshop-style layer styles as declarative data.
Package effects implements Photoshop-style layer styles as declarative data.
examples
blendmodes command
Command blendmodes renders a 4x4 chart of every blend mode, each cell blending a vertical color ramp over a horizontal rainbow so the modes' behavior is visible at a glance.
Command blendmodes renders a 4x4 chart of every blend mode, each cell blending a vertical color ramp over a horizontal rainbow so the modes' behavior is visible at a glance.
effects command
Command effects renders each of the eight layer styles on a rounded-rectangle badge, in a 4x2 grid.
Command effects renders each of the eight layer styles on a rounded-rectangle badge, in a 4x2 grid.
gradients command
Command gradients renders the five gradient types plus a per-stop opacity fade shown over a checkerboard, in a 3x2 grid.
Command gradients renders the five gradient types plus a per-stop opacity fade shown over a checkerboard, in a 3x2 grid.
internal/demo
Package demo holds helpers shared by the example programs: saving buffers to PNG, building solid and checkerboard content, and a few handy path shapes.
Package demo holds helpers shared by the example programs: saving buffers to PNG, building solid and checkerboard content, and a few handy path shapes.
paths command
Command paths renders stroke caps, stroke joins, dashes, the two fill rules, and a stroked bezier, all drawn directly onto one buffer.
Command paths renders stroke caps, stroke joins, dashes, the two fill rules, and a stroked bezier, all drawn directly onto one buffer.
showcase command
Command showcase composes a single poster that combines gradients, masks, groups, blend modes, and the full set of layer effects into one scene.
Command showcase composes a single poster that combines gradients, masks, groups, blend modes, and the full set of layer effects into one scene.
Package gradient generates linear, radial, angle, reflected, and diamond gradients with multi-stop color and independent per-stop opacity.
Package gradient generates linear, radial, angle, reflected, and diamond gradients with multi-stop color and independent per-stop opacity.
internal
parallel
Package parallel splits row-oriented pixel work across goroutines.
Package parallel splits row-oriented pixel work across goroutines.
Package mask defines coverage sources that scale a layer's alpha before it is composited.
Package mask defines coverage sources that scale a layer's alpha before it is composited.
Package path builds bezier paths and rasterizes them with anti-aliased scanline coverage.
Package path builds bezier paths and rasterizes them with anti-aliased scanline coverage.
Package raster is the substrate every other package builds on.
Package raster is the substrate every other package builds on.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL