63 lines
1.7 KiB
Go
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
|
|
}
|