/
channel.go
109 lines (91 loc) · 2.19 KB
/
channel.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
103
104
105
106
107
108
109
/*Package channel provides image channel separation and manipulation functions.*/
package channel
import (
"fmt"
"image"
"github.com/anthonynsimon/bild/clone"
"github.com/anthonynsimon/bild/parallel"
)
// Channel identifier for RGBA images
type Channel int
// Channel identifiers
const (
Red = iota
Green
Blue
Alpha
)
var (
allChannels = []Channel{Red, Green, Blue, Alpha}
)
// ExtractMultiple returns a RGBA image containing the values of the selected channels.
//
// Usage example:
//
// result := channel.ExtractMultiple(img, channel.Blue, channel.Alpha)
//
func ExtractMultiple(img image.Image, channels ...Channel) *image.RGBA {
for _, c := range channels {
if c < 0 || 3 < c {
panic(fmt.Sprintf("channel index '%v' out of bounds. Red: 0, Green: 1, Blue: 2, Alpha: 3", c))
}
}
dst := clone.AsRGBA(img)
bounds := dst.Bounds()
dstW, dstH := bounds.Dx(), bounds.Dy()
if bounds.Empty() {
return &image.RGBA{}
}
channelsToRemove := []Channel{}
for _, channel := range allChannels {
shouldRemove := true
for _, enabled := range channels {
if enabled == channel {
shouldRemove = false
break
}
}
if shouldRemove {
channelsToRemove = append(channelsToRemove, channel)
}
}
parallel.Line(dstH, func(start, end int) {
for y := start; y < end; y++ {
for x := 0; x < dstW; x++ {
pos := y*dst.Stride + x*4
for _, c := range channelsToRemove {
dst.Pix[pos+int(c)] = 0x00
}
}
}
})
return dst
}
// Extract returns a grayscale image containing the values of the selected channel.
//
// Usage example:
//
// result := channel.Extract(img, channel.Alpha)
//
func Extract(img image.Image, c Channel) *image.Gray {
if c < 0 || 3 < c {
panic(fmt.Sprintf("channel index '%v' out of bounds. Red: 0, Green: 1, Blue: 2, Alpha: 3", c))
}
src := clone.AsRGBA(img)
bounds := src.Bounds()
srcW, srcH := bounds.Dx(), bounds.Dy()
if bounds.Empty() {
return &image.Gray{}
}
dst := image.NewGray(bounds)
parallel.Line(srcH, func(start, end int) {
for y := start; y < end; y++ {
for x := 0; x < srcW; x++ {
srcPos := y*src.Stride + x*4
dstPos := y*dst.Stride + x
dst.Pix[dstPos] = src.Pix[srcPos+int(c)]
}
}
})
return dst
}