package batchsplit import ( "context" "fmt" "os/exec" "path/filepath" "regexp" "strconv" "time" ) // Renderer rastert die Seiten eines PDFs; Ergebnis: Seitennummer -> PNG-Pfad. type Renderer interface { Render(pdfPath, outDir string) (map[int]string, error) } // PopplerRenderer rastert mit pdftoppm (Graustufen-PNG). type PopplerRenderer struct { Binary string DPI int Timeout time.Duration } var renderedPage = regexp.MustCompile(`-(\d+)\.png$`) func (r PopplerRenderer) Render(pdfPath, outDir string) (map[int]string, error) { bin, dpi, timeout := r.Binary, r.DPI, r.Timeout if bin == "" { bin = "pdftoppm" } if dpi <= 0 { dpi = 200 } if timeout <= 0 { timeout = 3 * time.Minute } ctx, cancel := context.WithTimeout(context.Background(), timeout) defer cancel() prefix := filepath.Join(outDir, "page") if out, err := exec.CommandContext(ctx, bin, "-r", strconv.Itoa(dpi), "-gray", "-png", pdfPath, prefix).CombinedOutput(); err != nil { return nil, fmt.Errorf("%s: %w: %.200s", bin, err, out) } files, err := filepath.Glob(prefix + "-*.png") if err != nil { return nil, err } pages := make(map[int]string, len(files)) for _, f := range files { if m := renderedPage.FindStringSubmatch(f); m != nil { n, _ := strconv.Atoi(m[1]) pages[n] = f } } return pages, nil }