github.com/laof/lite-speed-test@v0.0.0-20230930011949-1f39b7037845/web/render/pattern.go (about)

     1  package render
     2  
     3  import (
     4  	"image"
     5  	"image/color"
     6  
     7  	"github.com/golang/freetype/raster"
     8  )
     9  
    10  type RepeatOp int
    11  
    12  const (
    13  	RepeatBoth RepeatOp = iota
    14  	RepeatX
    15  	RepeatY
    16  	RepeatNone
    17  )
    18  
    19  type Pattern interface {
    20  	ColorAt(x, y int) color.Color
    21  }
    22  
    23  // Solid Pattern
    24  type solidPattern struct {
    25  	color color.Color
    26  }
    27  
    28  func (p *solidPattern) ColorAt(x, y int) color.Color {
    29  	return p.color
    30  }
    31  
    32  func NewSolidPattern(color color.Color) Pattern {
    33  	return &solidPattern{color: color}
    34  }
    35  
    36  // Surface Pattern
    37  type surfacePattern struct {
    38  	im image.Image
    39  	op RepeatOp
    40  }
    41  
    42  func (p *surfacePattern) ColorAt(x, y int) color.Color {
    43  	b := p.im.Bounds()
    44  	switch p.op {
    45  	case RepeatX:
    46  		if y >= b.Dy() {
    47  			return color.Transparent
    48  		}
    49  	case RepeatY:
    50  		if x >= b.Dx() {
    51  			return color.Transparent
    52  		}
    53  	case RepeatNone:
    54  		if x >= b.Dx() || y >= b.Dy() {
    55  			return color.Transparent
    56  		}
    57  	}
    58  	x = x%b.Dx() + b.Min.X
    59  	y = y%b.Dy() + b.Min.Y
    60  	return p.im.At(x, y)
    61  }
    62  
    63  func NewSurfacePattern(im image.Image, op RepeatOp) Pattern {
    64  	return &surfacePattern{im: im, op: op}
    65  }
    66  
    67  type patternPainter struct {
    68  	im   *image.RGBA
    69  	mask *image.Alpha
    70  	p    Pattern
    71  }
    72  
    73  // Paint satisfies the Painter interface.
    74  func (r *patternPainter) Paint(ss []raster.Span, done bool) {
    75  	b := r.im.Bounds()
    76  	for _, s := range ss {
    77  		if s.Y < b.Min.Y {
    78  			continue
    79  		}
    80  		if s.Y >= b.Max.Y {
    81  			return
    82  		}
    83  		if s.X0 < b.Min.X {
    84  			s.X0 = b.Min.X
    85  		}
    86  		if s.X1 > b.Max.X {
    87  			s.X1 = b.Max.X
    88  		}
    89  		if s.X0 >= s.X1 {
    90  			continue
    91  		}
    92  		const m = 1<<16 - 1
    93  		y := s.Y - r.im.Rect.Min.Y
    94  		x0 := s.X0 - r.im.Rect.Min.X
    95  		// RGBAPainter.Paint() in $GOPATH/src/github.com/golang/freetype/raster/paint.go
    96  		i0 := (s.Y-r.im.Rect.Min.Y)*r.im.Stride + (s.X0-r.im.Rect.Min.X)*4
    97  		i1 := i0 + (s.X1-s.X0)*4
    98  		for i, x := i0, x0; i < i1; i, x = i+4, x+1 {
    99  			ma := s.Alpha
   100  			if r.mask != nil {
   101  				ma = ma * uint32(r.mask.AlphaAt(x, y).A) / 255
   102  				if ma == 0 {
   103  					continue
   104  				}
   105  			}
   106  			c := r.p.ColorAt(x, y)
   107  			cr, cg, cb, ca := c.RGBA()
   108  			dr := uint32(r.im.Pix[i+0])
   109  			dg := uint32(r.im.Pix[i+1])
   110  			db := uint32(r.im.Pix[i+2])
   111  			da := uint32(r.im.Pix[i+3])
   112  			a := (m - (ca * ma / m)) * 0x101
   113  			r.im.Pix[i+0] = uint8((dr*a + cr*ma) / m >> 8)
   114  			r.im.Pix[i+1] = uint8((dg*a + cg*ma) / m >> 8)
   115  			r.im.Pix[i+2] = uint8((db*a + cb*ma) / m >> 8)
   116  			r.im.Pix[i+3] = uint8((da*a + ca*ma) / m >> 8)
   117  		}
   118  	}
   119  }
   120  
   121  func newPatternPainter(im *image.RGBA, mask *image.Alpha, p Pattern) *patternPainter {
   122  	return &patternPainter{im, mask, p}
   123  }