2026-05-26 18:27:37 +02:00

125 lines
3.2 KiB
Go

package printjob
import (
"fmt"
"os"
"printer.backend/internal/itemimage"
"printer.backend/internal/layout"
"printer.backend/internal/model"
"printer.backend/internal/platepdf"
"printer.backend/internal/store"
)
// RenderPDF builds a plate PDF with customer images placed in each item mask.
func RenderPDF(
job model.PrintJob,
configs *store.ConfigurationStore,
plates *store.PlateStore,
items *store.ItemStore,
orders *store.OrderStore,
) ([]byte, model.PrintJobSummary, error) {
cfg, err := configs.Get(job.ConfigurationID)
if err != nil {
return nil, model.PrintJobSummary{}, fmt.Errorf("configuration: %w", err)
}
plate, err := findPlate(plates, cfg.PlateID)
if err != nil {
return nil, model.PrintJobSummary{}, err
}
item, err := items.Get(cfg.ItemID)
if err != nil {
return nil, model.PrintJobSummary{}, fmt.Errorf("item: %w", err)
}
itemSVGPath, err := items.SVGPath(cfg.ItemID)
if err != nil {
return nil, model.PrintJobSummary{}, err
}
itemSVG, err := os.ReadFile(itemSVGPath)
if err != nil {
return nil, model.PrintJobSummary{}, fmt.Errorf("read item svg: %w", err)
}
orderList, err := loadOrders(orders, job.OrderIDs)
if err != nil {
return nil, model.PrintJobSummary{}, err
}
preview := layout.Pack(plate, item.Spec, cfg.SpacingMM)
preview.PlateID = cfg.PlateID
preview.ItemID = cfg.ItemID
summary := Summary(orderList, preview)
slotSVGs, err := buildSlotSVGs(itemSVG, item.Spec, preview, summary.Assignments, orders)
if err != nil {
return nil, summary, err
}
pdf, err := platepdf.GenerateWithSlots(plate, item.Spec, slotSVGs, preview)
if err != nil {
return nil, summary, err
}
return pdf, summary, nil
}
func buildSlotSVGs(
templateSVG []byte,
spec model.ItemSpec,
preview model.LayoutPreview,
assignments []model.PrintJobSlotAssignment,
orders *store.OrderStore,
) ([][]byte, error) {
slotSVGs := make([][]byte, len(preview.Positions))
for i := range slotSVGs {
slotSVGs[i] = templateSVG
}
for _, a := range assignments {
if a.Slot < 0 || a.Slot >= len(slotSVGs) {
return nil, fmt.Errorf("slot %d out of range", a.Slot)
}
path, img, err := orders.ImagePath(a.Image.OrderID, a.Image.ImageID)
if err != nil {
return nil, fmt.Errorf("slot %d: %w", a.Slot, err)
}
data, err := os.ReadFile(path)
if err != nil {
return nil, fmt.Errorf("slot %d: read image: %w", a.Slot, err)
}
embedded, err := itemimage.Embed(templateSVG, spec, data, img.ContentType)
if err != nil {
return nil, fmt.Errorf("slot %d: %w", a.Slot, err)
}
slotSVGs[a.Slot] = embedded
}
return slotSVGs, nil
}
func loadOrders(orders *store.OrderStore, ids []string) ([]model.Order, error) {
if len(ids) == 0 {
return nil, fmt.Errorf("at least one order_id is required")
}
out := make([]model.Order, 0, len(ids))
for _, id := range ids {
o, err := orders.Get(id)
if err != nil {
return nil, fmt.Errorf("order %s: %w", id, err)
}
out = append(out, o)
}
return out, nil
}
func findPlate(plates *store.PlateStore, id string) (model.Plate, error) {
list, err := plates.List()
if err != nil {
return model.Plate{}, err
}
for _, p := range list {
if p.ID == id {
return p, nil
}
}
return model.Plate{}, fmt.Errorf("plate not found: %s", id)
}