raster

package
v0.2.4 Latest Latest
Warning

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

Go to latest
Published: Aug 24, 2026 License: Apache-2.0 Imports: 3 Imported by: 0

Documentation

Overview

Package raster is a two dimensional graphics engine: paths, curve flattening, an anti-aliased cell rasterizer with both fill rules, a stroker and a dasher, clip masks, pixmaps of one to four color components with an optional alpha channel, and the span pipeline over them.

It knows nothing about PDF. A color space reaches it as Model, which is three methods: how many components, and how to get to and from RGB.

Index

Constants

View Source
const DefaultFlatness = 0.25

DefaultFlatness is how far a flattened curve may stray from the true one, in the units the path is flattened into.

View Source
const StrokeSubPixels = 32

StrokeSubPixels is SubPixels for a stroked glyph, whose two edges lie close enough together that a quarter pixel moves more coverage than under a fill.

View Source
const SubPixels = 4

SubPixels is how many phases of the glyph origin are kept apart. Snapping a glyph to whole pixels is visible as uneven spacing.

Variables

View Source
var EmptyRect = Rect{1e20, 1e20, -1e20, -1e20}

EmptyRect contains nothing. Union with it is the identity.

View Source
var Identity = Matrix{1, 0, 0, 1, 0, 0}

Identity leaves a point where it is.

View Source
var InfiniteRect = Rect{-1e20, -1e20, 1e20, 1e20}

InfiniteRect is the rectangle that contains everything, used where a scissor is required but nothing is clipped.

Functions

func Blur

func Blur(p *Pixmap, sigmaX, sigmaY float32)

Blur blurs a premultiplied pixmap by a Gaussian of the given standard deviations, in pixels. Below two it convolves the kernel and from two up it is the three box blurs of SVG 1.1 15.17. Outside the pixmap is transparent.

Types

type BlendMode

type BlendMode int

BlendMode is one of the sixteen blend functions of ISO 32000-1 11.3.5, the same set SVG and CSS use. The first twelve are separable and run one component at a time; the last four take a color as a whole, through RGB.

const (
	BlendNormal BlendMode = iota
	BlendMultiply
	BlendScreen
	BlendOverlay
	BlendDarken
	BlendLighten
	BlendColorDodge
	BlendColorBurn
	BlendHardLight
	BlendSoftLight
	BlendDifference
	BlendExclusion
	BlendHue
	BlendSaturation
	BlendColor
	BlendLuminosity
)

The separable blend modes, then the four non-separable ones.

func (BlendMode) Separable

func (b BlendMode) Separable() bool

Separable reports whether the mode is a function of one component at a time.

func (BlendMode) String

func (b BlendMode) String() string

String returns the mode's name.

type Blitter

type Blitter interface {
	BlitSolid(x, y, w int, alpha uint8)
	BlitCover(x, y int, cover []uint8)
}

Blitter consumes the coverage a Rasterizer produces, one run at a time. The cover slice passed to BlitCover is reused and must not be retained.

type Cap

type Cap int

Cap is how a stroke ends, matching the PDF J operator.

const (
	CapButt Cap = iota
	CapRound
	CapSquare
	// CapTriangle has no PDF operator and no dot: it is here because other
	// formats have it and the stroker costs nothing to make it work.
	CapTriangle
)

Line caps.

type FillRule

type FillRule int

FillRule decides which parts of a self intersecting path are inside.

const (
	NonZero FillRule = iota
	EvenOdd
)

The two fill rules of ISO 32000-1 8.5.3.3.

type Flattener

type Flattener interface {
	MoveTo(x, y float32)
	LineTo(x, y float32)
	Close()
}

Flattener receives a path whose curves have been replaced by line segments.

type GlyphCache

type GlyphCache struct {
	// contains filtered or unexported fields
}

GlyphCache holds rendered glyph masks, bounded by their total size, and drops the least recently used when it is full.

func NewGlyphCache

func NewGlyphCache(max int) *GlyphCache

NewGlyphCache returns a cache holding at most max bytes of masks.

func (*GlyphCache) Clear

func (c *GlyphCache) Clear()

Clear empties the cache.

func (*GlyphCache) Get

func (c *GlyphCache) Get(k GlyphKey) *Pixmap

Get returns a cached mask, nil when there is none.

