mask

package
v0.0.9-alpha.8 Latest Latest
Warning

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

Go to latest
Published: Dec 4, 2024 License: MIT Imports: 7 Imported by: 7

Documentation

Overview

The mask subpackage defines the Rasterizer interface used within etxt and provides multiple ready-to-use implementations.

In this context, "Rasterizer" refers to a "glyph mask rasterizer": whenever we want to render text on a screen we first have to rasterize the individual font glyphs, extracted from font files as outlines (sets of lines and curves), and draw them into a raster image (a grid of pixels).

In short, this subpackage allows anyone to pick different rasterizers or implement their own by targeting the Rasterizer interface. This opens the door to the creation of cool effects that may modify the glyph outlines (e.g.: glyph expansion), the rasterization algorithms (e.g.: hinting), the resulting glyph masks (e.g.: blurring) or any combination of the previous.

That said, before you jump into the hype train, notice that some of these effects can also be achieved (often more easily) at later stages with shaders or custom blitting.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Rasterize

func Rasterize(outline sfnt.Segments, rasterizer Rasterizer, origin fract.Point) (*image.Alpha, error)

A low level method to rasterize glyph masks.

Returned masks have their coordinates adjusted so the mask is drawn at origin (0, 0) + the given fractional position by default. To draw it at a specific origin with a matching fractional position, translate the mask by origin.X.Floor() and origin.Y.Floor(). If you don't want to adjust the fractional pixel position, you can call this method with a zero-value fract.Point{}.

The given drawing coordinate can be your current drawing origin, but as indicated above, only its fractional part will be considered.

The image returned will be nil if the segments are empty or do not include any active lines or curves (e.g.: space glyphs).

Types

type DefaultRasterizer

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

The DefaultRasterizer is a wrapper to make golang.org/x/image/vector.Rasterizer conform to the Rasterizer interface.

func (*DefaultRasterizer) CubeTo

func (self *DefaultRasterizer) CubeTo(controlA, controlB, target fract.Point)

Creates a cubic Bézier curve to the given target passing through the given control points.

func (*DefaultRasterizer) LineTo

func (self *DefaultRasterizer) LineTo(point fract.Point)

Creates a straight boundary from the current position to the given point.

func (*DefaultRasterizer) MoveTo

func (self *DefaultRasterizer) MoveTo(point fract.Point)

Moves the current position to the given point.

func (*DefaultRasterizer) QuadTo

func (self *DefaultRasterizer) QuadTo(control, target fract.Point)

Creates a quadratic Bézier curve (also known as a conic Bézier curve) to the given target passing through the given control point.

func (*DefaultRasterizer) Rasterize

func (self *DefaultRasterizer) Rasterize(outline sfnt.Segments, origin fract.Point) (*image.Alpha, error)

Satisfies the Rasterizer interface.

func (*DefaultRasterizer) SetOnChangeFunc

func (self *DefaultRasterizer) SetOnChangeFunc(onChange func(Rasterizer))

Satisfies the Rasterizer interface.

func (*DefaultRasterizer) Signature

func (self *DefaultRasterizer) Signature() uint64

Satisfies the Rasterizer interface. The signature for the default rasterizer is always zero, but may be customized as you want through type embedding and method overriding.

type EdgeMarkerRasterizer

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

An alternative to DefaultRasterizer that avoids using golang.org/x/image/vector.Rasterizer under the hood. Results are visually very similar, but performance is 3 times worse.

The purpose of this rasterizer is to offer a simpler, more readable and well-documented version of the algorithm used by vector.Rasterizer that anyone can edit, adapt or learn from.

The zero-value will produce jaggy results, as curve segmentation parameters are not configured. Reasonable defaults can be set through EdgeMarkerRasterizer.SetCurveThreshold(0.1) and EdgeMarkerRasterizer.SetMaxCurveSplits(8).

func (*EdgeMarkerRasterizer) CubeTo

func (self *EdgeMarkerRasterizer) CubeTo(controlA, controlB, target fract.Point)

See DefaultRasterizer.CubeTo().

func (*EdgeMarkerRasterizer) LineTo

func (self *EdgeMarkerRasterizer) LineTo(point fract.Point)

See DefaultRasterizer.LineTo().

func (*EdgeMarkerRasterizer) MoveTo

func (self *EdgeMarkerRasterizer) MoveTo(point fract.Point)

See DefaultRasterizer.MoveTo().

func (*EdgeMarkerRasterizer) QuadTo

func (self *EdgeMarkerRasterizer) QuadTo(control, target fract.Point)

See DefaultRasterizer.QuadTo().

func (*EdgeMarkerRasterizer) Rasterize

func (self *EdgeMarkerRasterizer) Rasterize(outline sfnt.Segments, origin fract.Point) (*image.Alpha, error)

Satisfies the Rasterizer interface.

