From bfa4d5076b716cb2e2a4134d25ce9dc4913546eb Mon Sep 17 00:00:00 2001 From: Ben Donnelly Date: Thu, 1 Oct 2020 19:25:40 +0200 Subject: [PATCH] feat(png): add support for generating the images as png --- README.md | 2 ++ internal/diagram.go | 7 +++++-- internal/generator.go | 2 +- internal/http.go | 32 +++++++++++++++++++++++--------- 4 files changed, 31 insertions(+), 12 deletions(-) diff --git a/README.md b/README.md index 4ad4bfa..7cdc3fe 100644 --- a/README.md +++ b/README.md @@ -22,6 +22,8 @@ go run cmd/app/main.go --mermaid=./mermaidcli/node_modules/.bin/mmdc --in=./in - ### Diagram creation +Use the query param 'type' to change between 'png' and 'svg' defaults to 'svg'. + #### POST Send a CURL request to generate a diagram via `POST`: diff --git a/internal/diagram.go b/internal/diagram.go index 32c2fe3..9e836dc 100644 --- a/internal/diagram.go +++ b/internal/diagram.go @@ -10,11 +10,12 @@ import ( ) // NewDiagram returns a new diagram. -func NewDiagram(description []byte) *Diagram { +func NewDiagram(description []byte, imgType string) *Diagram { return &Diagram{ description: []byte(strings.TrimSpace(string(description))), lastTouched: time.Now(), mu: &sync.RWMutex{}, + imgType: imgType, } } @@ -30,6 +31,8 @@ type Diagram struct { mu *sync.RWMutex // lastTouched is the time that the diagram was last used. lastTouched time.Time + // the type of image to generate svg or png + imgType string } // Touch updates the last touched time of the diagram. @@ -55,7 +58,7 @@ func (d *Diagram) ID() (string, error) { encoded := base64.StdEncoding.EncodeToString(d.description) hash := md5.Sum([]byte(encoded)) - d.id = hex.EncodeToString(hash[:]) + d.id = hex.EncodeToString(hash[:]) + d.imgType return d.id, nil } diff --git a/internal/generator.go b/internal/generator.go index 65130f1..0b14c59 100644 --- a/internal/generator.go +++ b/internal/generator.go @@ -79,7 +79,7 @@ func (c cachingGenerator) generate(diagram *Diagram) error { } inPath := fmt.Sprintf("%s/%s.mmd", c.inPath, id) - outPath := fmt.Sprintf("%s/%s.svg", c.outPath, id) + outPath := fmt.Sprintf("%s/%s.%s", c.outPath, id, diagram.imgType) if err := ioutil.WriteFile(inPath, diagram.description, 0644); err != nil { return fmt.Errorf("could not write to input file [%s]: %w", inPath, err) diff --git a/internal/http.go b/internal/http.go index ea55d65..7361905 100644 --- a/internal/http.go +++ b/internal/http.go @@ -22,8 +22,12 @@ func writeJSON(rw http.ResponseWriter, value interface{}, status int) { } } -func writeSVG(rw http.ResponseWriter, data []byte, status int) { - rw.Header().Set("Content-Type", "image/svg+xml") +func writeImage(rw http.ResponseWriter, data []byte, status int, imgType string) { + if imgType == "png" { + rw.Header().Set("Content-Type", "image/png") + } else { + rw.Header().Set("Content-Type", "image/svg+xml") + } rw.WriteHeader(status) if _, err := rw.Write(data); err != nil { panic("could not write bytes to response: " + err.Error()) @@ -41,7 +45,7 @@ func writeErr(rw http.ResponseWriter, err error, status int) { // URLParam is the URL parameter getDiagramFromGET uses to look for data. const URLParam = "data" -func getDiagramFromGET(rw http.ResponseWriter, r *http.Request) *Diagram { +func getDiagramFromGET(rw http.ResponseWriter, r *http.Request, imgType string) *Diagram { if r.Method != http.MethodGet { writeErr(rw, fmt.Errorf("expected HTTP method GET"), http.StatusBadRequest) return nil @@ -59,11 +63,11 @@ func getDiagramFromGET(rw http.ResponseWriter, r *http.Request) *Diagram { } // Create a diagram from the description - d := NewDiagram([]byte(data)) + d := NewDiagram([]byte(data), imgType) return d } -func getDiagramFromPOST(rw http.ResponseWriter, r *http.Request) *Diagram { +func getDiagramFromPOST(rw http.ResponseWriter, r *http.Request, imgType string) *Diagram { if r.Method != http.MethodPost { writeErr(rw, fmt.Errorf("expected HTTP method POST"), http.StatusBadRequest) return nil @@ -76,7 +80,7 @@ func getDiagramFromPOST(rw http.ResponseWriter, r *http.Request) *Diagram { } // Create a diagram from the description - d := NewDiagram(bytes) + d := NewDiagram(bytes, imgType) return d } @@ -85,11 +89,21 @@ func generateHTTPHandler(generator Generator) func(rw http.ResponseWriter, r *ht return func(rw http.ResponseWriter, r *http.Request) { var diagram *Diagram + var imgType = r.URL.Query().Get("type") + if imgType == "" { + imgType = "svg" + } + + if imgType != "png" && imgType != "svg" { + writeErr(rw, fmt.Errorf("unsupported image type (%s) use svg or png", imgType), http.StatusBadRequest) + return + } + switch r.Method { case http.MethodGet: - diagram = getDiagramFromGET(rw, r) + diagram = getDiagramFromGET(rw, r, imgType) case http.MethodPost: - diagram = getDiagramFromPOST(rw, r) + diagram = getDiagramFromPOST(rw, r, imgType) default: writeErr(rw, fmt.Errorf("unexpected HTTP method %s", r.Method), http.StatusBadRequest) return @@ -112,6 +126,6 @@ func generateHTTPHandler(generator Generator) func(rw http.ResponseWriter, r *ht writeErr(rw, fmt.Errorf("could not read diagram bytes: %s", err), http.StatusInternalServerError) return } - writeSVG(rw, diagramBytes, http.StatusOK) + writeImage(rw, diagramBytes, http.StatusOK, imgType) } }