func (*GlyphCache) Put

func (c *GlyphCache) Put(k GlyphKey, mask *Pixmap)

Put adds a mask, which the cache then owns. A nil mask records that the glyph draws nothing, which is worth remembering too.

type GlyphKey

type GlyphKey struct {
	Font       any
	GID        int32
	A, B, C, D float32
	SubX, SubY uint8
	// Stroked and the pen below it identify the outline of a glyph that is
	// stroked rather than filled.
	Stroked           bool
	Width, MiterLimit float32
	StartCap, DashCap Cap
	EndCap            Cap
	Join              Join
}

GlyphKey identifies a rendered glyph mask: the font it came from, the glyph in it, the transform with the translation taken out, and the subpixel phase of the origin in quarter pixels.

type Gradient

type Gradient struct {
	// contains filtered or unexported fields
}

Gradient is a Shader over one of those: what a PDF type 2 or type 3 shading and an SVG linearGradient or radialGradient all evaluate to.

func NewGradient

func NewGradient(s GradientSpec) *Gradient

NewGradient prepares a gradient for drawing, nil if it degenerates: an axial gradient of no length, or a transform that does not invert.

func (*Gradient) Opaque

func (g *Gradient) Opaque() bool

Opaque reports that every entry of the table is fully opaque.

func (*Gradient) Shade

func (g *Gradient) Shade(x, y, w int, span []uint8)

Shade writes one color per pixel of the span, opaque where the gradient covers the point and clear where it does not.

func (*Gradient) ShadeRow

func (g *Gradient) ShadeRow(dst *Pixmap, x, y, w int)

ShadeRow writes the same colors straight into a destination row, in that pixmap's own shape, and leaves a pixel it does not cover alone.

type GradientSpec

type GradientSpec struct {
	Matrix Matrix
	LUT    []uint8
	// A is one opacity per entry of the table, and nil for a gradient that
	// is opaque throughout. LUT is premultiplied by it.
	A          []uint8
	N          int
	C0, C1     Point
	R0, R1     float32
	Radial     bool
	Ext0, Ext1 bool
}

GradientSpec describes an axial or radial gradient: the two circles it runs between (an axial one ignores the radii and runs between the points), the table of 256 colors of N components it takes its color from, the transform from its own space to the device, and whether it paints on past each end.

type Join

type Join int

Join is how two segments meet, matching the PDF j operator.

const (
	JoinMiter Join = iota
	JoinRound
	JoinBevel
)

Line joins.

type Matrix

type Matrix struct{ A, B, C, D, E, F float32 }

Matrix is an affine transform in PDF order: the six numbers of the cm operator, applied to a row vector, so x' = a*x + c*y + e.

func Concat

func Concat(m, n Matrix) Matrix

Concat returns the transform that applies m and then n.

func Rotate

func Rotate(deg float64) Matrix

Rotate turns by an angle in degrees, counterclockwise.

func Scale

func Scale(x, y float32) Matrix

Scale scales about the origin.

func Translate

func Translate(x, y float32) Matrix

Translate moves by x and y.

func (Matrix) Apply

func (m Matrix) Apply(p Point) Point

Apply transforms a point.

func (Matrix) ApplyRect

func (m Matrix) ApplyRect(r Rect) Rect

ApplyRect returns the bounding box of the transformed rectangle.

func (Matrix) Det

func (m Matrix) Det() float32

Det is the determinant, zero when the transform collapses to a line.

func (Matrix) Expansion

func (m Matrix) Expansion() float32

Expansion is the square root of the absolute determinant: how much a transform scales lengths on average, and what line width and flatness use.

func (Matrix) Invert

func (m Matrix) Invert() (Matrix, bool)

Invert returns the inverse transform. A matrix whose inverse a float32 cannot hold inverts to the identity, which keeps a degenerate CTM from taking coordinates to infinity.

func (Matrix) MaxExpansion

func (m Matrix) MaxExpansion() float32

MaxExpansion is the largest factor any direction is scaled by.

func (Matrix) UnapplyRect

func (m Matrix) UnapplyRect(r Rect) (Rect, bool)

UnapplyRect maps r back through the transform. The arithmetic is float64 because the answer is a difference of two products of the inverse, and under a transform that scales by a millionth those two are equal to seven figures: in float32 the whole answer is lost to the cancellation.

