This repository has been archived by the owner on Jun 3, 2019. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathHSLColor.go
102 lines (83 loc) · 2.23 KB
/
HSLColor.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
package arn
import (
"fmt"
"image"
"math"
)
// HSLColor ...
type HSLColor struct {
Hue float64 `json:"hue"`
Saturation float64 `json:"saturation"`
Lightness float64 `json:"lightness"`
}
// String returns a representation like hsl(0, 0%, 0%).
func (color HSLColor) String() string {
return fmt.Sprintf("hsl(%.1f, %.1f%%, %.1f%%)", color.Hue*360, color.Saturation*100, color.Lightness*100)
}
// StringWithAlpha returns a representation like hsla(0, 0%, 0%, 0.5).
func (color HSLColor) StringWithAlpha(alpha float64) string {
return fmt.Sprintf("hsla(%.1f, %.1f%%, %.1f%%, %.2f)", color.Hue*360, color.Saturation*100, color.Lightness*100, alpha)
}
// GetAverageColor returns the average color of an image in HSL format.
func GetAverageColor(img image.Image) HSLColor {
width := img.Bounds().Dx()
height := img.Bounds().Dy()
totalR := uint64(0)
totalG := uint64(0)
totalB := uint64(0)
for x := 0; x < width; x++ {
for y := 0; y < height; y++ {
r, g, b, _ := img.At(x, y).RGBA()
totalR += uint64(r)
totalG += uint64(g)
totalB += uint64(b)
}
}
pixels := uint64(width * height)
const max = float64(65535)
averageR := float64(totalR/pixels) / max
averageG := float64(totalG/pixels) / max
averageB := float64(totalB/pixels) / max
h, s, l := RGBToHSL(averageR, averageG, averageB)
return HSLColor{h, s, l}
}
// RGBToHSL converts RGB to HSL (RGB input and HSL output are floats in the 0..1 range).
// Original source: https://github.com/gerow/go-color
func RGBToHSL(r, g, b float64) (h, s, l float64) {
max := math.Max(math.Max(r, g), b)
min := math.Min(math.Min(r, g), b)
// Luminosity is the average of the max and min rgb color intensities.
l = (max + min) / 2
// Saturation
delta := max - min
if delta == 0 {
// It's gray
return 0, 0, l
}
// It's not gray
if l < 0.5 {
s = delta / (max + min)
} else {
s = delta / (2 - max - min)
}
// Hue
r2 := (((max - r) / 6) + (delta / 2)) / delta
g2 := (((max - g) / 6) + (delta / 2)) / delta
b2 := (((max - b) / 6) + (delta / 2)) / delta
switch {
case r == max:
h = b2 - g2
case g == max:
h = (1.0 / 3.0) + r2 - b2
case b == max:
h = (2.0 / 3.0) + g2 - r2
}
// fix wraparounds
switch {
case h < 0:
h++
case h > 1:
h--
}
return h, s, l
}