text/glyph_outline.go

Functions Structs

Functions

func Clone

Clone creates a deep copy of the outline.

func (o *GlyphOutline) Clone() *GlyphOutline {
	if o == nil {
		return nil
	}

	clone := &GlyphOutline{
		Segments:	make([]OutlineSegment, len(o.Segments)),
		Bounds:		o.Bounds,
		Advance:	o.Advance,
		LSB:		o.LSB,
		GID:		o.GID,
		Type:		o.Type,
	}
	copy(clone.Segments, o.Segments)
	return clone
}

func Error

func (e *FontError) Error() string {
	return "text: " + e.Reason
}

func ExtractOutline

ExtractOutline extracts the outline for a glyph at the given size.

The size is in pixels (ppem - pixels per em).

Returns nil if the glyph has no outline (e.g., space character).

func (e *OutlineExtractor) ExtractOutline(parsedFont ParsedFont, gid GlyphID, size float64) (*GlyphOutline, error) {
	return e.ExtractOutlineHinted(parsedFont, gid, size, HintingNone)
}

func ExtractOutlineHinted

ExtractOutlineHinted extracts the outline for a glyph at the given size

with the specified hinting mode.

 

When hinting is enabled:

- Advance widths are grid-fitted to integer pixel boundaries (via sfnt)

- Y-coordinates of horizontal segments are snapped to pixel grid

(crisp baselines, x-heights, cap-heights)

- HintingVertical snaps only Y-coordinates (horizontal stems)

- HintingFull snaps both X and Y coordinates

 

Hinting should be disabled for rotated/scaled text where grid-fitting

doesn't apply (the pixel grid is no longer axis-aligned).

func (e *OutlineExtractor) ExtractOutlineHinted(parsedFont ParsedFont, gid GlyphID, size float64, hinting Hinting) (*GlyphOutline, error) {
	xiFont, ok := parsedFont.(*ximageParsedFont)
	if !ok {
		return nil, ErrUnsupportedFontType
	}

	outline, err := e.extractFromSFNT(xiFont.font, gid, size, hinting)
	if err != nil {
		return nil, err
	}

	if outline == nil || hinting == HintingNone {
		return outline, nil
	}

	gridFitOutline(outline, hinting)
	return outline, nil
}

func IdentityTransform

IdentityTransform returns the identity transformation.

func IdentityTransform() *AffineTransform {
	return &AffineTransform{A: 1, D: 1}
}

func IsEmpty

IsEmpty returns true if the outline has no segments.

func (o *GlyphOutline) IsEmpty() bool {
	return len(o.Segments) == 0
}

func Multiply

Multiply returns the composition of two transformations.

func (m *AffineTransform) Multiply(other *AffineTransform) *AffineTransform {
	return &AffineTransform{
		A:	m.A*other.A + m.B*other.C,
		B:	m.A*other.B + m.B*other.D,
		C:	m.C*other.A + m.D*other.C,
		D:	m.C*other.B + m.D*other.D,
		Tx:	m.A*other.Tx + m.B*other.Ty + m.Tx,
		Ty:	m.C*other.Tx + m.D*other.Ty + m.Ty,
	}
}

func NewOutlineExtractor

NewOutlineExtractor creates a new outline extractor.

func NewOutlineExtractor() *OutlineExtractor {
	return &OutlineExtractor{}
}

func Scale

Scale returns a new outline with all coordinates scaled by the given factor.

func (o *GlyphOutline) Scale(factor float32) *GlyphOutline {
	if o == nil {
		return nil
	}

	scaled := &GlyphOutline{
		Segments:	make([]OutlineSegment, len(o.Segments)),
		Bounds: Rect{
			MinX:	o.Bounds.MinX * float64(factor),
			MinY:	o.Bounds.MinY * float64(factor),
			MaxX:	o.Bounds.MaxX * float64(factor),
			MaxY:	o.Bounds.MaxY * float64(factor),
		},
		Advance:	o.Advance * factor,
		LSB:		o.LSB * factor,
		GID:		o.GID,
		Type:		o.Type,
	}

	for i, seg := range o.Segments {
		scaled.Segments[i] = OutlineSegment{
			Op:	seg.Op,
			Points: [3]OutlinePoint{
				{X: seg.Points[0].X * factor, Y: seg.Points[0].Y * factor},
				{X: seg.Points[1].X * factor, Y: seg.Points[1].Y * factor},
				{X: seg.Points[2].X * factor, Y: seg.Points[2].Y * factor},
			},
		}
	}

	return scaled
}

func ScaleTransform

ScaleTransform returns a scaling transformation.

func ScaleTransform(sx, sy float32) *AffineTransform {
	return &AffineTransform{A: sx, D: sy}
}

func SegmentCount

SegmentCount returns the number of segments in the outline.

func (o *GlyphOutline) SegmentCount() int {
	return len(o.Segments)
}

func String

String returns a string representation of the operation.

func (op OutlineOp) String() string {
	switch op {
	case OutlineOpMoveTo:
		return "MoveTo"
	case OutlineOpLineTo:
		return "LineTo"
	case OutlineOpQuadTo:
		return "QuadTo"
	case OutlineOpCubicTo:
		return "CubicTo"
	default:
		return "Unknown"
	}
}

