github.com/jmigpin/editor@v1.6.0/util/imageutil/hsva.go (about) 1 package imageutil 2 3 import ( 4 "image/color" 5 "sort" 6 ) 7 8 // https://en.wikipedia.org/wiki/HSL_and_HSV#/media/File:HSV-RGB-comparison.svg 9 10 type HSV struct { 11 H uint16 // [0-360) 12 S, V uint8 // [0-255] 13 } 14 15 // h in [0-360), {s,v} in [0-100] 16 func MakeHSV(h uint16, s, v uint8) HSV { 17 return HSV{ 18 H: h, 19 S: uint8(uint32(s) * 255 / 100), 20 V: uint8(uint32(v) * 255 / 100), 21 } 22 } 23 24 func (c HSV) RGBA() (_, _, _, _ uint32) { 25 r, g, b := hsv2rgb(c.H, c.S, c.V) 26 rgba := color.RGBA{r, g, b, 0xff} 27 return rgba.RGBA() 28 } 29 30 var HSVModel color.Model = color.ModelFunc(convertToHSV) 31 32 func convertToHSV(c color.Color) color.Color { 33 c2 := color.RGBAModel.Convert(c).(color.RGBA) 34 h, s, v := rgb2hsv(c2.R, c2.G, c2.B) 35 return HSV{h, s, v} 36 } 37 38 func hsv2rgb(h uint16, s, v uint8) (r, g, b uint8) { 39 max0 := int(v) 40 min0 := int(v) * (255 - int(s)) / 255 41 42 offset := int(h % 60) 43 mid0 := (max0 - min0) * offset / 60 44 45 max := uint8(max0) 46 min := uint8(min0) 47 mid := uint8(mid0) 48 49 seg := h / 60 50 switch seg { 51 case 0: 52 return max, min + mid, min 53 case 1: 54 return max - mid, max, min 55 case 2: 56 return min, max, min + mid 57 case 3: 58 return min, max - mid, max 59 case 4: 60 return min + mid, min, max 61 case 5: 62 return max, min, max - mid 63 default: 64 panic("!") 65 } 66 } 67 68 func rgb2hsv(r0, g0, b0 uint8) (h uint16, s, v uint8) { 69 r, g, b := int(r0), int(g0), int(b0) 70 71 u := []int{r, g, b} 72 sort.Ints(u) 73 m1, _, m3 := u[0], u[1], u[2] 74 75 max := m3 76 max0 := max 77 v = uint8(max0) 78 79 min := m1 80 min0 := min 81 s = uint8(0) 82 if v != 0 { 83 s = uint8(-(min0*255/int(v) - 255)) 84 } 85 86 seg := 0 87 mid := 0 88 if b == m1 { 89 if r == m3 { 90 seg = 0 91 mid = g - min 92 } else { 93 seg = 1 94 mid = max - r 95 } 96 } else if r == m1 { 97 if g == m3 { 98 seg = 2 99 mid = b - min 100 } else { 101 seg = 3 102 mid = max - g 103 } 104 } else { 105 if b == m3 { 106 seg = 4 107 mid = r - min 108 } else { 109 seg = 5 110 mid = max - b 111 } 112 } 113 114 mid0 := mid 115 offset := 0 116 d := max0 - min0 117 if d != 0 { 118 offset = mid0 * 60 / d 119 } 120 h = uint16(seg*60 + offset) 121 122 return 123 }