-
-
Notifications
You must be signed in to change notification settings - Fork 10
/
dither_color.go
93 lines (85 loc) · 2.12 KB
/
dither_color.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
package dither
import (
"image"
"image/color"
)
type Settings struct {
Filter [][]float32
}
type Dither struct {
Type string
Settings
}
func (dither Dither) Color(input image.Image, errorMultiplier float32) image.Image {
bounds := input.Bounds()
img := image.NewRGBA(bounds)
for x := bounds.Min.X; x < bounds.Dx(); x++ {
for y := bounds.Min.Y; y < bounds.Dy(); y++ {
pixel := input.At(x, y)
img.Set(x, y, pixel)
}
}
dx, dy := img.Bounds().Dx(), img.Bounds().Dy()
// Prepopulate multidimensional slices
redErrors := make([][]float32, dx)
greenErrors := make([][]float32, dx)
blueErrors := make([][]float32, dx)
for x := 0; x < dx; x++ {
redErrors[x] = make([]float32, dy)
greenErrors[x] = make([]float32, dy)
blueErrors[x] = make([]float32, dy)
for y := 0; y < dy; y++ {
redErrors[x][y] = 0
greenErrors[x][y] = 0
blueErrors[x][y] = 0
}
}
var qrr, qrg, qrb float32
for x := 0; x < dx; x++ {
for y := 0; y < dy; y++ {
r32, g32, b32, a := img.At(x, y).RGBA()
r, g, b := float32(uint8(r32)), float32(uint8(g32)), float32(uint8(b32))
r -= redErrors[x][y] * errorMultiplier
g -= greenErrors[x][y] * errorMultiplier
b -= blueErrors[x][y] * errorMultiplier
// Diffuse the error of each calculation to the neighboring pixels
if r < 128 {
qrr = -r
r = 0
} else {
qrr = 255 - r
r = 255
}
if g < 128 {
qrg = -g
g = 0
} else {
qrg = 255 - g
g = 255
}
if b < 128 {
qrb = -b
b = 0
} else {
qrb = 255 - b
b = 255
}
img.Set(x, y, color.RGBA{uint8(r), uint8(g), uint8(b), uint8(a)})
// Diffuse error in two dimension
ydim := len(dither.Filter) - 1
xdim := len(dither.Filter[0]) / 2
for xx := 0; xx < ydim+1; xx++ {
for yy := -xdim; yy <= xdim-1; yy++ {
if y+yy < 0 || dy <= y+yy || x+xx < 0 || dx <= x+xx {
continue
}
// Adds the error of the previous pixel to the current pixel
redErrors[x+xx][y+yy] += qrr * dither.Filter[xx][yy+ydim]
greenErrors[x+xx][y+yy] += qrg * dither.Filter[xx][yy+ydim]
blueErrors[x+xx][y+yy] += qrb * dither.Filter[xx][yy+ydim]
}
}
}
}
return img
}