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 }