package state
import (
"bytes"
"fmt"
"html/template"
"image"
"image/color"
"net/http"
"github.com/srwiley/oksvg"
"github.com/srwiley/rasterx"
"golang.org/x/image/draw"
"tangled.org/core/appview/pages"
"tangled.org/core/ico"
)
func (s *State) FaviconSvg(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/svg+xml")
w.Header().Set("Cache-Control", "public, max-age=31536000") // one year
w.Header().Set("ETag", `"favicon-svg-v1"`)
if match := r.Header.Get("If-None-Match"); match == `"favicon-svg-v1"` {
w.WriteHeader(http.StatusNotModified)
return
}
s.pages.Favicon(w)
}
func (s *State) FaviconIco(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Content-Type", "image/x-icon")
w.Header().Set("Cache-Control", "public, max-age=31536000") // one year
w.Header().Set("ETag", `"favicon-ico-v1"`)
if match := r.Header.Get("If-None-Match"); match == `"favicon-ico-v1"` {
w.WriteHeader(http.StatusNotModified)
return
}
ico, err := dollyIco()
if err != nil {
s.logger.Error("failed to render ico", "err", err)
w.WriteHeader(http.StatusNotFound)
return
}
w.Write(ico)
}
func dollyIco() ([]byte, error) {
// first, get the bytes from the svg
tpl, err := template.New("dolly").
ParseFS(pages.Files, "templates/fragments/dolly/silhouette.html")
if err != nil {
return nil, err
}
var svgData bytes.Buffer
if err := tpl.ExecuteTemplate(&svgData, "fragments/dolly/silhouette", "#000000"); err != nil {
return nil, err
}
img, err := svgToImage(svgData.Bytes(), 48, 48)
if err != nil {
return nil, err
}
ico, err := ico.ImageToIco(img)
if err != nil {
return nil, err
}
return ico, nil
}
func svgToImage(svgData []byte, w, h int) (image.Image, error) {
icon, err := oksvg.ReadIconStream(bytes.NewReader(svgData))
if err != nil {
return nil, fmt.Errorf("error parsing SVG: %v", err)
}
icon.SetTarget(0, 0, float64(w), float64(h))
rgba := image.NewRGBA(image.Rect(0, 0, w, h))
draw.Draw(rgba, rgba.Bounds(), &image.Uniform{color.Transparent}, image.Point{}, draw.Src)
scanner := rasterx.NewScannerGV(w, h, rgba, rgba.Bounds())
raster := rasterx.NewDasher(w, h, scanner)
icon.Draw(raster, 1.0)
return rgba, nil
}