func Transform

Transform returns a new outline with all coordinates transformed.

func (o *GlyphOutline) Transform(m *AffineTransform) *GlyphOutline {
	if o == nil || m == nil {
		return o.Clone()
	}

	transformed := &GlyphOutline{
		Segments:	make([]OutlineSegment, len(o.Segments)),
		Advance:	o.Advance,
		LSB:		o.LSB,
		GID:		o.GID,
		Type:		o.Type,
	}

	// Transform all segments and compute new bounds
	minX, minY := float32(1e10), float32(1e10)
	maxX, maxY := float32(-1e10), float32(-1e10)

	for i, seg := range o.Segments {
		transformed.Segments[i] = OutlineSegment{Op: seg.Op}

		pointCount := 1
		switch seg.Op {
		case OutlineOpMoveTo, OutlineOpLineTo:
			pointCount = 1
		case OutlineOpQuadTo:
			pointCount = 2
		case OutlineOpCubicTo:
			pointCount = 3
		}

		for j := 0; j < pointCount; j++ {
			x, y := m.TransformPoint(seg.Points[j].X, seg.Points[j].Y)
			transformed.Segments[i].Points[j] = OutlinePoint{X: x, Y: y}

			updateMinMax(x, y, &minX, &minY, &maxX, &maxY)
		}
	}

	if len(o.Segments) > 0 {
		transformed.Bounds = Rect{
			MinX:	float64(minX),
			MinY:	float64(minY),
			MaxX:	float64(maxX),
			MaxY:	float64(maxY),
		}
	}

	return transformed
}

func TransformPoint

TransformPoint applies the transformation to a point.

func (m *AffineTransform) TransformPoint(x, y float32) (float32, float32) {
	return m.A*x + m.B*y + m.Tx, m.C*x + m.D*y + m.Ty
}

func Translate

Translate returns a new outline with all coordinates translated by (dx, dy).

func (o *GlyphOutline) Translate(dx, dy float32) *GlyphOutline {
	if o == nil {
		return nil
	}

	translated := &GlyphOutline{
		Segments:	make([]OutlineSegment, len(o.Segments)),
		Bounds: Rect{
			MinX:	o.Bounds.MinX + float64(dx),
			MinY:	o.Bounds.MinY + float64(dy),
			MaxX:	o.Bounds.MaxX + float64(dx),
			MaxY:	o.Bounds.MaxY + float64(dy),
		},
		Advance:	o.Advance,
		LSB:		o.LSB,
		GID:		o.GID,
		Type:		o.Type,
	}

	for i, seg := range o.Segments {
		translated.Segments[i] = OutlineSegment{
			Op:	seg.Op,
			Points: [3]OutlinePoint{
				{X: seg.Points[0].X + dx, Y: seg.Points[0].Y + dy},
				{X: seg.Points[1].X + dx, Y: seg.Points[1].Y + dy},
				{X: seg.Points[2].X + dx, Y: seg.Points[2].Y + dy},
			},
		}
	}

	return translated
}

func TranslateTransform

TranslateTransform returns a translation transformation.

func TranslateTransform(tx, ty float32) *AffineTransform {
	return &AffineTransform{A: 1, D: 1, Tx: tx, Ty: ty}
}

Structs

type OutlinePoint struct

OutlinePoint represents a point in a glyph outline.

All coordinates are in font units and should be scaled by size/unitsPerEm.

type OutlinePoint struct {
	X, Y float32
}

type OutlineSegment struct

OutlineSegment represents a segment of a glyph outline.

type OutlineSegment struct {
	// Op is the segment operation type.
	Op	OutlineOp

	// Points contains the control and end points for this segment.
	// - MoveTo: Points[0] is the target point
	// - LineTo: Points[0] is the target point
	// - QuadTo: Points[0] is control, Points[1] is target
	// - CubicTo: Points[0], Points[1] are controls, Points[2] is target
	Points	[3]OutlinePoint
}

type GlyphOutline struct

GlyphOutline represents the vector outline of a glyph.

The outline consists of one or more closed contours.

type GlyphOutline struct {
	// Segments is the list of path segments that make up the outline.
	Segments	[]OutlineSegment

	// Bounds is the bounding box of the outline in scaled units.
	Bounds	Rect

	// Advance is the horizontal advance width of the glyph.
	Advance	float32

	// LSB is the left side bearing.
	LSB	float32

	// GID is the glyph ID this outline represents.
	GID	GlyphID

	// Type indicates the type of glyph (outline, bitmap, COLR).
	Type	GlyphType
}

type AffineTransform struct

AffineTransform represents a 2D affine transformation matrix.

The matrix is:

 

[A B Tx]

[C D Ty]

[0 0 1 ]

type AffineTransform struct {
	A, B, C, D	float32	// Matrix coefficients
	Tx, Ty		float32	// Translation
}

type OutlineExtractor struct

OutlineExtractor extracts glyph outlines from fonts.

It uses a buffer pool internally for efficiency.

type OutlineExtractor struct {
	// buffer is reused for sfnt operations
	buffer sfnt.Buffer
}

type FontError struct

FontError represents a font-related error.

type FontError struct {
	Reason string
}