package main
import (
"fmt"
"os"
"path/filepath"
"strings"
)
// GenerateScanGridSVG creates printable calibration grid SVG files.
// Returns the list of generated file paths.
func GenerateScanGridSVG(cfg *ScanHelperConfig, outputDir string) ([]string, error) {
if cfg == nil {
return nil, fmt.Errorf("no scan helper config")
}
os.MkdirAll(outputDir, 0755)
pageW := cfg.PageWidth
pageH := cfg.PageHeight
grid := cfg.GridSpacing
if grid <= 0 {
grid = 10
}
margin := 15.0 // mm margin for printer bleed
markerSize := 5.0
var files []string
for row := 0; row < cfg.PagesTall; row++ {
for col := 0; col < cfg.PagesWide; col++ {
filename := fmt.Sprintf("scan_grid_%dx%d.svg", col+1, row+1)
if cfg.PagesWide == 1 && cfg.PagesTall == 1 {
filename = "scan_grid.svg"
}
path := filepath.Join(outputDir, filename)
svg, err := renderGridPage(pageW, pageH, margin, grid, markerSize, col, row, cfg.PagesWide, cfg.PagesTall)
if err != nil {
return files, err
}
if err := os.WriteFile(path, []byte(svg), 0644); err != nil {
return files, fmt.Errorf("write %s: %v", filename, err)
}
files = append(files, path)
}
}
return files, nil
}
func renderGridPage(pageW, pageH, margin, gridSpacing, markerSize float64, col, row, totalCols, totalRows int) (string, error) {
var b strings.Builder
b.WriteString(fmt.Sprintf(`
\n")
return b.String(), nil
}
func writeCornerMark(b *strings.Builder, x, y, size, dx, dy float64) {
// L-shaped corner mark
b.WriteString(fmt.Sprintf(``,
x, y, x+size*dx, y))
b.WriteString("\n")
b.WriteString(fmt.Sprintf(``,
x, y, x, y+size*dy))
b.WriteString("\n")
// Small filled circle at corner
b.WriteString(fmt.Sprintf(``, x, y))
b.WriteString("\n")
}
func writeAlignmentMarkers(b *strings.Builder, x, y, w, h, size float64) {
// Edge midpoint crosses for stitching alignment
edges := [][2]float64{
{x + w/2, y}, // top center
{x + w/2, y + h}, // bottom center
{x, y + h/2}, // left center
{x + w, y + h/2}, // right center
}
for _, e := range edges {
b.WriteString(fmt.Sprintf(``,
e[0]-size/2, e[1], e[0]+size/2, e[1]))
b.WriteString("\n")
b.WriteString(fmt.Sprintf(``,
e[0], e[1]-size/2, e[0], e[1]+size/2))
b.WriteString("\n")
}
}