func (*EdgeMarkerRasterizer) SetCurveThreshold

func (self *EdgeMarkerRasterizer) SetCurveThreshold(threshold float64)

Sets the threshold distance to use when splitting Bézier curves into linear segments. If a linear segment misses the curve by more than the threshold value, the curve will be split. Otherwise, the linear segment will be used to approximate it.

Values very close to zero could prevent the algorithm from converging due to floating point instability, but the MaxCurveSplits cutoff will prevent infinite looping anyway.

Reasonable values range from 0.01 to 1.0. Values outside the [0, 6.5] range will be silently clamped. Precision is truncated to three decimal places. A good default in my experience is 0.1.

func (*EdgeMarkerRasterizer) SetMaxCurveSplits

func (self *EdgeMarkerRasterizer) SetMaxCurveSplits(maxCurveSplits int)

Sets the maximum amount of times a curve can be recursively split into subsegments while trying to approximate it.

The maximum number of segments that will approximate a curve is 2^maxCurveSplits.

This value is typically used as a cutoff to prevent low curve thresholds from making the curve splitting process too slow, but it can also be used creatively to get jaggy results instead of smooth curves.

Values outside the [0, 255] range will be silently clamped. Reasonable values range from 0 to 10. A good default in my experience is 8, but lower values will also work well if you don't need to draw big glyphs.

func (*EdgeMarkerRasterizer) SetOnChangeFunc

func (self *EdgeMarkerRasterizer) SetOnChangeFunc(onChange func(Rasterizer))

Satisfies the Rasterizer interface.

func (*EdgeMarkerRasterizer) Signature

func (self *EdgeMarkerRasterizer) Signature() uint64

Satisfies the Rasterizer interface. The signature for the edge marker rasterizer has the following shape:

  • 0xFF00000000000000 unused bits customizable through type embedding.
  • 0x00FF000000000000 bits being 0xE6 (self signature byte).
  • 0x0000FFFFFF000000 bits being zero, currently undefined.
  • 0x0000000000FFFFFF bits representing the curve segmenter configuration.

type FauxRasterizer

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

A rasterizer to draw oblique and faux-bold text. For high quality results, please use the font's italic and bold versions directly instead of these fake effects.

In general, the performance of FauxRasterizer without effects is very similar to DefaultRasterizer. Using reasonable skew factors for oblique text tends to increase the rasterization time around 15%, and using faux-bold increases the rasterization time in 60%, but it depends a lot on how extreme the effects are.

This rasterizer was created mostly to serve as an example of how to create modified rasterizers, featuring both modification of glyph control points (oblique) and post-processing of the generated mask (faux-bold).

func (*FauxRasterizer) CubeTo

func (self *FauxRasterizer) CubeTo(controlA, controlB, target fract.Point)

See DefaultRasterizer.CubeTo().

func (*FauxRasterizer) GetExtraWidth

func (self *FauxRasterizer) GetExtraWidth() float32

Gets the extra width (in pixels, possibly fractional) used for the faux-bold style.

func (*FauxRasterizer) GetSkewFactor

func (self *FauxRasterizer) GetSkewFactor() float32

Gets the skewing factor [-1.0, 1.0] used for the oblique style. See FauxRasterizer.SetSkewFactor() if you need details on how to interpret skew values.

func (*FauxRasterizer) LineTo

func (self *FauxRasterizer) LineTo(point fract.Point)

See DefaultRasterizer.LineTo().

func (*FauxRasterizer) MoveTo

func (self *FauxRasterizer) MoveTo(point fract.Point)

See DefaultRasterizer.MoveTo().

func (*FauxRasterizer) QuadTo

func (self *FauxRasterizer) QuadTo(control, target fract.Point)

See DefaultRasterizer.QuadTo().

func (*FauxRasterizer) Rasterize

func (self *FauxRasterizer) Rasterize(outline sfnt.Segments, origin fract.Point) (*image.Alpha, error)

Satisfies the Rasterizer interface.

func (*FauxRasterizer) SetAuxOnChangeFunc

func (self *FauxRasterizer) SetAuxOnChangeFunc(onChange func(*FauxRasterizer))

Like FauxRasterizer.SetOnChangeFunc, but not reserved for internal Renderer use. This is provided so you can link a custom sizer.Sizer to the rasterizer and get notified when its configuration changes.

func (*FauxRasterizer) SetExtraWidth

func (self *FauxRasterizer) SetExtraWidth(extraWidth float32)

Sets the extra width for the faux-bold. Values outside the [0, 1024] range will be clamped. Fractional values are allowed, but internally the decimal part will be quantized to 1/64ths of a pixel.

