/
vibrance.go
65 lines (52 loc) · 1.7 KB
/
vibrance.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
// Package vibrance provides functions to adjust the "vibrancy" of images.
package vibrance
import (
"github.com/lucasb-eyer/go-colorful"
"hawx.me/code/img/channel"
"hawx.me/code/img/utils"
"image"
"image/color"
"math"
)
// Adjust increases the saturation of the least saturated parts of the image
// while also reducing the lightness of these parts.
func Adjust(img image.Image, amount float64) image.Image {
return utils.MapColor(img, AdjustC(amount))
}
// AdjustC returns a Composable function that increases the saturation and
// decreases the lightness of unsaturated colours.
//
// Uses the same method as Darktable:
// https://github.com/darktable-org/darktable/blob/24c4a087fd020df587b5260f438bfaf494203cec/src/iop/vibrance.c
func AdjustC(amount float64) utils.Composable {
return func(c color.Color) color.Color {
r, g, b, a := utils.RatioRGBA(c)
ll, la, lb := colorful.Color{r, g, b}.Lab()
// saturation weight [0, 1]
sw := math.Sqrt(la*la+lb*lb) / 2
ls := 1.0 - amount*sw*0.25
ss := 1.0 + amount*sw
ll *= ls
la *= ss
lb *= ss
f := colorful.Lab(ll, la, lb)
fr := utils.Truncatef(f.R * 255)
fg := utils.Truncatef(f.G * 255)
fb := utils.Truncatef(f.B * 255)
return color.NRGBA{uint8(fr), uint8(fg), uint8(fb), uint8(a * 255)}
}
}
// Exp increases the saturation of the least saturated parts of an image.
func Exp(img image.Image, amount float64) image.Image {
return utils.MapColor(img, ExpC(amount))
}
// ExpC returns a Composable function that increases the saturation of
// unsaturated colours.
func ExpC(amount float64) utils.Composable {
ch := channel.Saturation
return func(c color.Color) color.Color {
s := ch.Get(c)
s = math.Pow(s, 1/amount)
return ch.Set(c, s)
}
}