2010-04-13 12:26:10 +00:00
|
|
|
// Copyright 2010 The Freetype-Go Authors. All rights reserved.
|
|
|
|
// Use of this source code is governed by your choice of either the
|
2010-08-03 01:07:23 +00:00
|
|
|
// FreeType License or the GNU General Public License version 2 (or
|
|
|
|
// any later version), both of which can be found in the LICENSE file.
|
2010-04-13 12:26:10 +00:00
|
|
|
|
|
|
|
package raster
|
|
|
|
|
|
|
|
import (
|
|
|
|
"image"
|
2011-10-06 02:55:02 +00:00
|
|
|
"image/color"
|
2011-06-05 04:47:45 +00:00
|
|
|
"image/draw"
|
2010-04-13 12:26:10 +00:00
|
|
|
"math"
|
|
|
|
)
|
|
|
|
|
|
|
|
// A Span is a horizontal segment of pixels with constant alpha. X0 is an
|
2015-08-30 13:48:43 +00:00
|
|
|
// inclusive bound and X1 is exclusive, the same as for slices. A fully opaque
|
|
|
|
// Span has Alpha == 0xffff.
|
2010-04-13 12:26:10 +00:00
|
|
|
type Span struct {
|
|
|
|
Y, X0, X1 int
|
2015-08-30 13:48:43 +00:00
|
|
|
Alpha uint32
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
|
2010-05-21 22:09:13 +00:00
|
|
|
// A Painter knows how to paint a batch of Spans. Rasterization may involve
|
2015-08-30 13:48:43 +00:00
|
|
|
// 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.
|
2010-04-13 12:26:10 +00:00
|
|
|
type Painter interface {
|
2010-05-21 22:09:13 +00:00
|
|
|
Paint(ss []Span, done bool)
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// The PainterFunc type adapts an ordinary function to the Painter interface.
|
2010-05-21 22:09:13 +00:00
|
|
|
type PainterFunc func(ss []Span, done bool)
|
2010-04-13 12:26:10 +00:00
|
|
|
|
|
|
|
// Paint just delegates the call to f.
|
2010-05-21 22:09:13 +00:00
|
|
|
func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) }
|
2010-04-13 12:26:10 +00:00
|
|
|
|
2015-08-30 13:48:43 +00:00
|
|
|
// An AlphaOverPainter is a Painter that paints Spans onto a *image.Alpha using
|
|
|
|
// the Over Porter-Duff composition operator.
|
2010-09-10 02:06:50 +00:00
|
|
|
type AlphaOverPainter struct {
|
2010-05-14 03:29:53 +00:00
|
|
|
Image *image.Alpha
|
|
|
|
}
|
|
|
|
|
2015-08-30 13:48:43 +00:00
|
|
|
// Paint satisfies the Painter interface.
|
2010-09-10 02:06:50 +00:00
|
|
|
func (r AlphaOverPainter) Paint(ss []Span, done bool) {
|
2010-08-10 07:39:32 +00:00
|
|
|
b := r.Image.Bounds()
|
2010-05-14 03:29:53 +00:00
|
|
|
for _, s := range ss {
|
2010-08-10 07:39:32 +00:00
|
|
|
if s.Y < b.Min.Y {
|
2010-05-14 03:29:53 +00:00
|
|
|
continue
|
|
|
|
}
|
2010-08-10 07:39:32 +00:00
|
|
|
if s.Y >= b.Max.Y {
|
2010-05-14 03:29:53 +00:00
|
|
|
return
|
|
|
|
}
|
2010-08-10 07:39:32 +00:00
|
|
|
if s.X0 < b.Min.X {
|
|
|
|
s.X0 = b.Min.X
|
2010-05-14 03:29:53 +00:00
|
|
|
}
|
2010-08-10 07:39:32 +00:00
|
|
|
if s.X1 > b.Max.X {
|
|
|
|
s.X1 = b.Max.X
|
2010-05-14 03:29:53 +00:00
|
|
|
}
|
2010-09-15 06:05:32 +00:00
|
|
|
if s.X0 >= s.X1 {
|
|
|
|
continue
|
|
|
|
}
|
2011-07-10 05:05:40 +00:00
|
|
|
base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
|
2010-08-10 07:39:32 +00:00
|
|
|
p := r.Image.Pix[base+s.X0 : base+s.X1]
|
2015-08-30 13:48:43 +00:00
|
|
|
a := int(s.Alpha >> 8)
|
2010-09-10 02:06:50 +00:00
|
|
|
for i, c := range p {
|
2011-07-12 06:41:03 +00:00
|
|
|
v := int(c)
|
|
|
|
p[i] = uint8((v*255 + (255-v)*a) / 255)
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
2010-05-14 03:29:53 +00:00
|
|
|
}
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 05:55:01 +00:00
|
|
|
// NewAlphaOverPainter creates a new AlphaOverPainter for the given image.
|
|
|
|
func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter {
|
|
|
|
return AlphaOverPainter{m}
|
|
|
|
}
|
|
|
|
|
2015-08-30 13:48:43 +00:00
|
|
|
// An AlphaSrcPainter is a Painter that paints Spans onto a *image.Alpha using
|
|
|
|
// the Src Porter-Duff composition operator.
|
2010-09-10 02:06:50 +00:00
|
|
|
type AlphaSrcPainter struct {
|
|
|
|
Image *image.Alpha
|
|
|
|
}
|
|
|
|
|
2015-08-30 13:48:43 +00:00
|
|
|
// Paint satisfies the Painter interface.
|
2010-09-10 02:06:50 +00:00
|
|
|
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
|
|
|
|
}
|
2010-09-15 06:05:32 +00:00
|
|
|
if s.X0 >= s.X1 {
|
|
|
|
continue
|
|
|
|
}
|
2011-07-10 05:05:40 +00:00
|
|
|
base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X
|
2010-09-10 02:06:50 +00:00
|
|
|
p := r.Image.Pix[base+s.X0 : base+s.X1]
|
2015-08-30 13:48:43 +00:00
|
|
|
color := uint8(s.Alpha >> 8)
|
2010-09-10 02:06:50 +00:00
|
|
|
for i := range p {
|
|
|
|
p[i] = color
|
|
|
|
}
|
|
|
|
}
|
2010-05-14 03:29:53 +00:00
|
|
|
}
|
|
|
|
|
2010-10-12 05:55:01 +00:00
|
|
|
// NewAlphaSrcPainter creates a new AlphaSrcPainter for the given image.
|
|
|
|
func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter {
|
|
|
|
return AlphaSrcPainter{m}
|
|
|
|
}
|
|
|
|
|
2015-08-30 13:48:43 +00:00
|
|
|
// An RGBAPainter is a Painter that paints Spans onto a *image.RGBA.
|
2010-05-14 03:29:53 +00:00
|
|
|
type RGBAPainter struct {
|
2015-08-30 13:48:43 +00:00
|
|
|
// Image is the image to compose onto.
|
2010-05-14 03:29:53 +00:00
|
|
|
Image *image.RGBA
|
2015-08-30 13:48:43 +00:00
|
|
|
// Op is the Porter-Duff composition operator.
|
2010-05-14 03:29:53 +00:00
|
|
|
Op draw.Op
|
2015-08-30 13:48:43 +00:00
|
|
|
// cr, cg, cb and ca are the 16-bit color to paint the spans.
|
2010-05-14 03:29:53 +00:00
|
|
|
cr, cg, cb, ca uint32
|
|
|
|
}
|
|
|
|
|
2015-08-30 13:48:43 +00:00
|
|
|
// Paint satisfies the Painter interface.
|
2010-05-21 22:09:13 +00:00
|
|
|
func (r *RGBAPainter) Paint(ss []Span, done bool) {
|
2010-08-10 07:39:32 +00:00
|
|
|
b := r.Image.Bounds()
|
2010-05-14 03:29:53 +00:00
|
|
|
for _, s := range ss {
|
2010-08-10 07:39:32 +00:00
|
|
|
if s.Y < b.Min.Y {
|
2010-05-14 03:29:53 +00:00
|
|
|
continue
|
|
|
|
}
|
2010-08-10 07:39:32 +00:00
|
|
|
if s.Y >= b.Max.Y {
|
2010-05-14 03:29:53 +00:00
|
|
|
return
|
|
|
|
}
|
2010-08-10 07:39:32 +00:00
|
|
|
if s.X0 < b.Min.X {
|
|
|
|
s.X0 = b.Min.X
|
2010-05-14 03:29:53 +00:00
|
|
|
}
|
2010-08-10 07:39:32 +00:00
|
|
|
if s.X1 > b.Max.X {
|
|
|
|
s.X1 = b.Max.X
|
2010-05-14 03:29:53 +00:00
|
|
|
}
|
2010-08-27 00:51:14 +00:00
|
|
|
if s.X0 >= s.X1 {
|
|
|
|
continue
|
|
|
|
}
|
2015-08-30 13:48:43 +00:00
|
|
|
// This code mimics drawGlyphOver in $GOROOT/src/image/draw/draw.go.
|
|
|
|
ma := s.Alpha
|
2011-07-12 06:41:03 +00:00
|
|
|
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)
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-14 03:29:53 +00:00
|
|
|
}
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
|
2010-05-14 03:29:53 +00:00
|
|
|
// SetColor sets the color to paint the spans.
|
2011-10-06 02:55:02 +00:00
|
|
|
func (r *RGBAPainter) SetColor(c color.Color) {
|
2010-05-14 03:29:53 +00:00
|
|
|
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
|
2010-04-13 12:26:10 +00:00
|
|
|
y, x0, x1 int
|
|
|
|
}
|
|
|
|
|
|
|
|
// Paint delegates to the wrapped Painter after quantizing each Span's alpha
|
2010-05-14 03:29:53 +00:00
|
|
|
// value and merging adjacent fully opaque Spans.
|
2010-05-21 22:09:13 +00:00
|
|
|
func (m *MonochromePainter) Paint(ss []Span, done bool) {
|
2010-04-13 12:26:10 +00:00
|
|
|
// We compact the ss slice, discarding any Spans whose alpha quantizes to zero.
|
|
|
|
j := 0
|
|
|
|
for _, s := range ss {
|
2015-08-30 13:48:43 +00:00
|
|
|
if s.Alpha >= 0x8000 {
|
2010-04-13 12:26:10 +00:00
|
|
|
if m.y == s.Y && m.x1 == s.X0 {
|
|
|
|
m.x1 = s.X1
|
|
|
|
} else {
|
|
|
|
ss[j] = Span{m.y, m.x0, m.x1, 1<<32 - 1}
|
|
|
|
j++
|
|
|
|
m.y, m.x0, m.x1 = s.Y, s.X0, s.X1
|
|
|
|
}
|
2010-05-21 22:09:13 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
if done {
|
|
|
|
// Flush the accumulated Span.
|
|
|
|
finalSpan := Span{m.y, m.x0, m.x1, 1<<32 - 1}
|
|
|
|
if j < len(ss) {
|
|
|
|
ss[j] = finalSpan
|
2010-04-13 12:26:10 +00:00
|
|
|
j++
|
2015-02-23 23:52:08 +00:00
|
|
|
m.Painter.Paint(ss[:j], true)
|
2010-05-21 22:09:13 +00:00
|
|
|
} else if j == len(ss) {
|
|
|
|
m.Painter.Paint(ss, false)
|
|
|
|
if cap(ss) > 0 {
|
2015-02-23 23:52:08 +00:00
|
|
|
ss = ss[:1]
|
2010-04-13 12:26:10 +00:00
|
|
|
} else {
|
2010-05-21 22:09:13 +00:00
|
|
|
ss = make([]Span, 1)
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
2010-05-21 22:09:13 +00:00
|
|
|
ss[0] = finalSpan
|
|
|
|
m.Painter.Paint(ss, true)
|
|
|
|
} else {
|
|
|
|
panic("unreachable")
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
2010-05-21 22:09:13 +00:00
|
|
|
// Reset the accumulator, so that this Painter can be re-used.
|
|
|
|
m.y, m.x0, m.x1 = 0, 0, 0
|
|
|
|
} else {
|
2015-02-23 23:52:08 +00:00
|
|
|
m.Painter.Paint(ss[:j], false)
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-14 03:29:53 +00:00
|
|
|
// NewMonochromePainter creates a new MonochromePainter that wraps the given
|
|
|
|
// Painter.
|
|
|
|
func NewMonochromePainter(p Painter) *MonochromePainter {
|
|
|
|
return &MonochromePainter{Painter: p}
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
|
2010-05-14 03:29:53 +00:00
|
|
|
// A GammaCorrectionPainter wraps another Painter, performing gamma-correction
|
|
|
|
// on each Span's alpha value.
|
|
|
|
type GammaCorrectionPainter struct {
|
2015-08-30 13:48:43 +00:00
|
|
|
// Painter is the wrapped Painter.
|
2010-05-14 03:29:53 +00:00
|
|
|
Painter Painter
|
2015-08-30 13:48:43 +00:00
|
|
|
// a is the precomputed alpha values for linear interpolation, with fully
|
|
|
|
// opaque == 0xffff.
|
2010-05-14 03:29:53 +00:00
|
|
|
a [256]uint16
|
2015-08-30 13:48:43 +00:00
|
|
|
// gammaIsOne is whether gamma correction is a no-op.
|
2010-05-20 00:37:01 +00:00
|
|
|
gammaIsOne bool
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
|
2015-08-30 13:48:43 +00:00
|
|
|
// Paint delegates to the wrapped Painter after performing gamma-correction on
|
|
|
|
// each Span.
|
2010-05-21 22:09:13 +00:00
|
|
|
func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) {
|
2010-05-20 00:37:01 +00:00
|
|
|
if !g.gammaIsOne {
|
2015-08-30 13:48:43 +00:00
|
|
|
const n = 0x101
|
2015-02-23 23:52:08 +00:00
|
|
|
for i, s := range ss {
|
2015-08-30 13:48:43 +00:00
|
|
|
if s.Alpha == 0 || s.Alpha == 0xffff {
|
2010-05-20 00:37:01 +00:00
|
|
|
continue
|
|
|
|
}
|
2015-08-30 13:48:43 +00:00
|
|
|
p, q := s.Alpha/n, s.Alpha%n
|
2010-05-20 00:37:01 +00:00
|
|
|
// The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1].
|
2015-08-30 13:48:43 +00:00
|
|
|
a := uint32(g.a[p])*(n-q) + uint32(g.a[p+1])*q
|
|
|
|
ss[i].Alpha = (a + n/2) / n
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
}
|
2010-05-21 22:09:13 +00:00
|
|
|
g.Painter.Paint(ss, done)
|
2010-04-13 12:26:10 +00:00
|
|
|
}
|
|
|
|
|
2010-05-14 03:29:53 +00:00
|
|
|
// SetGamma sets the gamma value.
|
2011-01-21 01:27:50 +00:00
|
|
|
func (g *GammaCorrectionPainter) SetGamma(gamma float64) {
|
2015-08-30 13:48:43 +00:00
|
|
|
g.gammaIsOne = gamma == 1
|
|
|
|
if g.gammaIsOne {
|
2010-05-20 00:37:01 +00:00
|
|
|
return
|
|
|
|
}
|
2010-04-13 12:26:10 +00:00
|
|
|
for i := 0; i < 256; i++ {
|
|
|
|
a := float64(i) / 0xff
|
2011-01-21 01:27:50 +00:00
|
|
|
a = math.Pow(a, gamma)
|
2010-04-13 12:26:10 +00:00
|
|
|
g.a[i] = uint16(0xffff * a)
|
|
|
|
}
|
2010-05-14 03:29:53 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// NewGammaCorrectionPainter creates a new GammaCorrectionPainter that wraps
|
|
|
|
// the given Painter.
|
2011-01-21 01:27:50 +00:00
|
|
|
func NewGammaCorrectionPainter(p Painter, gamma float64) *GammaCorrectionPainter {
|
2010-05-14 03:29:53 +00:00
|
|
|
g := &GammaCorrectionPainter{Painter: p}
|
|
|
|
g.SetGamma(gamma)
|
2010-04-13 12:26:10 +00:00
|
|
|
return g
|
|
|
|
}
|