diff --git a/palette.go b/palette.go index 2d0c9a0..e6bf568 100644 --- a/palette.go +++ b/palette.go @@ -1,9 +1,11 @@ package vibrant import ( + "encoding/json" "errors" "image" "math" + "strings" ) // These constants are taken directly from the Android Palette source code, @@ -36,6 +38,107 @@ type Palette struct { selected []*Swatch } +// CSS4 +// +// Export as CSS4 variables. Use in your CSS with var() +// e.g. html { background-color: var(--vibrant); } +// +// FIXME(day): variable names not final +// FIXME(day): variable names not final +// FIXME(day): variable names not final +// --vibrant:#123456; +// --vibrantText:#ffffff; +// --darkvibrant:#123456; +// --darkvibrantText:#ffffff; +// --lightvibrant:#123456; +// --lightvibrantText:#ffffff; +// --muted:#123456; +// --mutedText:#ffffff; +// --darkmuted:#123456; +// --darkmutedText:#ffffff; +// --lightmuted:#123456; +// --lightmutedText:#ffffff; +func (p *Palette) CSS4() string { + out := "" + for k, sw := range p.ExtractAwesome() { + // @consistency these variable names should match JSON output + // @consistency these variable names should match JSON output + // @consistency these variable names should match JSON output + out += "--" + strings.ToLower(k) + ":" + sw.Color.String() + ";" + out += "--" + strings.ToLower(k) + "Text:" + sw.Color.TitleTextColor().String() + ";" + } + return out +} + +// JSON +// +// err should always be nil unless something catastrophic is happening. +// +// JSON structure: +// +// { +// "vibrant": 0x123456, +// "dark-vibrant": 0x123456, +// "light-vibrant": 0x123456, +// "muted": 0x123456, +// "dark-muted": 0x123456, +// "light-muted": 0x123456, +// "vibrant-text": 0x123456, +// "dark-vibrant-text": 0x123456, +// "light-vibrant-text": 0x123456, +// "muted-text": 0x123456, +// "dark-muted-text": 0x123456, +// "light-muted-text": 0x123456 +// } +// +// Please note that encoding/json encodes hex numbers as decimal integers +// Please note that encoding/json encodes hex numbers as decimal integers +// Please note that encoding/json encodes hex numbers as decimal integers +func (p *Palette) JSON() ([]byte, error) { + // NOTE(day): As I type this I realize a more elegant data structure might look like + // { + // "vibrant": {"color": 0x99ccff, "text": 0xffffff}, + // "dark-vibrant": {"color": 0x00007f, "text": 0xffffff}, + // ... + // } + // also using PascalCase camelCase or snake_case instead of kebab-case + // might yield a more pleasurable user experience. + // this library was designed for CSS webdev stuff (that's why vibrant.Color.String() returns #abcdef oh. Oh. I just realized something... + // -day Sun 11 Jun 2023 10:28:06 PM EDT + // email me@dayvonjersen if you disagree =) + // -day Sun 11 Jun 2023 09:57:57 PM EDT + type vibrantJSON struct { + Vibrant int `json:"vibrant"` + DarkVibrant int `json:"dark-vibrant"` + LightVibrant int `json:"light-vibrant"` + Muted int `json:"muted"` + DarkMuted int `json:"dark-muted"` + LightMuted int `json:"light-muted"` + VibrantText int `json:"vibrant-text"` + DarkVibrantText int `json:"dark-vibrant-text"` + LightVibrantText int `json:"light-vibrant-text"` + MutedText int `json:"muted-text"` + DarkMutedText int `json:"dark-muted-text"` + LightMutedText int `json:"light-muted-text"` + } + this := p.ExtractAwesome() + choose := func(sw *Swatch, defaultColor int, defaultText int) (primary, text int) { + if sw == nil { + return defaultColor, defaultText + } + return int(sw.Color), int(sw.Color.TitleTextColor()) + } + // NOTE(day): sensible fallback colors (greyscale) + data := &vibrantJSON{} + data.Vibrant, data.VibrantText = choose(this["Vibrant"], 0xacaaaa, 0x0) + data.LightVibrant, data.LightVibrantText = choose(this["LightVibrant"], 0xffffff, 0x0) + data.DarkVibrant, data.DarkVibrantText = choose(this["DarkVibrant"], 0x2b2b2b, 0xffffff) + data.LightMuted, data.LightMutedText = choose(this["LightMuted"], 0xdad5d5, 0x0) + data.DarkMuted, data.DarkMutedText = choose(this["DarkMuted"], 0x32312f, 0xffffff) + data.Muted, data.MutedText = choose(this["Muted"], 0x6d6a6a, 0xffffff) + return json.Marshal(data) +} + // Calls NewPalette with DEFAULT_CALCULATE_NUMBER_COLORS as a default value for numColors. func NewPaletteFromImage(img image.Image) (Palette, error) { return NewPalette(img, DEFAULT_CALCULATE_NUMBER_COLORS) diff --git a/webapp.go b/webapp.go index 4a5fe67..2b1fc0e 100644 --- a/webapp.go +++ b/webapp.go @@ -1,12 +1,13 @@ +//go:build ignore // +build ignore /* - sample webapp to demo the functionality of github.com/dayvonjersen/vibrant +sample webapp to demo the functionality of github.com/dayvonjersen/vibrant - base64 encoding the images provides the benefit of not having to manage - uploaded files or do any javascript fanciness but comes with a performance penalty +base64 encoding the images provides the benefit of not having to manage +uploaded files or do any javascript fanciness but comes with a performance penalty - DO NOT USE THIS IN A PRODUCTION ENVIRONMENT +DO NOT USE THIS IN A PRODUCTION ENVIRONMENT */ package main @@ -17,6 +18,7 @@ import ( "io" "log" "net/http" + "sorbet/vibrant" "strconv" "time" @@ -25,8 +27,6 @@ import ( _ "image/png" "text/template" - - "github.com/dayvonjersen/vibrant" ) func index(w http.ResponseWriter, r *http.Request) { @@ -56,6 +56,7 @@ func index(w http.ResponseWriter, r *http.Request) { Benchmark time.Duration DefaultMaxColors int MaxColors int + JSON, CSS4 string }{DefaultMaxColors: vibrant.DEFAULT_CALCULATE_NUMBER_COLORS, MaxColors: vibrant.DEFAULT_CALCULATE_NUMBER_COLORS} @@ -133,6 +134,9 @@ func index(w http.ResponseWriter, r *http.Request) { } } data.Stylesheet = stylesheet + j, _ := palette.JSON() + data.JSON = string(j) + data.CSS4 = palette.CSS4() data.Missing = len(awesome) != 6 setStatus(200) data.Response = true @@ -141,8 +145,8 @@ func index(w http.ResponseWriter, r *http.Request) { func main() { http.HandleFunc("/", index) - log.Println("Listening on :8080...") - log.Fatalln(http.ListenAndServe(":8080", nil)) + log.Println("Listening on :9999...") + log.Fatalln(http.ListenAndServe(":9999", nil)) } const tpl = ` @@ -264,6 +268,8 @@ h2 { + + {{ if .Missing }}

If color swatches are missing, try increasing maxColors in the text field above.

{{ end }}