type Model

type Model interface {
	Components() int
	ToRGB(dst, src []uint8)
	FromRGB(dst, src []uint8)
}

Model is what raster needs to know about a color space: how many components it has, and how to get to and from RGB when something has to be shown or blended non separably.

var (
	// ModelGray, ModelRGB and ModelCMYK are the device spaces, here because
	// the non separable blend modes and the luminosity of a soft mask need
	// them without knowing anything about PDF.
	ModelGray Model = grayModel{}
	ModelRGB  Model = rgbModel{}
	ModelCMYK Model = cmykModel{}
)

type Paint

type Paint struct {
	// Color has the destination's N components, straight, not premultiplied.
	Color []uint8
	// Alpha is the constant alpha of the operation, 255 for opaque.
	Alpha uint8
	// Clip multiplies the coverage. It is an alpha only pixmap positioned by
	// its X and Y, and nil when nothing clips.
	Clip *Pixmap
}

Paint is the source color of a drawing operation and what modulates it.

type Path

type Path struct {
	// contains filtered or unexported fields
}

Path is a sequence of subpaths built from lines and cubic curves. The commands and the points are kept in two slices, which is compact and lets a path be reused across fills without reallocating.

func (*Path) Append

func (p *Path) Append(q *Path)

Append adds the segments of another path.

func (*Path) AsRect

func (p *Path) AsRect(m Matrix) (Rect, bool)

AsRect reports whether the path is one subpath that maps to an axis aligned rectangle under m, and returns it. Clipping to a rectangle is exact and costs nothing, so the caller wants to know.

func (*Path) Bounds

func (p *Path) Bounds(m Matrix) Rect

Bounds returns the bounding box of the path under m. Control points are included rather than the curve solved: the result is conservative, which is what every caller of a bounding box wants.

func (*Path) Clone

func (p *Path) Clone() *Path

Clone returns a copy that shares nothing with the original.

func (*Path) Close

func (p *Path) Close()

Close closes the current subpath. Closing an already closed subpath, or one that has not begun, does nothing.

func (*Path) Current

func (p *Path) Current() Point

Current returns the current point.

func (*Path) CurveTo

func (p *Path) CurveTo(x1, y1, x2, y2, x3, y3 float32)

CurveTo adds a cubic Bezier segment. A cubic whose control points sit on its ends is a straight line and is added as one; one that collapses onto a single point is nothing at all.

func (*Path) CurveToV

func (p *Path) CurveToV(x2, y2, x3, y3 float32)

CurveToV is the PDF v operator, whose first control point is the current one.

func (*Path) CurveToY

func (p *Path) CurveToY(x1, y1, x3, y3 float32)

CurveToY is the PDF y operator, whose second control point is its end point.

func (*Path) Flatten

func (p *Path) Flatten(m Matrix, tol float32, f Flattener)

Flatten walks the path under m, replacing every curve by line segments that stay within tol of it. A tol of zero means DefaultFlatness.

func (*Path) IsEmpty

func (p *Path) IsEmpty() bool

IsEmpty reports whether nothing has been added.

func (*Path) LineTo

func (p *Path) LineTo(x, y float32)

LineTo adds a straight segment. A path that begins with a line has an implicit move to its first point. A line to the point the path is already at is dropped unless a move put it there, where it is a subpath of its own that a round or a square cap paints as a dot.

func (*Path) MoveTo

func (p *Path) MoveTo(x, y float32)

MoveTo begins a new subpath.

func (*Path) Rect

func (p *Path) Rect(x, y, w, h float32)

Rect adds a closed rectangular subpath, the PDF re operator.

func (*Path) Reset

func (p *Path) Reset()

Reset empties the path, keeping the memory for the next one.

func (*Path) Start

func (p *Path) Start() Point

Start returns the first point of the current subpath.

func (*Path) StrokeBounds

func (p *Path) StrokeBounds(s *Stroke, m Matrix) Rect

StrokeBounds returns the bounding box of the path when stroked, padded by the line width and enough for a miter join.

func (*Path) Transform

func (p *Path) Transform(m Matrix) *Path

Transform returns a copy of the path with every point transformed.

func (*Path) Walk

func (p *Path) Walk(w Walker)

Walk replays the path into w.

type Pixmap

