package platepdf import ( "bytes" "fmt" "os/exec" ) // rsvgAvailable returns true when rsvg-convert is found in PATH. func rsvgAvailable() bool { _, err := exec.LookPath("rsvg-convert") return err == nil } // svgToPDFViaRsvg converts an SVG byte slice to a PDF using rsvg-convert. // widthMM / heightMM set the output page size so the PDF is exactly that physical size. func svgToPDFViaRsvg(svg []byte, widthMM, heightMM float64) ([]byte, error) { args := []string{ "-f", "pdf", "--page-width", fmt.Sprintf("%.4fmm", widthMM), "--page-height", fmt.Sprintf("%.4fmm", heightMM), "-", // read from stdin } cmd := exec.Command("rsvg-convert", args...) cmd.Stdin = bytes.NewReader(svg) var stdout, stderr bytes.Buffer cmd.Stdout = &stdout cmd.Stderr = &stderr err := cmd.Run() // rsvg-convert exits non-zero when writing to a non-terminal stdout; treat // a non-empty PDF output as success regardless of exit code. if stdout.Len() > 4 && string(stdout.Bytes()[:4]) == "%PDF" { return stdout.Bytes(), nil } if err != nil { return nil, fmt.Errorf("rsvg-convert: %w: %s", err, stderr.String()) } return stdout.Bytes(), nil } // svgToPNGViaRsvg converts SVG to PNG at the given DPI using rsvg-convert. func svgToPNGViaRsvg(svg []byte, dpi float64) ([]byte, error) { args := []string{ "-f", "png", "-d", fmt.Sprintf("%.0f", dpi), "-p", fmt.Sprintf("%.0f", dpi), "-", } cmd := exec.Command("rsvg-convert", args...) cmd.Stdin = bytes.NewReader(svg) out, err := cmd.Output() if err != nil { var stderr []byte if ee, ok := err.(*exec.ExitError); ok { stderr = ee.Stderr } return nil, fmt.Errorf("rsvg-convert: %w: %s", err, stderr) } return out, nil }