Go CLI that turns the markdown currency of this stack (Redmine notes, Discourse posts, briefing output) into typeset PDFs: two embedded typst templates (report with title page/TOC/headers, dense brief), front-matter (title/subtitle/author/date/classification/template), GFM tables, and bar charts rendered in pure Go (go-chart) from fenced chart data blocks. Engine is a prebuilt typst 0.15.1 container pinned by digest and run --network none; PDF bytes to stdout or -o. Exit codes 0/1/2. All dev in docker (dev.sh/Makefile); unit tests + golden typst fixtures plus a host-side smoke against the real engine container. Generated with Crush Assisted-by: Crush:glm-5.2
43 lines
912 B
Go
43 lines
912 B
Go
package chart
|
|
|
|
import (
|
|
"bytes"
|
|
"errors"
|
|
"image"
|
|
"image/png"
|
|
)
|
|
|
|
// RGBACollector is a render target for a chart.
|
|
type RGBACollector interface {
|
|
SetRGBA(i *image.RGBA)
|
|
}
|
|
|
|
// ImageWriter is a special type of io.Writer that produces a final image.
|
|
type ImageWriter struct {
|
|
rgba *image.RGBA
|
|
contents *bytes.Buffer
|
|
}
|
|
|
|
func (ir *ImageWriter) Write(buffer []byte) (int, error) {
|
|
if ir.contents == nil {
|
|
ir.contents = bytes.NewBuffer([]byte{})
|
|
}
|
|
return ir.contents.Write(buffer)
|
|
}
|
|
|
|
// SetRGBA sets a raw version of the image.
|
|
func (ir *ImageWriter) SetRGBA(i *image.RGBA) {
|
|
ir.rgba = i
|
|
}
|
|
|
|
// Image returns an *image.Image for the result.
|
|
func (ir *ImageWriter) Image() (image.Image, error) {
|
|
if ir.rgba != nil {
|
|
return ir.rgba, nil
|
|
}
|
|
if ir.contents != nil && ir.contents.Len() > 0 {
|
|
return png.Decode(ir.contents)
|
|
}
|
|
return nil, errors.New("no valid sources for image data, cannot continue")
|
|
}
|