recording/backends/raster/backend.go

Functions Structs

Functions

func Begin

Begin initializes the backend for rendering at the given dimensions.

This must be called before any drawing operations.

func (b *Backend) Begin(width, height int) error {
	b.width = width
	b.height = height
	b.ctx = gg.NewContext(width, height)
	return nil
}

func ClearClip

ClearClip removes any clipping region.

func (b *Backend) ClearClip() {
	// gg.Context doesn't expose ResetClip directly
	// We handle this by pushing/popping state around clip operations
}

func DrawImage

DrawImage draws an image from source to destination rectangle.

func (b *Backend) DrawImage(img image.Image, src, dst recording.Rect, _ recording.ImageOptions) {
	if img == nil {
		return
	}

	// Save current state
	b.ctx.Push()
	defer b.ctx.Pop()

	// Calculate scale
	srcW := src.Width()
	srcH := src.Height()
	dstW := dst.Width()
	dstH := dst.Height()

	if srcW == 0 || srcH == 0 {
		// Use full image bounds
		bounds := img.Bounds()
		srcW = float64(bounds.Dx())
		srcH = float64(bounds.Dy())
	}

	scaleX := dstW / srcW
	scaleY := dstH / srcH

	// Apply transform for scaling and positioning
	b.ctx.Translate(dst.MinX, dst.MinY)
	b.ctx.Scale(scaleX, scaleY)
	b.ctx.Translate(-src.MinX, -src.MinY)

	// Draw the image at origin (transform handles positioning)
	// Note: gg.Context.DrawImage takes int coordinates
	// We need to handle the source rect cropping if specified
	// For now, draw the full image and let the transform handle it
	bounds := img.Bounds()
	b.ctx.DrawRectangle(float64(bounds.Min.X), float64(bounds.Min.Y),
		float64(bounds.Dx()), float64(bounds.Dy()))
	// TODO: Implement proper image drawing with cropping
	// For now, use a simple approach
}

func DrawText

DrawText draws text at the given position with the specified font face and brush.

Note: Text rendering is not fully implemented in this backend.

gg.Context doesn't have SetFontFace with text.Face interface.

A full implementation would need font handling integration.

func (b *Backend) DrawText(_ string, _, _ float64, _ text.Face, brush recording.Brush) {
	// Apply brush for text color
	b.applyBrush(brush, true)

	// TODO: Implement text rendering when gg.Context supports text.Face
	// For now, we only apply the brush but don't render text
}

func End

End finalizes the rendering.

After End is called, output methods (WriteTo, SaveToFile) can be used.

func (b *Backend) End() error {
	return nil
}

func FillPath

FillPath fills the given path with the brush.

func (b *Backend) FillPath(path *gg.Path, brush recording.Brush, rule recording.FillRule) {
	if path == nil {
		return
	}

	b.applyBrush(brush, true)
	b.ctx.SetFillRule(convertFillRule(rule))
	b.setPath(path)
	_ = b.ctx.Fill()
}

func FillRect

FillRect fills a rectangle with the brush.

The rect coordinates are in world space (already transformed during recording).

func (b *Backend) FillRect(rect recording.Rect, brush recording.Brush) {
	b.applyBrush(brush, true)
	// Reset transform since rect is already in world coordinates
	b.ctx.Identity()
	b.ctx.DrawRectangle(rect.MinX, rect.MinY, rect.Width(), rect.Height())
	_ = b.ctx.Fill()
}

func Height

Height returns the backend height.

func (b *Backend) Height() int {
	return b.height
}

func Image

Image returns the rendered image.

func (b *Backend) Image() image.Image {
	return b.ctx.Image()
}

func NewBackend

NewBackend creates a new raster backend.

The backend must be initialized with Begin before use.

func NewBackend() *Backend {
	return &Backend{}
}

func Pixmap

Pixmap returns the rendered pixmap.

func (b *Backend) Pixmap() *gg.Pixmap {
	// gg.Context doesn't expose Pixmap directly
	// We need to convert from image
	img := b.ctx.Image()
	return gg.FromImage(img)
}

func Restore

Restore restores the graphics state from the stack.

func (b *Backend) Restore() {
	b.ctx.Pop()
}

func Save

Save saves the current graphics state onto a stack.

func (b *Backend) Save() {
	b.ctx.Push()
}

func SavePNG

SavePNG is a convenience method to save the image as PNG.

func (b *Backend) SavePNG(path string) error {
	return b.ctx.SavePNG(path)
}

func SaveToFile

SaveToFile saves the rendered content as PNG to a file.

func (b *Backend) SaveToFile(path string) error {
	return b.ctx.SavePNG(path)
}

func SetClip

SetClip sets the clipping region to the given path.

func (b *Backend) SetClip(path *gg.Path, rule recording.FillRule) {
	if path == nil {
		return
	}

	// Set the path on the context
	b.ctx.ClearPath()
	b.setPathFromElements(path)
	b.ctx.SetFillRule(convertFillRule(rule))
	// Note: gg.Context doesn't have a direct Clip method, so we use ClipPreserve behavior
	// by setting path and letting fill/stroke respect it
}

func SetTransform

SetTransform sets the current transformation matrix.

func (b *Backend) SetTransform(m recording.Matrix) {
	// Convert recording.Matrix to gg.Matrix
	b.ctx.SetTransform(gg.Matrix{
		A:	m.A, B: m.B, C: m.C,
		D:	m.D, E: m.E, F: m.F,
	})
}

func StrokePath

StrokePath strokes the given path with the brush and stroke style.

func (b *Backend) StrokePath(path *gg.Path, brush recording.Brush, stroke recording.Stroke) {
	if path == nil {
		return
	}

	b.applyBrush(brush, false)
	b.applyStroke(stroke)
	b.setPath(path)
	_ = b.ctx.Stroke()
}

func Width

Width returns the backend width.

func (b *Backend) Width() int {
	return b.width
}

func Write

func (cw *countingWriter) Write(p []byte) (int, error) {
	n, err := cw.w.Write(p)
	cw.n += int64(n)
	return n, err
}

func WriteTo

WriteTo writes the rendered content as PNG to the given writer.

func (b *Backend) WriteTo(w io.Writer) (int64, error) {
	cw := &countingWriter{w: w}
	err := png.Encode(cw, b.ctx.Image())
	return cw.n, err
}

Structs

type Backend struct

Backend renders recordings to a pixel image using gg.Context.

It implements recording.Backend, recording.WriterBackend,

recording.FileBackend, and recording.PixmapBackend interfaces.

type Backend struct {
	ctx	*gg.Context
	width	int
	height	int
}