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  }