提交 8a442816 编写于 作者: N Nigel Tao

Make raster.Painter's max alpha 1<<16-1, not 1<<32-1.

This is more consistent with the standard library's image/color package.

The benchmarks didn't seem to change significantly.
上级 3ba1c0f7
...@@ -13,17 +13,17 @@ import ( ...@@ -13,17 +13,17 @@ import (
) )
// A Span is a horizontal segment of pixels with constant alpha. X0 is an // 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 // inclusive bound and X1 is exclusive, the same as for slices. A fully opaque
// opaque Span has A == 1<<32 - 1. // Span has Alpha == 0xffff.
type Span struct { type Span struct {
Y, X0, X1 int Y, X0, X1 int
A uint32 Alpha uint32
} }
// A Painter knows how to paint a batch of Spans. Rasterization may involve // 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. // Painting multiple batches, and done will be true for the final batch. The
// The Spans' Y values are monotonically increasing during a rasterization. // Spans' Y values are monotonically increasing during a rasterization. Paint
// Paint may use all of ss as scratch space during the call. // may use all of ss as scratch space during the call.
type Painter interface { type Painter interface {
Paint(ss []Span, done bool) Paint(ss []Span, done bool)
} }
...@@ -34,13 +34,13 @@ type PainterFunc func(ss []Span, done bool) ...@@ -34,13 +34,13 @@ type PainterFunc func(ss []Span, done bool)
// Paint just delegates the call to f. // Paint just delegates the call to f.
func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) } func (f PainterFunc) Paint(ss []Span, done bool) { f(ss, done) }
// An AlphaOverPainter is a Painter that paints Spans onto an image.Alpha // An AlphaOverPainter is a Painter that paints Spans onto a *image.Alpha using
// using the Over Porter-Duff composition operator. // the Over Porter-Duff composition operator.
type AlphaOverPainter struct { type AlphaOverPainter struct {
Image *image.Alpha Image *image.Alpha
} }
// Paint satisfies the Painter interface by painting ss onto an image.Alpha. // Paint satisfies the Painter interface.
func (r AlphaOverPainter) Paint(ss []Span, done bool) { func (r AlphaOverPainter) Paint(ss []Span, done bool) {
b := r.Image.Bounds() b := r.Image.Bounds()
for _, s := range ss { for _, s := range ss {
...@@ -61,7 +61,7 @@ func (r AlphaOverPainter) Paint(ss []Span, done bool) { ...@@ -61,7 +61,7 @@ func (r AlphaOverPainter) Paint(ss []Span, done bool) {
} }
base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X 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] p := r.Image.Pix[base+s.X0 : base+s.X1]
a := int(s.A >> 24) a := int(s.Alpha >> 8)
for i, c := range p { for i, c := range p {
v := int(c) v := int(c)
p[i] = uint8((v*255 + (255-v)*a) / 255) p[i] = uint8((v*255 + (255-v)*a) / 255)
...@@ -74,13 +74,13 @@ func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter { ...@@ -74,13 +74,13 @@ func NewAlphaOverPainter(m *image.Alpha) AlphaOverPainter {
return AlphaOverPainter{m} return AlphaOverPainter{m}
} }
// An AlphaSrcPainter is a Painter that paints Spans onto an image.Alpha // An AlphaSrcPainter is a Painter that paints Spans onto a *image.Alpha using
// using the Src Porter-Duff composition operator. // the Src Porter-Duff composition operator.
type AlphaSrcPainter struct { type AlphaSrcPainter struct {
Image *image.Alpha Image *image.Alpha
} }
// Paint satisfies the Painter interface by painting ss onto an image.Alpha. // Paint satisfies the Painter interface.
func (r AlphaSrcPainter) Paint(ss []Span, done bool) { func (r AlphaSrcPainter) Paint(ss []Span, done bool) {
b := r.Image.Bounds() b := r.Image.Bounds()
for _, s := range ss { for _, s := range ss {
...@@ -101,7 +101,7 @@ func (r AlphaSrcPainter) Paint(ss []Span, done bool) { ...@@ -101,7 +101,7 @@ func (r AlphaSrcPainter) Paint(ss []Span, done bool) {
} }
base := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride - r.Image.Rect.Min.X 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] p := r.Image.Pix[base+s.X0 : base+s.X1]
color := uint8(s.A >> 24) color := uint8(s.Alpha >> 8)
for i := range p { for i := range p {
p[i] = color p[i] = color
} }
...@@ -113,16 +113,17 @@ func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter { ...@@ -113,16 +113,17 @@ func NewAlphaSrcPainter(m *image.Alpha) AlphaSrcPainter {
return AlphaSrcPainter{m} return AlphaSrcPainter{m}
} }
// An RGBAPainter is a Painter that paints Spans onto a *image.RGBA.
type RGBAPainter struct { type RGBAPainter struct {
// The image to compose onto. // Image is the image to compose onto.
Image *image.RGBA Image *image.RGBA
// The Porter-Duff composition operator. // Op is the Porter-Duff composition operator.
Op draw.Op Op draw.Op
// The 16-bit color to paint the spans. // cr, cg, cb and ca are the 16-bit color to paint the spans.
cr, cg, cb, ca uint32 cr, cg, cb, ca uint32
} }
// Paint satisfies the Painter interface by painting ss onto an image.RGBA. // Paint satisfies the Painter interface.
func (r *RGBAPainter) Paint(ss []Span, done bool) { func (r *RGBAPainter) Paint(ss []Span, done bool) {
b := r.Image.Bounds() b := r.Image.Bounds()
for _, s := range ss { for _, s := range ss {
...@@ -141,8 +142,8 @@ func (r *RGBAPainter) Paint(ss []Span, done bool) { ...@@ -141,8 +142,8 @@ func (r *RGBAPainter) Paint(ss []Span, done bool) {
if s.X0 >= s.X1 { if s.X0 >= s.X1 {
continue continue
} }
// This code is similar to drawGlyphOver in $GOROOT/src/pkg/image/draw/draw.go. // This code mimics drawGlyphOver in $GOROOT/src/image/draw/draw.go.
ma := s.A >> 16 ma := s.Alpha
const m = 1<<16 - 1 const m = 1<<16 - 1
i0 := (s.Y-r.Image.Rect.Min.Y)*r.Image.Stride + (s.X0-r.Image.Rect.Min.X)*4 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 i1 := i0 + (s.X1-s.X0)*4
...@@ -192,7 +193,7 @@ func (m *MonochromePainter) Paint(ss []Span, done bool) { ...@@ -192,7 +193,7 @@ func (m *MonochromePainter) Paint(ss []Span, done bool) {
// We compact the ss slice, discarding any Spans whose alpha quantizes to zero. // We compact the ss slice, discarding any Spans whose alpha quantizes to zero.
j := 0 j := 0
for _, s := range ss { for _, s := range ss {
if s.A >= 1<<31 { if s.Alpha >= 0x8000 {
if m.y == s.Y && m.x1 == s.X0 { if m.y == s.Y && m.x1 == s.X0 {
m.x1 = s.X1 m.x1 = s.X1
} else { } else {
...@@ -237,33 +238,28 @@ func NewMonochromePainter(p Painter) *MonochromePainter { ...@@ -237,33 +238,28 @@ func NewMonochromePainter(p Painter) *MonochromePainter {
// A GammaCorrectionPainter wraps another Painter, performing gamma-correction // A GammaCorrectionPainter wraps another Painter, performing gamma-correction
// on each Span's alpha value. // on each Span's alpha value.
type GammaCorrectionPainter struct { type GammaCorrectionPainter struct {
// The wrapped Painter. // Painter is the wrapped Painter.
Painter Painter Painter Painter
// Precomputed alpha values for linear interpolation, with fully opaque == 1<<16-1. // a is the precomputed alpha values for linear interpolation, with fully
// opaque == 0xffff.
a [256]uint16 a [256]uint16
// Whether gamma correction is a no-op. // gammaIsOne is whether gamma correction is a no-op.
gammaIsOne bool gammaIsOne bool
} }
// Paint delegates to the wrapped Painter after performing gamma-correction // Paint delegates to the wrapped Painter after performing gamma-correction on
// on each Span. // each Span.
func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) { func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) {
if !g.gammaIsOne { if !g.gammaIsOne {
const ( const n = 0x101
M = 0x1010101 // 255*M == 1<<32-1
N = 0x8080 // N = M>>9, and N < 1<<16-1
)
for i, s := range ss { for i, s := range ss {
if s.A == 0 || s.A == 1<<32-1 { if s.Alpha == 0 || s.Alpha == 0xffff {
continue continue
} }
p, q := s.A/M, (s.A%M)>>9 p, q := s.Alpha/n, s.Alpha%n
// The resultant alpha is a linear interpolation of g.a[p] and g.a[p+1]. // 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 a := uint32(g.a[p])*(n-q) + uint32(g.a[p+1])*q
a = (a + N/2) / N ss[i].Alpha = (a + n/2) / n
// Convert the alpha from 16-bit (which is g.a's range) to 32-bit.
a |= a << 16
ss[i].A = a
} }
} }
g.Painter.Paint(ss, done) g.Painter.Paint(ss, done)
...@@ -271,11 +267,10 @@ func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) { ...@@ -271,11 +267,10 @@ func (g *GammaCorrectionPainter) Paint(ss []Span, done bool) {
// SetGamma sets the gamma value. // SetGamma sets the gamma value.
func (g *GammaCorrectionPainter) SetGamma(gamma float64) { func (g *GammaCorrectionPainter) SetGamma(gamma float64) {
if gamma == 1.0 { g.gammaIsOne = gamma == 1
g.gammaIsOne = true if g.gammaIsOne {
return return
} }
g.gammaIsOne = false
for i := 0; i < 256; i++ { for i := 0; i < 256; i++ {
a := float64(i) / 0xff a := float64(i) / 0xff
a = math.Pow(a, gamma) a = math.Pow(a, gamma)
......
...@@ -469,13 +469,13 @@ func (r *Rasterizer) AddStroke(q Path, width fixed.Int26_6, cr Capper, jr Joiner ...@@ -469,13 +469,13 @@ func (r *Rasterizer) AddStroke(q Path, width fixed.Int26_6, cr Capper, jr Joiner
} }
// areaToAlpha converts an area value to a uint32 alpha value. A completely // areaToAlpha converts an area value to a uint32 alpha value. A completely
// filled pixel corresponds to an area of 64*64*2, and an alpha of 1<<32-1. The // filled pixel corresponds to an area of 64*64*2, and an alpha of 0xffff. The
// conversion of area values greater than this depends on the winding rule: // conversion of area values greater than this depends on the winding rule:
// even-odd or non-zero. // even-odd or non-zero.
func (r *Rasterizer) areaToAlpha(area int) uint32 { func (r *Rasterizer) areaToAlpha(area int) uint32 {
// The C Freetype implementation (version 2.3.12) does "alpha := area>>1" // The C Freetype implementation (version 2.3.12) does "alpha := area>>1"
// without the +1. Round-to-nearest gives a more symmetric result than // without the +1. Round-to-nearest gives a more symmetric result than
// round-down. The C implementation also returns 8-bit alpha, not 32-bit // round-down. The C implementation also returns 8-bit alpha, not 16-bit
// alpha. // alpha.
a := (area + 1) >> 1 a := (area + 1) >> 1
if a < 0 { if a < 0 {
...@@ -494,8 +494,9 @@ func (r *Rasterizer) areaToAlpha(area int) uint32 { ...@@ -494,8 +494,9 @@ func (r *Rasterizer) areaToAlpha(area int) uint32 {
alpha = 0x0fff alpha = 0x0fff
} }
} }
alpha >>= 4 // alpha is now in the range [0x0000, 0x0fff]. Convert that 12-bit alpha to
return alpha * 0x01010101 // 16-bit alpha.
return alpha<<4 | alpha>>8
} }
// Rasterize converts r's accumulated curves into Spans for p. The Spans passed // Rasterize converts r's accumulated curves into Spans for p. The Spans passed
......
...@@ -468,7 +468,7 @@ func (p facePainter) Paint(ss []raster.Span, done bool) { ...@@ -468,7 +468,7 @@ func (p facePainter) Paint(ss []raster.Span, done bool) {
} }
base := (s.Y-m.Rect.Min.Y)*m.Stride - m.Rect.Min.X base := (s.Y-m.Rect.Min.Y)*m.Stride - m.Rect.Min.X
p := m.Pix[base+s.X0 : base+s.X1] p := m.Pix[base+s.X0 : base+s.X1]
color := uint8(s.A >> 24) color := uint8(s.Alpha >> 8)
for i := range p { for i := range p {
p[i] = color p[i] = color
} }
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册