type Pixmap struct {
	W, H    int
	N       int
	Alpha   bool
	Stride  int
	X, Y    int
	Samples []uint8
	Model   Model
}

Pixmap is an interleaved 8 bit image of N color components and an optional alpha channel, premultiplied when there is one. X and Y are where its top left sample sits, and everything that composites into it works in those coordinates rather than in the pixmap's own, so that a group covering part of a page needs no transform of its own.

func NewMask

func NewMask(w, h int) *Pixmap

NewMask returns an alpha only pixmap, the shape a clip mask and a glyph take.

func NewPixmap

func NewPixmap(model Model, w, h int, alpha bool) *Pixmap

NewPixmap returns a zeroed pixmap, nil if the size does not fit in memory.

func (*Pixmap) BlendOver

func (p *Pixmap) BlendOver(src *Pixmap, alpha uint8, mode BlendMode)

BlendOver composites src onto p. src is premultiplied, carries an alpha channel and is positioned by its own X and Y; alpha scales it, and mode is the blend function against what p already holds.

func (*Pixmap) Blitter

func (p *Pixmap) Blitter(paint Paint) Blitter

Blitter returns a blitter that composites the paint into the pixmap under the coverage a Rasterizer produces.

func (*Pixmap) Bounds

func (p *Pixmap) Bounds() Rect

Bounds is the pixmap's place in device space.

func (*Pixmap) Clear

func (p *Pixmap) Clear()

Clear sets every sample to zero, which is transparent when there is an alpha channel and black when there is not.

func (*Pixmap) ClearWhite

func (p *Pixmap) ClearWhite()

ClearWhite sets the pixmap to opaque white, the background of a page.

func (*Pixmap) Comps

func (p *Pixmap) Comps() int

Comps is how many bytes one pixel takes, which is the color components and the alpha channel when there is one.

func (*Pixmap) Coverage

func (p *Pixmap) Coverage() *Pixmap

Coverage returns the first component of every pixel as an alpha only pixmap. A pixmap that already has one component is returned as it is.

func (*Pixmap) DrawMask

func (p *Pixmap) DrawMask(mask *Pixmap, paint Paint)

DrawMask composites the paint through an alpha mask, which its own X and Y place in the destination's coordinates. This is how a glyph is stamped.

func (*Pixmap) FillRect

func (p *Pixmap) FillRect(x0, y0, x1, y1 int, paint Paint)

FillRect composites a paint over a rectangle, in the coordinates the pixmap's own X and Y place it in.

func (*Pixmap) FillTriangle

func (p *Pixmap) FillTriangle(v0, v1, v2 Vertex)

FillTriangle fills a triangle, interpolating color linearly between its corners, and leaves the pixels it covers opaque. It does not anti-alias, because two triangles that share an edge have to meet without a seam; a mesh is anti-aliased at its own boundary instead, when it is composited.

func (*Pixmap) KnockoutOver

func (p *Pixmap) KnockoutOver(src *Pixmap, alpha uint8)

KnockoutOver composites src onto p the way an element of a knockout group does: where src covers a pixel it replaces what is there rather than layering over it, however little alpha it carries. alpha is the constant alpha the element was drawn with, which scales what it contributes but not how much of the backdrop it takes away.

func (*Pixmap) Mask

func (p *Pixmap) Mask(luminosity bool, table *[256]uint8) *Pixmap

Mask turns what a soft mask group drew into the alpha only pixmap a clip takes: the luminosity of each pixel, or the pixel's own alpha. table, when it is not nil, is a transfer function the result is read through.

func (*Pixmap) MaskBlitter

func (p *Pixmap) MaskBlitter() Blitter

MaskBlitter returns a blitter that writes coverage into an alpha only pixmap, replacing what is there. It writes in the pixmap's own coordinates, because what fills a mask has already been moved into them.

func (*Pixmap) MulImage

func (p *Pixmap) MulImage(src *Pixmap, inv Matrix)

MulImage multiplies an alpha only pixmap by the alpha of src through inv, which maps a pixel of p to one of src, and is how a stencil mask clips.

func (*Pixmap) MulMask

func (p *Pixmap) MulMask(m *Pixmap)

MulMask multiplies an alpha only pixmap by another, over the part they share in the coordinates their X and Y are in, and zeroes the rest. It is how a nested clip narrows the one it is nested in.

