recording/backends/raster/backend.go
Functions
func Begin
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
}
Begin initializes the backend for rendering at the given dimensions.
This must be called before any drawing operations.