summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/golang/freetype/raster/paint.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/golang/freetype/raster/paint.go')
-rw-r--r--vendor/github.com/golang/freetype/raster/paint.go287
1 files changed, 287 insertions, 0 deletions
diff --git a/vendor/github.com/golang/freetype/raster/paint.go b/vendor/github.com/golang/freetype/raster/paint.go
new file mode 100644
index 000000000..652256cca
--- /dev/null
+++ b/vendor/github.com/golang/freetype/raster/paint.go
@@ -0,0 +1,287 @@
+// Copyright 2010 The Freetype-Go Authors. All rights reserved.
+// Use of this source code is governed by your choice of either the
+// FreeType License or the GNU General Public License version 2 (or
+// any later version), both of which can be found in the LICENSE file.
+
+package raster
+
+import (
+ "image"
+ "image/color"
+ "image/draw"
+ "math"
+)
+
+// A Span is a horizontal segment of pixels with constant alpha. X0 is an
+// inclusive bound and X1 is exclusive, the same as for slices. A fully opaque
+// Span has Alpha == 0xffff.
+type Span struct {
+ Y, X0, X1 int
+ Alpha uint32
+}
+
+// A Painter knows how to paint a batch of Spans. Rasterization may involve
+// Painting multiple batches, and done will be true for the final batch. The
+// Spans' Y values are monotonically increasing during a rasterization. Paint
+// may use all of ss as scratch space during the call.
+type Painter interface {
+ Paint(ss []Span, done bool)
+}
+
+// The PainterFunc type adapts an ordinary function to the Painter interface.
+type PainterFunc func(ss []Span, done bool)
+
+// Paint just delegates the call to f.
+func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) }
+
+// An AlphaOverPainter is a Painter that paints Spans onto a *image.Alpha using
+// the Over Porter-Duff composition operator.
+type AlphaOverPainter struct {
+ Image *image.Alpha
+}
+
+// Paint satisfies the Painter interface.
+func (r AlphaOverPainter) Paint(ss []Span, done bool) {
+ b := r.Image.Bounds()
+ for _, s := range ss {
+ if s.Y < b.Min.Y {
+ continue
+ }
+ if s.Y >= b.Max.Y {
+ return
+ }
+ if s.X0 < b.Min.X {
+ s.X0 = b.Min.X
+ }
+ if s.X1 > b.Max.X {
+ s.X1 = b.Max.X
+ }
+ if s.X0 >= s.X1 {
+ continue
+ }
+ base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
+ p := r.Image.Pix[base+s.X0 : base+s.X1]
+ a := int(s.Alpha >> 8)
+ for i, c := range p {
+ v := int(c)
+ p[i] = uint8((v*255 + (255-v)*a) / 255)
+ }
+ }
+}
+
+// NewAlphaOverPainter creates a new AlphaOverPainter for the given image.
+func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter {
+ return AlphaOverPainter{m}
+}
+
+// An AlphaSrcPainter is a Painter that paints Spans onto a *image.Alpha using
+// the Src Porter-Duff composition operator.
+type AlphaSrcPainter struct {
+ Image *image.Alpha
+}
+
+// Paint satisfies the Painter interface.
+func (r AlphaSrcPainter) Paint(ss []Span, done bool) {
+ b := r.Image.Bounds()
+ for _, s := range ss {
+ if s.Y < b.Min.Y {
+ continue
+ }
+ if s.Y >= b.Max.Y {
+ return
+ }
+ if s.X0 < b.Min.X {
+ s.X0 = b.Min.X
+ }
+ if s.X1 > b.Max.X {
+ s.X1 = b.Max.X
+ }
+ if s.X0 >= s.X1 {
+ continue
+ }
+ base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
+ p := r.Image.Pix[base+s.X0 : base+s.X1]
+ color := uint8(s.Alpha >> 8)
+ for i := range p {
+ p[i] = color
+ }
+ }
+}
+
+// NewAlphaSrcPainter creates a new AlphaSrcPainter for the given image.
+func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter {
+ return AlphaSrcPainter{m}
+}
+
+// An RGBAPainter is a Painter that paints Spans onto a *image.RGBA.
+type RGBAPainter struct {
+ // Image is the image to compose onto.
+ Image *image.RGBA
+ // Op is the Porter-Duff composition operator.
+ Op draw.Op
+ // cr, cg, cb and ca are the 16-bit color to paint the spans.
+ cr, cg, cb, ca uint32
+}
+
+// Paint satisfies the Painter interface.
+func (r *RGBAPainter) Paint(ss []Span, done bool) {
+ b := r.Image.Bounds()
+ for _, s := range ss {
+ if s.Y < b.Min.Y {
+ continue
+ }
+ if s.Y >= b.Max.Y {
+ return
+ }
+ if s.X0 < b.Min.X {
+ s.X0 = b.Min.X
+ }
+ if s.X1 > b.Max.X {
+ s.X1 = b.Max.X
+ }
+ if s.X0 >= s.X1 {
+ continue
+ }
+ // This code mimics drawGlyphOver in $GOROOT/src/image/draw/draw.go.
+ ma := s.Alpha
+ const m = 1<<16 - 1
+ i0 := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride + (s.X0-r.Image.Rect.Min.X)*4
+ i1 := i0 + (s.X1-s.X0)*4
+ if r.Op == draw.Over {
+ for i := i0; i < i1; i += 4 {
+ dr := uint32(r.Image.Pix[i+0])
+ dg := uint32(r.Image.Pix[i+1])
+ db := uint32(r.Image.Pix[i+2])
+ da := uint32(r.Image.Pix[i+3])
+ a := (m - (r.ca * ma / m)) * 0x101
+ r.Image.Pix[i+0] = uint8((dr*a + r.cr*ma) / m >> 8)
+ r.Image.Pix[i+1] = uint8((dg*a + r.cg*ma) / m >> 8)
+ r.Image.Pix[i+2] = uint8((db*a + r.cb*ma) / m >> 8)
+ r.Image.Pix[i+3] = uint8((da*a + r.ca*ma) / m >> 8)
+ }
+ } else {
+ for i := i0; i < i1; i += 4 {
+ r.Image.Pix[i+0] = uint8(r.cr * ma / m >> 8)
+ r.Image.Pix[i+1] = uint8(r.cg * ma / m >> 8)
+ r.Image.Pix[i+2] = uint8(r.cb * ma / m >> 8)
+ r.Image.Pix[i+3] = uint8(r.ca * ma / m >> 8)
+ }
+ }
+ }
+}
+
+// SetColor sets the color to paint the spans.
+func (r *RGBAPainter) SetColor(c color.Color) {
+ r.cr, r.cg, r.cb, r.ca = c.RGBA()
+}
+
+// NewRGBAPainter creates a new RGBAPainter for the given image.
+func NewRGBAPainter(m *image.RGBA) *RGBAPainter {
+ return &RGBAPainter{Image: m}
+}
+
+// A MonochromePainter wraps another Painter, quantizing each Span's alpha to
+// be either fully opaque or fully transparent.
+type MonochromePainter struct {
+ Painter Painter
+ y, x0, x1 int
+}
+
+// Paint delegates to the wrapped Painter after quantizing each Span's alpha
+// value and merging adjacent fully opaque Spans.
+func (m *MonochromePainter) Paint(ss []Span, done bool) {
+ // We compact the ss slice, discarding any Spans whose alpha quantizes to zero.
+ j := 0
+ for _, s := range ss {
+ if s.Alpha >= 0x8000 {
+ if m.y == s.Y && m.x1 == s.X0 {
+ m.x1 = s.X1
+ } else {
+ ss[j] = Span{m.y, m.x0, m.x1, 1<<16 - 1}
+ j++
+ m.y, m.x0, m.x1 = s.Y, s.X0, s.X1
+ }
+ }
+ }
+ if done {
+ // Flush the accumulated Span.
+ finalSpan := Span{m.y, m.x0, m.x1, 1<<16 - 1}
+ if j < len(ss) {
+ ss[j] = finalSpan
+ j++
+ m.Painter.Paint(ss[:j], true)
+ } else if j == len(ss) {
+ m.Painter.Paint(ss, false)
+ if cap(ss) > 0 {
+ ss = ss[:1]
+ } else {
+ ss = make([]Span, 1)
+ }
+ ss[0] = finalSpan
+ m.Painter.Paint(ss, true)
+ } else {
+ panic("unreachable")
+ }
+ // Reset the accumulator, so that this Painter can be re-used.
+ m.y, m.x0, m.x1 = 0, 0, 0
+ } else {
+ m.Painter.Paint(ss[:j], false)
+ }
+}
+
+// NewMonochromePainter creates a new MonochromePainter that wraps the given
+// Painter.
+func NewMonochromePainter(p Painter) *MonochromePainter {
+ return &MonochromePainter{Painter: p}
+}
+
+// A GammaCorrectionPainter wraps another Painter, performing gamma-correction
+// on each Span's alpha value.
+type GammaCorrectionPainter struct {
+ // Painter is the wrapped Painter.
+ Painter Painter
+ // a is the precomputed alpha values for linear interpolation, with fully
+ // opaque == 0xffff.
+ a [256]uint16
+ // gammaIsOne is whether gamma correction is a no-op.
+ gammaIsOne bool
+}
+
+// Paint delegates to the wrapped Painter after performing gamma-correction on
+// each Span.
+func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) {
+ if !g.gammaIsOne {
+ const n = 0x101
+ for i, s := range ss {
+ if s.Alpha == 0 || s.Alpha == 0xffff {
+ continue
+ }
+ p, q := s.Alpha/n, s.Alpha%n
+ // The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1].
+ a := uint32(g.a[p])*(n-q) + uint32(g.a[p+1])*q
+ ss[i].Alpha = (a + n/2) / n
+ }
+ }
+ g.Painter.Paint(ss, done)
+}
+
+// SetGamma sets the gamma value.
+func (g *GammaCorrectionPainter) SetGamma(gamma float64) {
+ g.gammaIsOne = gamma == 1
+ if g.gammaIsOne {
+ return
+ }
+ for i := 0; i < 256; i++ {
+ a := float64(i) / 0xff
+ a = math.Pow(a, gamma)
+ g.a[i] = uint16(0xffff * a)
+ }
+}
+
+// NewGammaCorrectionPainter creates a new GammaCorrectionPainter that wraps
+// the given Painter.
+func NewGammaCorrectionPainter(p Painter, gamma float64) *GammaCorrectionPainter {
+ g := &GammaCorrectionPainter{Painter: p}
+ g.SetGamma(gamma)
+ return g
+}