github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/freetype/raster/paint.go (about) 1 // Copyright 2010 The Freetype-Go Authors. All rights reserved. 2 // Use of this source code is governed by your choice of either the 3 // FreeType License or the GNU General Public License version 2 (or 4 // any later version), both of which can be found in the LICENSE file. 5 6 package raster 7 8 import ( 9 "image" 10 "image/color" 11 "image/draw" 12 "math" 13 ) 14 15 // A Span is a horizontal segment of pixels with constant alpha. X0 is an 16 // inclusive bound and X1 is exclusive, the same as for slices. A fully opaque 17 // Span has Alpha == 0xffff. 18 type Span struct { 19 Y, X0, X1 int 20 Alpha uint32 21 } 22 23 // A Painter knows how to paint a batch of Spans. Rasterization may involve 24 // Painting multiple batches, and done will be true for the final batch. The 25 // Spans' Y values are monotonically increasing during a rasterization. Paint 26 // may use all of ss as scratch space during the call. 27 type Painter interface { 28 Paint(ss []Span, done bool) 29 } 30 31 // The PainterFunc type adapts an ordinary function to the Painter interface. 32 type PainterFunc func(ss []Span, done bool) 33 34 // Paint just delegates the call to f. 35 func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) } 36 37 // An AlphaOverPainter is a Painter that paints Spans onto a *image.Alpha using 38 // the Over Porter-Duff composition operator. 39 type AlphaOverPainter struct { 40 Image *image.Alpha 41 } 42 43 // Paint satisfies the Painter interface. 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 // NewAlphaOverPainter creates a new AlphaOverPainter for the given image. 73 func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter { 74 return AlphaOverPainter{m} 75 } 76 77 // An AlphaSrcPainter is a Painter that paints Spans onto a *image.Alpha using 78 // the Src Porter-Duff composition operator. 79 type AlphaSrcPainter struct { 80 Image *image.Alpha 81 } 82 83 // Paint satisfies the Painter interface. 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 // NewAlphaSrcPainter creates a new AlphaSrcPainter for the given image. 112 func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter { 113 return AlphaSrcPainter{m} 114 } 115 116 // An RGBAPainter is a Painter that paints Spans onto a *image.RGBA. 117 type RGBAPainter struct { 118 // Image is the image to compose onto. 119 Image *image.RGBA 120 // Op is the Porter-Duff composition operator. 121 Op draw.Op 122 // cr, cg, cb and ca are the 16-bit color to paint the spans. 123 cr, cg, cb, ca uint32 124 } 125 126 // Paint satisfies the Painter interface. 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 // This code mimics drawGlyphOver in $GOROOT/src/image/draw/draw.go. 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 // SetColor sets the color to paint the spans. 174 func (r *RGBAPainter) SetColor(c color.Color) { 175 r.cr, r.cg, r.cb, r.ca = c.RGBA() 176 } 177 178 // NewRGBAPainter creates a new RGBAPainter for the given image. 179 func NewRGBAPainter(m *image.RGBA) *RGBAPainter { 180 return &RGBAPainter{Image: m} 181 } 182 183 // A MonochromePainter wraps another Painter, quantizing each Span's alpha to 184 // be either fully opaque or fully transparent. 185 type MonochromePainter struct { 186 Painter Painter 187 y, x0, x1 int 188 } 189 190 // Paint delegates to the wrapped Painter after quantizing each Span's alpha 191 // value and merging adjacent fully opaque Spans. 192 func (m *MonochromePainter) Paint(ss []Span, done bool) { 193 // We compact the ss slice, discarding any Spans whose alpha quantizes to zero. 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 // Flush the accumulated Span. 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 // Reset the accumulator, so that this Painter can be re-used. 226 m.y, m.x0, m.x1 = 0, 0, 0 227 } else { 228 m.Painter.Paint(ss[:j], false) 229 } 230 } 231 232 // NewMonochromePainter creates a new MonochromePainter that wraps the given 233 // Painter. 234 func NewMonochromePainter(p Painter) *MonochromePainter { 235 return &MonochromePainter{Painter: p} 236 } 237 238 // A GammaCorrectionPainter wraps another Painter, performing gamma-correction 239 // on each Span's alpha value. 240 type GammaCorrectionPainter struct { 241 // Painter is the wrapped Painter. 242 Painter Painter 243 // a is the precomputed alpha values for linear interpolation, with fully 244 // opaque == 0xffff. 245 a [256]uint16 246 // gammaIsOne is whether gamma correction is a no-op. 247 gammaIsOne bool 248 } 249 250 // Paint delegates to the wrapped Painter after performing gamma-correction on 251 // each Span. 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 // The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1]. 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 // SetGamma sets the gamma value. 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 // NewGammaCorrectionPainter creates a new GammaCorrectionPainter that wraps 282 // the given Painter. 283 func NewGammaCorrectionPainter(p Painter, gamma float64) *GammaCorrectionPainter { 284 g := &GammaCorrectionPainter{Painter: p} 285 g.SetGamma(gamma) 286 return g 287 }