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) }