1// Copyright 2016 The Go Authors. All rights reserved. 2// Use of this source code is governed by a BSD-style 3// license that can be found in the LICENSE file. 4 5package iconvg 6 7import ( 8 "image/color" 9) 10 11func validAlphaPremulColor(c color.RGBA) bool { 12 return c.R <= c.A && c.G <= c.A && c.B <= c.A 13} 14 15// ColorType distinguishes types of Colors. 16type ColorType uint8 17 18const ( 19 // ColorTypeRGBA is a direct RGBA color. 20 ColorTypeRGBA ColorType = iota 21 22 // ColorTypePaletteIndex is an indirect color, indexing the custom palette. 23 ColorTypePaletteIndex 24 25 // ColorTypeCReg is an indirect color, indexing the CREG color registers. 26 ColorTypeCReg 27 28 // ColorTypeBlend is an indirect color, blending two other colors. 29 ColorTypeBlend 30) 31 32// Color is an IconVG color, whose RGBA values can depend on context. Some 33// Colors are direct RGBA values. Other Colors are indirect, referring to an 34// index of the custom palette, a color register of the decoder virtual 35// machine, or a blend of two other Colors. 36// 37// See the "Colors" section in the package documentation for details. 38type Color struct { 39 typ ColorType 40 data color.RGBA 41} 42 43func (c Color) rgba() color.RGBA { return c.data } 44func (c Color) paletteIndex() uint8 { return c.data.R } 45func (c Color) cReg() uint8 { return c.data.R } 46func (c Color) blend() (t, c0, c1 uint8) { return c.data.R, c.data.G, c.data.B } 47 48// Resolve resolves the Color's RGBA value, given its context: the custom 49// palette and the color registers of the decoder virtual machine. 50func (c Color) Resolve(pal *Palette, cReg *[64]color.RGBA) color.RGBA { 51 switch c.typ { 52 case ColorTypeRGBA: 53 return c.rgba() 54 case ColorTypePaletteIndex: 55 return pal[c.paletteIndex()&0x3f] 56 case ColorTypeCReg: 57 return cReg[c.cReg()&0x3f] 58 } 59 t, c0, c1 := c.blend() 60 p, q := uint32(255-t), uint32(t) 61 rgba0 := decodeColor1(c0).Resolve(pal, cReg) 62 rgba1 := decodeColor1(c1).Resolve(pal, cReg) 63 return color.RGBA{ 64 uint8(((p * uint32(rgba0.R)) + q*uint32(rgba1.R) + 128) / 255), 65 uint8(((p * uint32(rgba0.G)) + q*uint32(rgba1.G) + 128) / 255), 66 uint8(((p * uint32(rgba0.B)) + q*uint32(rgba1.B) + 128) / 255), 67 uint8(((p * uint32(rgba0.A)) + q*uint32(rgba1.A) + 128) / 255), 68 } 69} 70 71// RGBAColor returns a direct Color. 72func RGBAColor(c color.RGBA) Color { return Color{ColorTypeRGBA, c} } 73 74// PaletteIndexColor returns an indirect Color referring to an index of the 75// custom palette. 76func PaletteIndexColor(i uint8) Color { return Color{ColorTypePaletteIndex, color.RGBA{R: i & 0x3f}} } 77 78// CRegColor returns an indirect Color referring to a color register of the 79// decoder virtual machine. 80func CRegColor(i uint8) Color { return Color{ColorTypeCReg, color.RGBA{R: i & 0x3f}} } 81 82// BlendColor returns an indirect Color that blends two other Colors. Those two 83// other Colors must both be encodable as a 1 byte color. 84// 85// To blend a Color that is not encodable as a 1 byte color, first load that 86// Color into a CREG color register, then call CRegColor to produce a Color 87// that is encodable as a 1 byte color. See testdata/favicon.ivg for an 88// example. 89// 90// See the "Colors" section in the package documentation for details. 91func BlendColor(t, c0, c1 uint8) Color { return Color{ColorTypeBlend, color.RGBA{R: t, G: c0, B: c1}} } 92 93func decodeColor1(x byte) Color { 94 if x >= 0x80 { 95 if x >= 0xc0 { 96 return CRegColor(x) 97 } else { 98 return PaletteIndexColor(x) 99 } 100 } 101 if x >= 125 { 102 switch x - 125 { 103 case 0: 104 return RGBAColor(color.RGBA{0xc0, 0xc0, 0xc0, 0xc0}) 105 case 1: 106 return RGBAColor(color.RGBA{0x80, 0x80, 0x80, 0x80}) 107 case 2: 108 return RGBAColor(color.RGBA{0x00, 0x00, 0x00, 0x00}) 109 } 110 } 111 blue := dc1Table[x%5] 112 x = x / 5 113 green := dc1Table[x%5] 114 x = x / 5 115 red := dc1Table[x] 116 return RGBAColor(color.RGBA{red, green, blue, 0xff}) 117} 118 119var dc1Table = [5]byte{0x00, 0x40, 0x80, 0xc0, 0xff} 120 121func is1(u uint8) bool { return u&0x3f == 0 || u == 0xff } 122 123func encodeColor1(c Color) (x byte, ok bool) { 124 switch c.typ { 125 case ColorTypeRGBA: 126 if c.data.A != 0xff { 127 switch c.data { 128 case color.RGBA{0x00, 0x00, 0x00, 0x00}: 129 return 127, true 130 case color.RGBA{0x80, 0x80, 0x80, 0x80}: 131 return 126, true 132 case color.RGBA{0xc0, 0xc0, 0xc0, 0xc0}: 133 return 125, true 134 } 135 } else if is1(c.data.R) && is1(c.data.G) && is1(c.data.B) && is1(c.data.A) { 136 r := c.data.R / 0x3f 137 g := c.data.G / 0x3f 138 b := c.data.B / 0x3f 139 return 25*r + 5*g + b, true 140 } 141 case ColorTypePaletteIndex: 142 return c.data.R | 0x80, true 143 case ColorTypeCReg: 144 return c.data.R | 0xc0, true 145 } 146 return 0, false 147} 148 149func is2(u uint8) bool { return u%0x11 == 0 } 150 151func encodeColor2(c Color) (x [2]byte, ok bool) { 152 if c.typ == ColorTypeRGBA && is2(c.data.R) && is2(c.data.G) && is2(c.data.B) && is2(c.data.A) { 153 return [2]byte{ 154 (c.data.R/0x11)<<4 | (c.data.G / 0x11), 155 (c.data.B/0x11)<<4 | (c.data.A / 0x11), 156 }, true 157 } 158 return [2]byte{}, false 159} 160 161func encodeColor3Direct(c Color) (x [3]byte, ok bool) { 162 if c.typ == ColorTypeRGBA && c.data.A == 0xff { 163 return [3]byte{c.data.R, c.data.G, c.data.B}, true 164 } 165 return [3]byte{}, false 166} 167 168func encodeColor4(c Color) (x [4]byte, ok bool) { 169 if c.typ == ColorTypeRGBA { 170 return [4]byte{c.data.R, c.data.G, c.data.B, c.data.A}, true 171 } 172 return [4]byte{}, false 173} 174 175func encodeColor3Indirect(c Color) (x [3]byte, ok bool) { 176 if c.typ == ColorTypeBlend { 177 return [3]byte{c.data.R, c.data.G, c.data.B}, true 178 } 179 return [3]byte{}, false 180} 181