2026-05-26 17:11:09 +02:00

63 lines
1.7 KiB
Go

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
}