pattern.go 2.4 KB

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