func (*Pixmap) Row

func (p *Pixmap) Row(y int) []uint8

Row returns the samples of one scanline.

func (*Pixmap) Subsample

func (p *Pixmap) Subsample(n int) *Pixmap

Subsample halves the pixmap n times with a box filter. Bringing a scan near its destination size before sampling it is both better looking and faster than point sampling the original.

type Point

type Point struct{ X, Y float32 }

Point is a position in whatever space the surrounding code is working in.

type Rasterizer

type Rasterizer struct {
	// contains filtered or unexported fields
}

Rasterizer turns paths into per pixel coverage. It is reused across paths: Reset, add geometry, Sweep.

func NewRasterizer

func NewRasterizer(w, h int) *Rasterizer

NewRasterizer returns a rasterizer for a w by h pixel target.

func (*Rasterizer) AddPath

func (r *Rasterizer) AddPath(p *Path, m Matrix)

AddPath flattens the path under m and adds it.

func (*Rasterizer) Bounds

func (r *Rasterizer) Bounds() (x0, y0, x1, y1 int)

Bounds returns the pixel rectangle the accumulated geometry touches, clamped to the target. It is conservative: an edge landing exactly on a pixel boundary counts.

func (*Rasterizer) Close

func (r *Rasterizer) Close()

Close closes the current subpath. Sweep closes it anyway; an explicit close only matters when more geometry follows.

func (*Rasterizer) Fill

func (r *Rasterizer) Fill(dst *Pixmap, rule FillRule, paint Paint)

Fill sweeps what the rasterizer has into a pixmap under the paint. It is Sweep with the blitter Blitter returns, through one the rasterizer keeps, so that filling many paths allocates nothing.

func (*Rasterizer) FillImage

func (r *Rasterizer) FillImage(dst, src *Pixmap, inv Matrix, paint Paint, smooth bool)

FillImage sweeps what the rasterizer has, reading color from src rather than from the paint. inv maps a destination pixel to a source pixel, and smooth chooses bilinear sampling over nearest.

A src with no color components is a stencil: the paint's color is painted through its alpha, which is how a one bit image mask draws.

func (*Rasterizer) FillShader

func (r *Rasterizer) FillShader(dst *Pixmap, rule FillRule, sh Shader, paint Paint)

FillShader sweeps what the rasterizer has into a pixmap, taking color from sh and everything else from the paint.

func (*Rasterizer) LineTo

func (r *Rasterizer) LineTo(x, y float32)

LineTo adds a segment to a device space point.

func (*Rasterizer) MoveTo

func (r *Rasterizer) MoveTo(x, y float32)

MoveTo begins a subpath at a device space point.

func (*Rasterizer) Reset

func (r *Rasterizer) Reset()

Reset drops the accumulated geometry, keeping the memory.

func (*Rasterizer) SetClip

func (r *Rasterizer) SetClip(box Rect)

SetClip restricts rasterization to the intersection of the target and box. It is not a clip mask: geometry outside is projected onto the boundary, which is what a bounding box clip means for coverage inside it.

func (*Rasterizer) SetFlatness

func (r *Rasterizer) SetFlatness(tol float32)

SetFlatness sets how far a flattened curve may stray from the true one, in pixels. Zero restores the default.

func (*Rasterizer) SetSize

func (r *Rasterizer) SetSize(w, h int)

SetSize sets the target size and clears any clip box.

func (*Rasterizer) Sweep

func (r *Rasterizer) Sweep(rule FillRule, b Blitter)

Sweep applies the fill rule and hands the coverage to b, scanline by scanline, top to bottom.

type Rect

type Rect struct{ X0, Y0, X1, Y1 float32 }

Rect is an axis aligned rectangle. X0,Y0 is the lower left corner in PDF user space and the upper left in device space; nothing here cares which.

func (Rect) AddPoint

func (r Rect) AddPoint(p Point) Rect

AddPoint returns the smallest rectangle containing r and p. It is min and max with no emptiness test, so that accumulating from EmptyRect works and a rectangle that has collapsed to a line or a point still grows correctly.

func (Rect) Contains

func (r Rect) Contains(s Rect) bool

Contains reports whether s lies entirely within r.

func (Rect) Intersect