Important: when extra width is used for faux-bold, the glyphs will become wider. If you want to adapt the positioning of the glyphs to account for this widening, you can use a sizer.PaddedAdvanceSizer, link the rasterizer to it through FauxRasterizer.SetAuxOnChangeFunc() and update the padding with the value of FauxRasterizer.GetExtraWidth(), for example.

func (*FauxRasterizer) SetOnChangeFunc

func (self *FauxRasterizer) SetOnChangeFunc(onChange func(Rasterizer))

Satisfies the Rasterizer interface.

func (*FauxRasterizer) SetSkewFactor

func (self *FauxRasterizer) SetSkewFactor(factor float32)

Sets the oblique skewing factor, which is expected to be in [-1, 1]. Values outside this range will be silently clamped.

This factor is internally defined to represent skews ranging from 45 to -45 degrees. Some practical examples:

  • A skew factor of -1 will rasterize glyphs tilted 45 degrees left (backwards leaning).
  • A skew factor of 1 will rasterize glyphs tilted 45 degrees right (forwards leaning).
  • A skew factor of 0 will rasterize glyphs without any tilt.
  • A skew factor of 0.5 will rasterize glyphs tilted 22.5 degrees right (forwards leaning).

Most italic fonts have an angle between 6 and 9 degrees, which correspond to skew factors in the [0.13, 0.2] range.

func (*FauxRasterizer) Signature

func (self *FauxRasterizer) Signature() uint64

Satisfies the Rasterizer interface. The signature for the faux rasterizer has the following shape:

  • 0xFF00000000000000 unused bits customizable through type embedding.
  • 0x00FF000000000000 bits being 0xFA (self signature byte).
  • 0x0000F00000000000 bits being 0x1 if italics are enabled.
  • 0x00000F0000000000 bits being 0xB if bold is enabled.
  • 0x000000FF00000000 bits being zero, currently undefined.
  • 0x00000000FFFF0000 bits encoding the skew [-1, 1] in the [0, 65535] range, with the "zero skew" not having a representation (signatures are still different due to the "italics-enabled" flag).
  • 0x000000000000FFFF bits encoding the extra bold width in 64ths of a pixel and encoded in a uint16.

type Rasterizer

type Rasterizer interface {
	// Rasterizes the given outline to an alpha mask. The outline must be
	// drawn at the given fractional position (always positive coords between
	// 0 and 0:63 (= 0.984375)).
	//
	// Notice that rasterizers might create masks bigger than Segments.Bounds()
	// to account for their own special effects, but they still can't affect
	// glyph bounds or advances (see sizer.Sizer for that).
	Rasterize(sfnt.Segments, fract.Point) (*image.Alpha, error)

	// The signature returns a uint64 that can be used with glyph caches
	// in order to tell rasterizers apart. When using multiple mask
	// rasterizers with a single cache, you normally want to make sure
	// that their signatures are different.
	Signature() uint64

	// Sets the function to be called when the Rasterizer configuration
	// or the signature change. This is a reserved function that only a
	// Renderer should call internally in order to connect its cache
	// handler to the rasterizer changes.
	SetOnChangeFunc(func(Rasterizer))
}

Rasterizer is an interface for 2D vector graphics rasterization to an alpha mask. This interface is offered as an open alternative to the concrete golang.org/x/image/vector.Rasterizer type (as used by golang.org/x/image/font/opentype), allowing anyone to target it and use its own rasterizer for text rendering.

Mask rasterizers can't be used concurrently and must tolerate coordinates out of bounds.

type SharpRasterizer

type SharpRasterizer struct{ DefaultRasterizer }

A rasterizer that quantizes all glyph mask values to fully opaque or fully transparent. Its primary use-case is to make scaled pixel art fonts look sharper through the elimination of blurry edges.

Since the implementation leverages type embedding, the available methods are the same as the ones for DefaultRasterizer, even if they do not appear explicitly in the documentation.

func (*SharpRasterizer) Rasterize

func (self *SharpRasterizer) Rasterize(outline sfnt.Segments, origin fract.Point) (*image.Alpha, error)

Satisfies the Rasterizer interface.

func (*SharpRasterizer) Signature

func (self *SharpRasterizer) Signature() uint64

Satisfies the Rasterizer interface.

type SharperRasterizer

type SharperRasterizer struct{ DefaultRasterizer }

A variant of SharpRasterizer, with more complex evaluations of what should be or not be a solid pixel. This process is executed on the CPU; an ideal implementation for Ebitengine would perform a similar process through a shader instead. As of right now, this is offered mostly as a proof of concept.

func (*SharperRasterizer) Rasterize

func (self *SharperRasterizer) Rasterize(outline sfnt.Segments, origin fract.Point) (*image.Alpha, error)

Satisfies the Rasterizer interface.

func (*SharperRasterizer) Signature

func (self *SharperRasterizer) Signature() uint64

Satisfies the Rasterizer interface.

Jump to

Keyboard shortcuts

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