1
2
3
4
5
6 package raster
7
8 import (
9 "image"
10 "image/color"
11 "image/draw"
12 "math"
13 )
14
15
16
17
18 type Span struct {
19 Y, X0, X1 int
20 Alpha uint32
21 }
22
23
24
25
26
27 type Painter interface {
28 Paint(ss []Span, done bool)
29 }
30
31
32 type PainterFunc func(ss []Span, done bool)
33
34
35 func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) }
36
37
38
39 type AlphaOverPainter struct {
40 Image *image.Alpha
41 }
42
43
44 func (r AlphaOverPainter) Paint(ss []Span, done bool) {
45 b := r.Image.Bounds()
46 for _, s := range ss {
47 if s.Y < b.Min.Y {
48 continue
49 }
50 if s.Y >= b.Max.Y {
51 return
52 }
53 if s.X0 < b.Min.X {
54 s.X0 = b.Min.X
55 }
56 if s.X1 > b.Max.X {
57 s.X1 = b.Max.X
58 }
59 if s.X0 >= s.X1 {
60 continue
61 }
62 base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
63 p := r.Image.Pix[base+s.X0 : base+s.X1]
64 a := int(s.Alpha >> 8)
65 for i, c := range p {
66 v := int(c)
67 p[i] = uint8((v*255 + (255-v)*a) / 255)
68 }
69 }
70 }
71
72
73 func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter {
74 return AlphaOverPainter{m}
75 }
76
77
78
79 type AlphaSrcPainter struct {
80 Image *image.Alpha
81 }
82
83
84 func (r AlphaSrcPainter) Paint(ss []Span, done bool) {
85 b := r.Image.Bounds()
86 for _, s := range ss {
87 if s.Y < b.Min.Y {
88 continue
89 }
90 if s.Y >= b.Max.Y {
91 return
92 }
93 if s.X0 < b.Min.X {
94 s.X0 = b.Min.X
95 }
96 if s.X1 > b.Max.X {
97 s.X1 = b.Max.X
98 }
99 if s.X0 >= s.X1 {
100 continue
101 }
102 base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
103 p := r.Image.Pix[base+s.X0 : base+s.X1]
104 color := uint8(s.Alpha >> 8)
105 for i := range p {
106 p[i] = color
107 }
108 }
109 }
110
111
112 func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter {
113 return AlphaSrcPainter{m}
114 }
115
116
117 type RGBAPainter struct {
118
119 Image *image.RGBA
120
121 Op draw.Op
122
123 cr, cg, cb, ca uint32
124 }
125
126
127 func (r *RGBAPainter) Paint(ss []Span, done bool) {
128 b := r.Image.Bounds()
129 for _, s := range ss {
130 if s.Y < b.Min.Y {
131 continue
132 }
133 if s.Y >= b.Max.Y {
134 return
135 }
136 if s.X0 < b.Min.X {
137 s.X0 = b.Min.X
138 }
139 if s.X1 > b.Max.X {
140 s.X1 = b.Max.X
141 }
142 if s.X0 >= s.X1 {
143 continue
144 }
145
146 ma := s.Alpha
147 const m = 1<<16 - 1
148 i0 := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride + (s.X0-r.Image.Rect.Min.X)*4
149 i1 := i0 + (s.X1-s.X0)*4
150 if r.Op == draw.Over {
151 for i := i0; i < i1; i += 4 {
152 dr := uint32(r.Image.Pix[i+0])
153 dg := uint32(r.Image.Pix[i+1])
154 db := uint32(r.Image.Pix[i+2])
155 da := uint32(r.Image.Pix[i+3])
156 a := (m - (r.ca * ma / m)) * 0x101
157 r.Image.Pix[i+0] = uint8((dr*a + r.cr*ma) / m >> 8)
158 r.Image.Pix[i+1] = uint8((dg*a + r.cg*ma) / m >> 8)
159 r.Image.Pix[i+2] = uint8((db*a + r.cb*ma) / m >> 8)
160 r.Image.Pix[i+3] = uint8((da*a + r.ca*ma) / m >> 8)
161 }
162 } else {
163 for i := i0; i < i1; i += 4 {
164 r.Image.Pix[i+0] = uint8(r.cr * ma / m >> 8)
165 r.Image.Pix[i+1] = uint8(r.cg * ma / m >> 8)
166 r.Image.Pix[i+2] = uint8(r.cb * ma / m >> 8)
167 r.Image.Pix[i+3] = uint8(r.ca * ma / m >> 8)
168 }
169 }
170 }
171 }
172
173
174 func (r *RGBAPainter) SetColor(c color.Color) {
175 r.cr, r.cg, r.cb, r.ca = c.RGBA()
176 }
177
178
179 func NewRGBAPainter(m *image.RGBA) *RGBAPainter {
180 return &RGBAPainter{Image: m}
181 }
182
183
184
185 type MonochromePainter struct {
186 Painter Painter
187 y, x0, x1 int
188 }
189
190
191
192 func (m *MonochromePainter) Paint(ss []Span, done bool) {
193
194 j := 0
195 for _, s := range ss {
196 if s.Alpha >= 0x8000 {
197 if m.y == s.Y && m.x1 == s.X0 {
198 m.x1 = s.X1
199 } else {
200 ss[j] = Span{m.y, m.x0, m.x1, 1<<16 - 1}
201 j++
202 m.y, m.x0, m.x1 = s.Y, s.X0, s.X1
203 }
204 }
205 }
206 if done {
207
208 finalSpan := Span{m.y, m.x0, m.x1, 1<<16 - 1}
209 if j < len(ss) {
210 ss[j] = finalSpan
211 j++
212 m.Painter.Paint(ss[:j], true)
213 } else if j == len(ss) {
214 m.Painter.Paint(ss, false)
215 if cap(ss) > 0 {
216 ss = ss[:1]
217 } else {
218 ss = make([]Span, 1)
219 }
220 ss[0] = finalSpan
221 m.Painter.Paint(ss, true)
222 } else {
223 panic("unreachable")
224 }
225
226 m.y, m.x0, m.x1 = 0, 0, 0
227 } else {
228 m.Painter.Paint(ss[:j], false)
229 }
230 }
231
232
233
234 func NewMonochromePainter(p Painter) *MonochromePainter {
235 return &MonochromePainter{Painter: p}
236 }
237
238
239
240 type GammaCorrectionPainter struct {
241
242 Painter Painter
243
244
245 a [256]uint16
246
247 gammaIsOne bool
248 }
249
250
251
252 func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) {
253 if !g.gammaIsOne {
254 const n = 0x101
255 for i, s := range ss {
256 if s.Alpha == 0 || s.Alpha == 0xffff {
257 continue
258 }
259 p, q := s.Alpha/n, s.Alpha%n
260
261 a := uint32(g.a[p])*(n-q) + uint32(g.a[p+1])*q
262 ss[i].Alpha = (a + n/2) / n
263 }
264 }
265 g.Painter.Paint(ss, done)
266 }
267
268
269 func (g *GammaCorrectionPainter) SetGamma(gamma float64) {
270 g.gammaIsOne = gamma == 1
271 if g.gammaIsOne {
272 return
273 }
274 for i := 0; i < 256; i++ {
275 a := float64(i) / 0xff
276 a = math.Pow(a, gamma)
277 g.a[i] = uint16(0xffff * a)
278 }
279 }
280
281
282
283 func NewGammaCorrectionPainter(p Painter, gamma float64) *GammaCorrectionPainter {
284 g := &GammaCorrectionPainter{Painter: p}
285 g.SetGamma(gamma)
286 return g
287 }
288
View as plain text