shiny/iconvg: implement suggested palettes.
Change-Id: I5bd5f0d1c0c5c83be0216eb149c87fbce595d7ab
Reviewed-on: https://go-review.googlesource.com/31374
Reviewed-by: David Crawshaw <crawshaw@golang.org>
diff --git a/shiny/iconvg/color.go b/shiny/iconvg/color.go
index f8ff941..b2fa7d3 100644
--- a/shiny/iconvg/color.go
+++ b/shiny/iconvg/color.go
@@ -84,7 +84,8 @@
//
// To blend a Color that is not encodable as a 1 byte color, first load that
// Color into a CREG color register, then call CRegColor to produce a Color
-// that is encodable as a 1 byte color.
+// that is encodable as a 1 byte color. See testdata/favicon.ivg for an
+// example.
//
// See the "Colors" section in the package documentation for details.
func BlendColor(t, c0, c1 uint8) Color { return Color{ColorTypeBlend, color.RGBA{R: t, G: c0, B: c1}} }
diff --git a/shiny/iconvg/decode_test.go b/shiny/iconvg/decode_test.go
index 520abb7..fae6ca7 100644
--- a/shiny/iconvg/decode_test.go
+++ b/shiny/iconvg/decode_test.go
@@ -136,7 +136,7 @@
{"testdata/blank", ""},
{"testdata/cowbell", ""},
{"testdata/elliptical", ""},
- {"testdata/favicon", ""},
+ {"testdata/favicon", ";pink"},
{"testdata/gradient", ""},
{"testdata/lod-polygon", ";64"},
{"testdata/video-005.primitive", ""},
@@ -198,10 +198,17 @@
height = int(float32(length) * dy / dx)
}
+ opts := &DecodeOptions{}
+ if variant == "pink" {
+ pal := DefaultPalette
+ pal[0] = color.RGBA{0xfe, 0x76, 0xea, 0xff}
+ opts.Palette = &pal
+ }
+
got := image.NewRGBA(image.Rect(0, 0, width, height))
var z Rasterizer
z.SetDstImage(got, got.Bounds(), draw.Src)
- if err := Decode(&z, ivgData, nil); err != nil {
+ if err := Decode(&z, ivgData, opts); err != nil {
t.Errorf("%s %q variant: Decode: %v", tc.filename, variant, err)
continue
}
diff --git a/shiny/iconvg/encode.go b/shiny/iconvg/encode.go
index ead030a..c9c3ac9 100644
--- a/shiny/iconvg/encode.go
+++ b/shiny/iconvg/encode.go
@@ -119,7 +119,53 @@
}
if mcSuggestedPalette {
- panic("TODO: encode mcSuggestedPalette")
+ n := 63
+ for ; n >= 0 && m.Palette[n] == (color.RGBA{0x00, 0x00, 0x00, 0xff}); n-- {
+ }
+
+ // Find the shortest encoding that can represent all of m.Palette's n+1
+ // explicit colors.
+ enc1, enc2, enc3 := true, true, true
+ for _, c := range m.Palette[:n+1] {
+ if enc1 && (!is1(c.R) || !is1(c.G) || !is1(c.B) || !is1(c.A)) {
+ enc1 = false
+ }
+ if enc2 && (!is2(c.R) || !is2(c.G) || !is2(c.B) || !is2(c.A)) {
+ enc2 = false
+ }
+ if enc3 && (c.A != 0xff) {
+ enc3 = false
+ }
+ }
+
+ e.altBuf = e.altBuf[:0]
+ e.altBuf.encodeNatural(midSuggestedPalette)
+ if enc1 {
+ e.altBuf = append(e.altBuf, byte(n)|0x00)
+ for _, c := range m.Palette[:n+1] {
+ x, _ := encodeColor1(RGBAColor(c))
+ e.altBuf = append(e.altBuf, x)
+ }
+ } else if enc2 {
+ e.altBuf = append(e.altBuf, byte(n)|0x40)
+ for _, c := range m.Palette[:n+1] {
+ x, _ := encodeColor2(RGBAColor(c))
+ e.altBuf = append(e.altBuf, x[0], x[1])
+ }
+ } else if enc3 {
+ e.altBuf = append(e.altBuf, byte(n)|0x80)
+ for _, c := range m.Palette[:n+1] {
+ e.altBuf = append(e.altBuf, c.R, c.G, c.B)
+ }
+ } else {
+ e.altBuf = append(e.altBuf, byte(n)|0xc0)
+ for _, c := range m.Palette[:n+1] {
+ e.altBuf = append(e.altBuf, c.R, c.G, c.B, c.A)
+ }
+ }
+
+ e.buf.encodeNatural(uint32(len(e.altBuf)))
+ e.buf = append(e.buf, e.altBuf...)
}
}
diff --git a/shiny/iconvg/encode_test.go b/shiny/iconvg/encode_test.go
index 94f3e0f..71489b3 100644
--- a/shiny/iconvg/encode_test.go
+++ b/shiny/iconvg/encode_test.go
@@ -351,11 +351,37 @@
}}
func TestEncodeFavicon(t *testing.T) {
- var e Encoder
+ // Set up a base color for theming the favicon, gopher blue by default.
+ pal := DefaultPalette
+ pal[0] = faviconColors[0] // color.RGBA{0x76, 0xe1, 0xfe, 0xff}
- for i, c := range faviconColors[:2] {
- e.SetCReg(uint8(i), false, RGBAColor(c))
+ var e Encoder
+ e.Reset(Metadata{
+ ViewBox: DefaultViewBox,
+ Palette: pal,
+ })
+
+ // The favicon graphic also uses a dark version of that base color. blend
+ // is 75% dark (CReg[63]) and 25% the base color (pal[0]).
+ dark := color.RGBA{0x23, 0x1d, 0x1b, 0xff}
+ blend := BlendColor(0x40, 0xff, 0x80)
+
+ // First, set CReg[63] to dark, then set CReg[63] to the blend of that dark
+ // color with pal[0].
+ e.SetCReg(1, false, RGBAColor(dark))
+ e.SetCReg(1, false, blend)
+
+ // Check that, for the suggested palette, blend resolves to the
+ // (non-themable) SVG file's faviconColors[1].
+ got := blend.Resolve(&pal, &[64]color.RGBA{
+ 63: dark,
+ })
+ want := faviconColors[1]
+ if got != want {
+ t.Fatalf("Blend:\ngot %#02x\nwant %#02x", got, want)
}
+
+ // Set aside the remaining, non-themable colors.
remainingColors := faviconColors[2:]
seenFCI2 := false
diff --git a/shiny/iconvg/testdata/README b/shiny/iconvg/testdata/README
index 21c5ee6..22b9579 100644
--- a/shiny/iconvg/testdata/README
+++ b/shiny/iconvg/testdata/README
@@ -58,7 +58,7 @@
favicon.ivg.disassembly is a disassembly of that IconVG file.
-favicon.png is a rendering of that IconVG file.
+favicon.png and favicon.pink.png are renderings of that IconVG file.
diff --git a/shiny/iconvg/testdata/favicon.ivg b/shiny/iconvg/testdata/favicon.ivg
index afe10eb..68ad0e9 100644
--- a/shiny/iconvg/testdata/favicon.ivg
+++ b/shiny/iconvg/testdata/favicon.ivg
Binary files differ
diff --git a/shiny/iconvg/testdata/favicon.ivg.disassembly b/shiny/iconvg/testdata/favicon.ivg.disassembly
index 28fca9d..c655193 100644
--- a/shiny/iconvg/testdata/favicon.ivg.disassembly
+++ b/shiny/iconvg/testdata/favicon.ivg.disassembly
@@ -1,9 +1,15 @@
89 49 56 47 IconVG Magic identifier
-00 Number of metadata chunks: 0
-90 Set CREG[CSEL-0] to a 3 byte (direct) color
+02 Number of metadata chunks: 1
+0a Metadata chunk length: 5
+02 Metadata Identifier: 1 (suggested palette)
+80 1 palette colors, 3 bytes per color
76 e1 fe RGBA 76e1feff
91 Set CREG[CSEL-1] to a 3 byte (direct) color
-38 4e 54 RGBA 384e54ff
+23 1d 1b RGBA 231d1bff
+a1 Set CREG[CSEL-1] to a 3 byte (indirect) color
+40 blend 191:64 c0:c1
+ff c0: CREG[63]
+80 c1: customPalette[0]
c1 Start path, filled with CREG[CSEL-1]; M (absolute moveTo)
31 80 +0.1875
44 -30
diff --git a/shiny/iconvg/testdata/favicon.pink.png b/shiny/iconvg/testdata/favicon.pink.png
new file mode 100644
index 0000000..862c538
--- /dev/null
+++ b/shiny/iconvg/testdata/favicon.pink.png
Binary files differ