...

Source file src/github.com/golang/freetype/raster/paint.go

Documentation: github.com/golang/freetype/raster

     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  }
   288  

View as plain text