homelabby/internal/printer/mock_driver.go
Mikkel Georgsen 1156eff896 feat(04-03): PrinterDriver interface, MockDriver, PrtQutieDriver stub
- PrinterDriver interface: Connect/Print(bitmap,w,h)/Disconnect
- ImageToRawBitmap(): 1-bit packed row-major converter from image.Image
- MockDriver: saves PNG to SaveDir (/tmp default) for visual inspection
- PrtQutieDriver: stub returns ErrNoDevice — safe before hardware arrives
- ErrNoDevice, ErrNotConnected, ErrEmptyBitmap sentinel errors
2026-04-10 06:50:12 +00:00

72 lines
1.9 KiB
Go

package printer
import (
"fmt"
"image"
"image/color"
"image/png"
"os"
"time"
)
// MockDriver implements PrinterDriver for testing and development.
// Print() saves a PNG to SaveDir (default /tmp) and logs to stdout.
// No hardware required — use this as the default driver until PRT Qutie arrives.
type MockDriver struct {
connected bool
// SaveDir is the directory where label PNGs are written.
// Defaults to /tmp. Override in tests to use t.TempDir().
SaveDir string
}
// NewMockDriver creates a MockDriver that saves PNGs to /tmp.
func NewMockDriver() *MockDriver {
return &MockDriver{SaveDir: "/tmp"}
}
// Connect marks the driver as connected.
func (m *MockDriver) Connect() error {
m.connected = true
return nil
}
// Disconnect marks the driver as disconnected.
func (m *MockDriver) Disconnect() error {
m.connected = false
return nil
}
// Print reconstructs the label image from the 1-bit bitmap and saves it as a PNG.
// Returns ErrEmptyBitmap if bitmap is nil or empty.
func (m *MockDriver) Print(bitmap []byte, width, height int) error {
if len(bitmap) == 0 {
return ErrEmptyBitmap
}
// Reconstruct image from 1-bit packed bitmap for visual inspection.
img := image.NewGray(image.Rect(0, 0, width, height))
rowBytes := (width + 7) / 8
for y := 0; y < height; y++ {
for x := 0; x < width; x++ {
byteIdx := y*rowBytes + x/8
bit := (bitmap[byteIdx] >> (7 - uint(x%8))) & 1
if bit == 1 {
img.SetGray(x, y, color.Gray{Y: 0})
} else {
img.SetGray(x, y, color.Gray{Y: 255})
}
}
}
path := fmt.Sprintf("%s/hwlab-label-%d.png", m.SaveDir, time.Now().UnixMilli())
f, err := os.Create(path)
if err != nil {
return fmt.Errorf("printer: mock create file: %w", err)
}
defer f.Close()
if err := png.Encode(f, img); err != nil {
return fmt.Errorf("printer: mock encode PNG: %w", err)
}
fmt.Printf("[MockDriver] label saved → %s (%dx%d)\n", path, width, height)
return nil
}