bilinear.go 3.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137
  1. package captcha
  2. // Bilinear Interpolation 双线性插值
  3. // 引用自 code.google.com/p/graphics-go/interp
  4. // 主要处理旋转验证码后消除锯齿
  5. import (
  6. "image"
  7. "image/color"
  8. "math"
  9. )
  10. var bili = Bilinear{}
  11. type Bilinear struct{}
  12. func (Bilinear) RGBA(src *image.RGBA, x, y float64) color.RGBA {
  13. p := findLinearSrc(src.Bounds(), x, y)
  14. // Array offsets for the surrounding pixels.
  15. off00 := offRGBA(src, p.low.X, p.low.Y)
  16. off01 := offRGBA(src, p.high.X, p.low.Y)
  17. off10 := offRGBA(src, p.low.X, p.high.Y)
  18. off11 := offRGBA(src, p.high.X, p.high.Y)
  19. var fr, fg, fb, fa float64
  20. fr += float64(src.Pix[off00+0]) * p.frac00
  21. fg += float64(src.Pix[off00+1]) * p.frac00
  22. fb += float64(src.Pix[off00+2]) * p.frac00
  23. fa += float64(src.Pix[off00+3]) * p.frac00
  24. fr += float64(src.Pix[off01+0]) * p.frac01
  25. fg += float64(src.Pix[off01+1]) * p.frac01
  26. fb += float64(src.Pix[off01+2]) * p.frac01
  27. fa += float64(src.Pix[off01+3]) * p.frac01
  28. fr += float64(src.Pix[off10+0]) * p.frac10
  29. fg += float64(src.Pix[off10+1]) * p.frac10
  30. fb += float64(src.Pix[off10+2]) * p.frac10
  31. fa += float64(src.Pix[off10+3]) * p.frac10
  32. fr += float64(src.Pix[off11+0]) * p.frac11
  33. fg += float64(src.Pix[off11+1]) * p.frac11
  34. fb += float64(src.Pix[off11+2]) * p.frac11
  35. fa += float64(src.Pix[off11+3]) * p.frac11
  36. var c color.RGBA
  37. c.R = uint8(fr + 0.5)
  38. c.G = uint8(fg + 0.5)
  39. c.B = uint8(fb + 0.5)
  40. c.A = uint8(fa + 0.5)
  41. return c
  42. }
  43. type BilinearSrc struct {
  44. // Top-left and bottom-right interpolation sources
  45. low, high image.Point
  46. // Fraction of each pixel to take. The 0 suffix indicates
  47. // top/left, and the 1 suffix indicates bottom/right.
  48. frac00, frac01, frac10, frac11 float64
  49. }
  50. func findLinearSrc(b image.Rectangle, sx, sy float64) BilinearSrc {
  51. maxX := float64(b.Max.X)
  52. maxY := float64(b.Max.Y)
  53. minX := float64(b.Min.X)
  54. minY := float64(b.Min.Y)
  55. lowX := math.Floor(sx - 0.5)
  56. lowY := math.Floor(sy - 0.5)
  57. if lowX < minX {
  58. lowX = minX
  59. }
  60. if lowY < minY {
  61. lowY = minY
  62. }
  63. highX := math.Ceil(sx - 0.5)
  64. highY := math.Ceil(sy - 0.5)
  65. if highX >= maxX {
  66. highX = maxX - 1
  67. }
  68. if highY >= maxY {
  69. highY = maxY - 1
  70. }
  71. // In the variables below, the 0 suffix indicates top/left, and the
  72. // 1 suffix indicates bottom/right.
  73. // Center of each surrounding pixel.
  74. x00 := lowX + 0.5
  75. y00 := lowY + 0.5
  76. x01 := highX + 0.5
  77. y01 := lowY + 0.5
  78. x10 := lowX + 0.5
  79. y10 := highY + 0.5
  80. x11 := highX + 0.5
  81. y11 := highY + 0.5
  82. p := BilinearSrc{
  83. low: image.Pt(int(lowX), int(lowY)),
  84. high: image.Pt(int(highX), int(highY)),
  85. }
  86. // Literally, edge cases. If we are close enough to the edge of
  87. // the image, curtail the interpolation sources.
  88. if lowX == highX && lowY == highY {
  89. p.frac00 = 1.0
  90. } else if sy-minY <= 0.5 && sx-minX <= 0.5 {
  91. p.frac00 = 1.0
  92. } else if maxY-sy <= 0.5 && maxX-sx <= 0.5 {
  93. p.frac11 = 1.0
  94. } else if sy-minY <= 0.5 || lowY == highY {
  95. p.frac00 = x01 - sx
  96. p.frac01 = sx - x00
  97. } else if sx-minX <= 0.5 || lowX == highX {
  98. p.frac00 = y10 - sy
  99. p.frac10 = sy - y00
  100. } else if maxY-sy <= 0.5 {
  101. p.frac10 = x11 - sx
  102. p.frac11 = sx - x10
  103. } else if maxX-sx <= 0.5 {
  104. p.frac01 = y11 - sy
  105. p.frac11 = sy - y01
  106. } else {
  107. p.frac00 = (x01 - sx) * (y10 - sy)
  108. p.frac01 = (sx - x00) * (y11 - sy)
  109. p.frac10 = (x11 - sx) * (sy - y00)
  110. p.frac11 = (sx - x10) * (sy - y01)
  111. }
  112. return p
  113. }
  114. func offRGBA(src *image.RGBA, x, y int) int {
  115. return (y-src.Rect.Min.Y)*src.Stride + (x-src.Rect.Min.X)*4
  116. }