func (r Rect) Intersect(s Rect) Rect

Intersect returns the overlap of two rectangles.

func (Rect) IsEmpty

func (r Rect) IsEmpty() bool

IsEmpty reports whether r contains no area.

func (Rect) IsInfinite

func (r Rect) IsInfinite() bool

IsInfinite reports whether r is the everything rectangle.

func (Rect) Normalized

func (r Rect) Normalized() Rect

Normalized returns r with its corners in the expected order.

func (Rect) Outer

func (r Rect) Outer() (x0, y0, x1, y1 int)

Outer returns the whole pixels r covers, and zeroes when it is empty.

func (Rect) Union

func (r Rect) Union(s Rect) Rect

Union returns the smallest rectangle containing both.

type RowShader

type RowShader interface {
	Shader
	ShadeRow(dst *Pixmap, x, y, w int)
}

A RowShader can write its color straight into a destination row, leaving the pixels it does not cover as they were, which a shader whose coverage is all or nothing can do instead of filling a span to be copied out of.

type Shader

type Shader interface {
	// Shade writes the color of w pixels starting at x, y into span: the
	// destination's color components and then one alpha for each pixel,
	// premultiplied by that alpha.
	Shade(x, y, w int, span []uint8)
}

Shader is a source of color for the pixels a Rasterizer covers, in place of the single color a Paint carries.

type Shrinker

type Shrinker struct {
	// contains filtered or unexported fields
}

A Shrinker halves rows as they arrive and cascades them through as many levels as Subsample would have used, so that an image may be reduced to the size it will be drawn at without the full size pixmap ever existing. What it returns is what Subsample would have built from that pixmap, byte for byte.

The caller fills the slice Row returns and calls Commit, once per row of the source, then takes the result from Pixmap.

func NewMaskShrinker

func NewMaskShrinker(w, h, n int) *Shrinker

NewMaskShrinker is NewShrinker for the one byte coverage NewMask returns.

func NewShrinker

func NewShrinker(model Model, w, h int, alpha bool, n int) *Shrinker

NewShrinker reduces a w by h image of the model's components n times.

func (*Shrinker) Commit

func (s *Shrinker) Commit()

Commit folds the row Row returned into the result.

func (*Shrinker) Pixmap

func (s *Shrinker) Pixmap() *Pixmap

Pixmap is the reduced image.

func (*Shrinker) Row

func (s *Shrinker) Row() []uint8

Row returns the buffer for the next source row, zeroed, which the caller fills and then commits. A row the caller leaves short reads as zero, which is what writing into a fresh pixmap did.

type Stroke

type Stroke struct {
	Width      float32
	MiterLimit float32
	StartCap   Cap
	DashCap    Cap
	EndCap     Cap
	Join       Join
	DashPhase  float32
	Dash       []float32
}

Stroke is the state the w, J, j, M and d operators set.

func DefaultStroke

func DefaultStroke() Stroke

DefaultStroke is the state a content stream starts with, ISO 32000-1 table 52.

func (*Stroke) Clone

func (s *Stroke) Clone() *Stroke

Clone returns a copy that shares no dash array with the original.

func (*Stroke) Outline

func (s *Stroke) Outline(p *Path, scale float32) *Path

Outline returns the path whose non-zero fill is the stroke of p. The path is stroked in its own space, so the caller transforms the result; scale is how much that transform magnifies lengths, and sets the flattening tolerance, the number of segments in an arc, and the width of a hairline.

func (*Stroke) OutlineInto

func (s *Stroke) OutlineInto(dst *Path, p *Path, scale float32) *Path

OutlineInto is Outline writing into dst, which it empties first, so that a caller stroking many paths can keep the memory.

func (*Stroke) SetCaps

func (s *Stroke) SetCaps(c Cap)

SetCaps sets all three caps, which is all the PDF J operator can express.

type Vertex

type Vertex struct {
	X, Y  float32
	Color [4]uint8
}

Vertex is a corner of a Gouraud shaded triangle: a point in the pixmap's own coordinates and a color of its components.

type Walker

type Walker interface {
	MoveTo(x, y float32)
	LineTo(x, y float32)
	CurveTo(x1, y1, x2, y2, x3, y3 float32)
	Close()
}

Walker receives the segments of a path in order.

Jump to

Keyboard shortcuts

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