Documentation ¶
Overview ¶
The emask 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 ¶
- func Rasterize(outline sfnt.Segments, rasterizer Rasterizer, dot fixed.Point26_6) (*image.Alpha, error)
- type DefaultRasterizer
- func (self *DefaultRasterizer) CacheSignature() uint64
- func (self *DefaultRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6)
- func (self *DefaultRasterizer) LineTo(point fixed.Point26_6)
- func (self *DefaultRasterizer) MoveTo(point fixed.Point26_6)
- func (self *DefaultRasterizer) QuadTo(control, target fixed.Point26_6)
- func (self *DefaultRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*image.Alpha, error)
- func (self *DefaultRasterizer) SetHighByte(value uint8)
- func (self *DefaultRasterizer) SetOnChangeFunc(onChange func(Rasterizer))
- type EdgeMarkerRasterizer
- func (self *EdgeMarkerRasterizer) CacheSignature() uint64
- func (self *EdgeMarkerRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6)
- func (self *EdgeMarkerRasterizer) LineTo(point fixed.Point26_6)
- func (self *EdgeMarkerRasterizer) MoveTo(point fixed.Point26_6)
- func (self *EdgeMarkerRasterizer) QuadTo(control, target fixed.Point26_6)
- func (self *EdgeMarkerRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*image.Alpha, error)
- func (self *EdgeMarkerRasterizer) SetCurveThreshold(threshold float32)
- func (self *EdgeMarkerRasterizer) SetHighByte(value uint8)
- func (self *EdgeMarkerRasterizer) SetMaxCurveSplits(maxCurveSplits int)
- func (self *EdgeMarkerRasterizer) SetOnChangeFunc(onChange func(Rasterizer))
- type FauxRasterizer
- func (self *FauxRasterizer) CacheSignature() uint64
- func (self *FauxRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6)
- func (self *FauxRasterizer) GetExtraWidth() float64
- func (self *FauxRasterizer) GetSkewFactor() float64
- func (self *FauxRasterizer) LineTo(point fixed.Point26_6)
- func (self *FauxRasterizer) MoveTo(point fixed.Point26_6)
- func (self *FauxRasterizer) QuadTo(control, target fixed.Point26_6)
- func (self *FauxRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*image.Alpha, error)
- func (self *FauxRasterizer) SetAuxOnChangeFunc(onChange func(*FauxRasterizer))
- func (self *FauxRasterizer) SetExtraWidth(extraWidth float64)
- func (self *FauxRasterizer) SetHighByte(value uint8)
- func (self *FauxRasterizer) SetOnChangeFunc(onChange func(Rasterizer))
- func (self *FauxRasterizer) SetSkewFactor(factor float64)
- type OutlineRasterizer
- func (self *OutlineRasterizer) CacheSignature() uint64
- func (self *OutlineRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6)
- func (self *OutlineRasterizer) LineTo(point fixed.Point26_6)
- func (self *OutlineRasterizer) MoveTo(point fixed.Point26_6)
- func (self *OutlineRasterizer) QuadTo(control, target fixed.Point26_6)
- func (self *OutlineRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*image.Alpha, error)
- func (self *OutlineRasterizer) SetHighByte(value uint8)
- func (self *OutlineRasterizer) SetMarginFactor(factor float64)
- func (self *OutlineRasterizer) SetOnChangeFunc(onChange func(Rasterizer))
- func (self *OutlineRasterizer) SetThickness(thickness float64)
- type Rasterizer
- type Shape
- func (self *Shape) CubeTo(cx1, cy1, cx2, cy2, x, y int)
- func (self *Shape) CubeToFract(cx1, cy1, cx2, cy2, x, y fixed.Int26_6)
- func (self *Shape) HasInvertY() bool
- func (self *Shape) InvertY(active bool)
- func (self *Shape) LineTo(x, y int)
- func (self *Shape) LineToFract(x, y fixed.Int26_6)
- func (self *Shape) MoveTo(x, y int)
- func (self *Shape) MoveToFract(x, y fixed.Int26_6)
- func (self *Shape) Paint(drawColor, backColor color.Color) *image.RGBA
- func (self *Shape) QuadTo(ctrlX, ctrlY, x, y int)
- func (self *Shape) QuadToFract(ctrlX, ctrlY, x, y fixed.Int26_6)
- func (self *Shape) Reset()
- func (self *Shape) Segments() sfnt.Segments
- type UserCfgCacheSignature
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Rasterize ¶
func Rasterize(outline sfnt.Segments, rasterizer Rasterizer, dot fixed.Point26_6) (*image.Alpha, error)
A low level method to rasterize glyph masks.
Returned masks have their coordinates adjusted so the mask is drawn at dot origin (0, 0) + the given fractional position by default. To draw it at a specific dot with a matching fractional position, translate the mask by dot.X.Floor() and dot.Y.Floor(). If you don't want to adjust the fractional pixel position, you can call Rasterize with a zero-value fixed.Point26_6{}.
The given drawing coordinate can be your current drawing dot, 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) CacheSignature ¶
func (self *DefaultRasterizer) CacheSignature() uint64
Satisfies the Rasterizer interface.
func (*DefaultRasterizer) CubeTo ¶
func (self *DefaultRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6)
Creates a cubic Bézier curve to the given target passing through the given control points.
func (*DefaultRasterizer) LineTo ¶
func (self *DefaultRasterizer) LineTo(point fixed.Point26_6)
Creates a straight boundary from the current position to the given point.
func (*DefaultRasterizer) MoveTo ¶
func (self *DefaultRasterizer) MoveTo(point fixed.Point26_6)
Moves the current position to the given point.
func (*DefaultRasterizer) QuadTo ¶
func (self *DefaultRasterizer) QuadTo(control, target fixed.Point26_6)
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, fract fixed.Point26_6) (*image.Alpha, error)
Satisfies the Rasterizer interface.
func (*DefaultRasterizer) SetHighByte ¶
func (self *DefaultRasterizer) SetHighByte(value uint8)
Satisfies the UserCfgCacheSignature interface.
func (*DefaultRasterizer) SetOnChangeFunc ¶
func (self *DefaultRasterizer) SetOnChangeFunc(onChange func(Rasterizer))
Satisfies the Rasterizer interface.
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 is usable but will produce jaggy results, as curve segmentation parameters are not configured. Use NewStdEdgeMarkerRasterizer() if you prefer a pre-configured rasterizer. You may also configure the rasterizer manually through EdgeMarkerRasterizer.SetCurveThreshold() and EdgeMarkerRasterizer.SetMaxCurveSplits().
func NewStdEdgeMarkerRasterizer ¶
func NewStdEdgeMarkerRasterizer() *EdgeMarkerRasterizer
Creates a new EdgeMarkerRasterizer with reasonable default values.
func (*EdgeMarkerRasterizer) CacheSignature ¶
func (self *EdgeMarkerRasterizer) CacheSignature() uint64
Satisfies the Rasterizer interface.
func (*EdgeMarkerRasterizer) CubeTo ¶
func (self *EdgeMarkerRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6)
See DefaultRasterizer.CubeTo().
func (*EdgeMarkerRasterizer) LineTo ¶
func (self *EdgeMarkerRasterizer) LineTo(point fixed.Point26_6)
See DefaultRasterizer.LineTo().
func (*EdgeMarkerRasterizer) MoveTo ¶
func (self *EdgeMarkerRasterizer) MoveTo(point fixed.Point26_6)
See DefaultRasterizer.MoveTo().
func (*EdgeMarkerRasterizer) QuadTo ¶
func (self *EdgeMarkerRasterizer) QuadTo(control, target fixed.Point26_6)
See DefaultRasterizer.QuadTo().
func (*EdgeMarkerRasterizer) Rasterize ¶
func (self *EdgeMarkerRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*image.Alpha, error)
Satisfies the Rasterizer interface.
func (*EdgeMarkerRasterizer) SetCurveThreshold ¶
func (self *EdgeMarkerRasterizer) SetCurveThreshold(threshold float32)
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. NewStdEdgeMarkerRasterizer() uses 0.1 by default.
func (*EdgeMarkerRasterizer) SetHighByte ¶
func (self *EdgeMarkerRasterizer) SetHighByte(value uint8)
Satisfies the UserCfgCacheSignature interface.
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. NewStdEdgeMarkerRasterizer() uses 8 by default.
func (*EdgeMarkerRasterizer) SetOnChangeFunc ¶
func (self *EdgeMarkerRasterizer) SetOnChangeFunc(onChange func(Rasterizer))
Satisfies the Rasterizer interface.
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) CacheSignature ¶
func (self *FauxRasterizer) CacheSignature() uint64
Satisfies the Rasterizer interface. The cache signature for the faux rasterizer has the following shape:
- 0xFF00000000000000 bits for UserCfgCacheSignature's high byte.
- 0x00FF000000000000 bits being 0xFA (self signature byte).
- 0x0000F00000000000 bits being 0x1 if italics are enabled.
- 0x00000F0000000000 bits being 0xB if bold is enabled.
- 0x00000000FFFF0000 bits encoding the skewing [-1, 1] as [0, 65535], with the zero skewing not having a representation here (signatures are still different due to the "italics-enabled" flag).
- 0x000000000000FFFF bits encoding the extra bold width in 64ths of a pixel and encoded as a uint16.
func (*FauxRasterizer) CubeTo ¶
func (self *FauxRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6)
See DefaultRasterizer.CubeTo().
func (*FauxRasterizer) GetExtraWidth ¶
func (self *FauxRasterizer) GetExtraWidth() float64
Gets the extra width (in pixels, possibly fractional) used for the faux-bold style.
func (*FauxRasterizer) GetSkewFactor ¶
func (self *FauxRasterizer) GetSkewFactor() float64
Gets the skewing factor [-1.0, 1.0] used for the oblique style.
func (*FauxRasterizer) LineTo ¶
func (self *FauxRasterizer) LineTo(point fixed.Point26_6)
See DefaultRasterizer.LineTo().
func (*FauxRasterizer) MoveTo ¶
func (self *FauxRasterizer) MoveTo(point fixed.Point26_6)
See DefaultRasterizer.MoveTo().
func (*FauxRasterizer) QuadTo ¶
func (self *FauxRasterizer) QuadTo(control, target fixed.Point26_6)
See DefaultRasterizer.QuadTo().
func (*FauxRasterizer) Rasterize ¶
func (self *FauxRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*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 esizer.Sizer to the rasterizer and get notified when its configuration changes.
func (*FauxRasterizer) SetExtraWidth ¶
func (self *FauxRasterizer) SetExtraWidth(extraWidth float64)
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 an esizer.AdvancePadSizer, link the rasterizer to it through SetAuxOnChangeFunc and update the padding with the value of FauxRasterizer.GetExtraWidth(), for example.
func (*FauxRasterizer) SetHighByte ¶
func (self *FauxRasterizer) SetHighByte(value uint8)
Satisfies the UserCfgCacheSignature interface.
func (*FauxRasterizer) SetOnChangeFunc ¶
func (self *FauxRasterizer) SetOnChangeFunc(onChange func(Rasterizer))
Satisfies the Rasterizer interface.
func (*FauxRasterizer) SetSkewFactor ¶
func (self *FauxRasterizer) SetSkewFactor(factor float64)
Sets the oblique skewing factor. Values outside the [-1, 1] range will be clamped. -1 corresponds to a counter-clockwise angle of 45 degrees from the vertical. 1 corresponds to -45 degrees.
In general, most italic fonts have an italic angle between -6 and -9 degrees, which would correspond to skew factors in the [0.13, 0.2] range.
type OutlineRasterizer ¶
type OutlineRasterizer struct {
// contains filtered or unexported fields
}
NOTICE: work in progress. There are a couple big clipping issues that will easily cause panics, and most likely still a few minor bugs on polygon filling edge cases. Clipping is tricky due to Bézier cusps and similar situations where two lines end up joining at very tight angles, but also in some edge cases where natural path intersections will go outside the intended paths area due to thickness becoming larger than path length and multiple paths colliding and stuff.
The algorithm is also quite slow and there's much room for improvement, but I'm still focusing on the baseline implementation.
In web API terms, the line cap is "butt" and the line joint is "miter".
func NewOutlineRasterizer ¶
func NewOutlineRasterizer(outlineThickness float64) *OutlineRasterizer
func (*OutlineRasterizer) CacheSignature ¶
func (self *OutlineRasterizer) CacheSignature() uint64
Satisfies the Rasterizer interface.
func (*OutlineRasterizer) CubeTo ¶
func (self *OutlineRasterizer) CubeTo(controlA, controlB, target fixed.Point26_6)
Satisfies the unexported vectorTracer interface.
func (*OutlineRasterizer) LineTo ¶
func (self *OutlineRasterizer) LineTo(point fixed.Point26_6)
Satisfies the unexported vectorTracer interface.
func (*OutlineRasterizer) MoveTo ¶
func (self *OutlineRasterizer) MoveTo(point fixed.Point26_6)
Satisfies the unexported vectorTracer interface.
func (*OutlineRasterizer) QuadTo ¶
func (self *OutlineRasterizer) QuadTo(control, target fixed.Point26_6)
Satisfies the unexported vectorTracer interface.
func (*OutlineRasterizer) Rasterize ¶
func (self *OutlineRasterizer) Rasterize(outline sfnt.Segments, fract fixed.Point26_6) (*image.Alpha, error)
Satisfies the Rasterizer interface.
func (*OutlineRasterizer) SetHighByte ¶
func (self *OutlineRasterizer) SetHighByte(value uint8)
Satisfies the UserCfgCacheSignature interface.
func (*OutlineRasterizer) SetMarginFactor ¶
func (self *OutlineRasterizer) SetMarginFactor(factor float64)
When two lines of the outline connect at a tight angle, the resulting vertex may extend far beyond 'thickness' distance. The margin factor allows setting a limit, in multiples of 'thickness', to adjust the paths so they don't extend further away than intended.
The default value is 2. Valid values range from 1 to 16.
func (*OutlineRasterizer) SetOnChangeFunc ¶
func (self *OutlineRasterizer) SetOnChangeFunc(onChange func(Rasterizer))
Satisfies the Rasterizer interface.
func (*OutlineRasterizer) SetThickness ¶
func (self *OutlineRasterizer) SetThickness(thickness float64)
Sets the outline thickness. Values must be in the [0.1, 1024] range.
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 esizer.Sizer for that). Rasterize(sfnt.Segments, fixed.Point26_6) (*image.Alpha, error) // The cache signature returns an 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 cache signatures are different. As a practical standard, // implementers of mask rasterizers are encouraged to leave at least // the 8 highest bits to be configurable by users through the // UserCfgCacheSignature interface. CacheSignature() uint64 // Sets the function to be called when the Rasterizer configuration // or cache signature changes. 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 Shape ¶
type Shape struct {
// contains filtered or unexported fields
}
A helper type to assist the creation of shapes that can later be converted to sfnt.Segments and rasterized with the Rasterize() method. Notice that this is actually unrelated to fonts, but once you have some rasterizers it's nice to have a way to play with them manually. Notice also that since Rasterize() is a CPU process, working with big shapes (based on their bounding rectangle) can be quite expensive.
Despite what the names of the methods might lead you to believe, shapes are not created by "drawing lines", but rather by defining a set of boundaries that enclose an area. If you get unexpected results using shapes, come back to think about this.
Shapes by themselves do not care about the direction you use to define the segments (clockwise/counter-clockwise), but rasterizers that use the segments most often do. For example, if you define two squares one inside the other, both in the same order (e.g: top-left to top-right, top-right to bottom right...) the rasterized result will be a single square. If you define them following opposite directions, instead, the result will be the difference between the two squares.
func NewShape ¶
Creates a new Shape object. The commandsCount is used to indicate the initial capacity of its internal segments buffer.
func (*Shape) CubeTo ¶
Creates a cubic Bézier curve to (x, y) with (cx1, cy1) and (cx2, cy2) as the control points. See golang.org/x/image/vector.Rasterizer operations and golang.org/x/image/font/sfnt.Segment.
func (*Shape) CubeToFract ¶
Like Shape.CubeTo, but with fixed.Int26_6 coordinates.
func (*Shape) HasInvertY ¶
Returns whether Shape.InvertY is active or inactive.
func (*Shape) InvertY ¶
Let's say you want to draw a triangle pointing up, similar to an "A". By default, you would move to (0, 0) and then draw lines to (k, 2*k), (2*k, 0) and back to (0, 0).
If you set InvertY to true, the previous shape will draw a triangle pointing down instead, similar to a "V". This is a convenient flag that makes it easier to work on different contexts (e.g., font glyphs are defined with the ascenders going into the negative y plane).
InvertY can also be used creatively or to switch between clockwise and counter-clockwise directions when drawing symmetrical shapes that have their center at (0, 0).
func (*Shape) LineTo ¶
Creates a straight boundary from the current position to (x, y). See golang.org/x/image/vector.Rasterizer operations and golang.org/x/image/font/sfnt.Segment.
func (*Shape) LineToFract ¶
Like Shape.LineTo, but with fixed.Int26_6 coordinates.
func (*Shape) MoveTo ¶
Moves the current position to (x, y). See golang.org/x/image/vector.Rasterizer operations and golang.org/x/image/font/sfnt.Segment.
func (*Shape) MoveToFract ¶
Like Shape.MoveTo, but with fixed.Int26_6 coordinates.
func (*Shape) Paint ¶
A helper method to rasterize the current shape with the default rasterizer. You could then export the result to a png file, e.g.:
file, _ := os.Create("my_ugly_shape.png") _ = png.Encode(file, shape.Paint(color.White, color.Black)) // ...maybe even checking errors and closing the file ;)
func (*Shape) QuadTo ¶
Creates a quadratic Bézier curve (also known as a conic Bézier curve) to (x, y) with (ctrlX, ctrlY) as the control point. See golang.org/x/image/vector.Rasterizer operations and golang.org/x/image/font/sfnt.Segment.
func (*Shape) QuadToFract ¶
Like Shape.QuadTo, but with fixed.Int26_6 coordinates.
func (*Shape) Reset ¶
func (self *Shape) Reset()
Resets the shape segments. Be careful to not be holding the segments from Shape.Segments() when calling this (they may be overriden soon).
type UserCfgCacheSignature ¶
type UserCfgCacheSignature interface { // Sets the highest byte of 'signature' to the given value, like: // signature = (signature & 0x00FFFFFFFFFFFFFF) | (uint64(value) << 56) SetHighByte(value uint8) }
See Rasterizer's CacheSignature() documentation.