rotate.go 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990
  1. package service
  2. import (
  3. "image"
  4. "math"
  5. )
  6. type rotate struct {
  7. dx float64
  8. dy float64
  9. sin float64
  10. cos float64
  11. neww float64
  12. newh float64
  13. src *image.RGBA
  14. }
  15. func (r *rotate) rotate(angle float64, src *image.RGBA) *rotate {
  16. r.src = src
  17. srsize := src.Bounds().Size()
  18. width, height := srsize.X, srsize.Y
  19. // 源图四个角的坐标(以图像中心为坐标系原点)
  20. // 左下角,右下角,左上角,右上角
  21. srcwp, srchp := float64(width)*0.5, float64(height)*0.5
  22. srcx1, srcy1 := -srcwp, srchp
  23. srcx2, srcy2 := srcwp, srchp
  24. srcx3, srcy3 := -srcwp, -srchp
  25. srcx4, srcy4 := srcwp, -srchp
  26. r.sin, r.cos = math.Sincos(radian(angle))
  27. // 旋转后的四角坐标
  28. desx1, desy1 := r.cos*srcx1+r.sin*srcy1, -r.sin*srcx1+r.cos*srcy1
  29. desx2, desy2 := r.cos*srcx2+r.sin*srcy2, -r.sin*srcx2+r.cos*srcy2
  30. desx3, desy3 := r.cos*srcx3+r.sin*srcy3, -r.sin*srcx3+r.cos*srcy3
  31. desx4, desy4 := r.cos*srcx4+r.sin*srcy4, -r.sin*srcx4+r.cos*srcy4
  32. // 新的高度很宽度
  33. r.neww = math.Max(math.Abs(desx4-desx1), math.Abs(desx3-desx2)) + 0.5
  34. r.newh = math.Max(math.Abs(desy4-desy1), math.Abs(desy3-desy2)) + 0.5
  35. r.dx = -0.5*r.neww*r.cos - 0.5*r.newh*r.sin + srcwp
  36. r.dy = 0.5*r.neww*r.sin - 0.5*r.newh*r.cos + srchp
  37. return r
  38. }
  39. func radian(angle float64) float64 {
  40. return angle * math.Pi / 180.0
  41. }
  42. func (r *rotate) transformRGBA() image.Image {
  43. srcb := r.src.Bounds()
  44. b := image.Rect(0, 0, int(r.neww), int(r.newh))
  45. dst := image.NewRGBA(b)
  46. for y := b.Min.Y; y < b.Max.Y; y++ {
  47. for x := b.Min.X; x < b.Max.X; x++ {
  48. sx, sy := r.pt(x, y)
  49. if inBounds(srcb, sx, sy) {
  50. // 消除锯齿填色
  51. c := bili.RGBA(r.src, sx, sy)
  52. off := (y-dst.Rect.Min.Y)*dst.Stride + (x-dst.Rect.Min.X)*4
  53. dst.Pix[off+0] = c.R
  54. dst.Pix[off+1] = c.G
  55. dst.Pix[off+2] = c.B
  56. dst.Pix[off+3] = c.A
  57. }
  58. }
  59. }
  60. return dst
  61. }
  62. func (r *rotate) pt(x, y int) (float64, float64) {
  63. return float64(-y)*r.sin + float64(x)*r.cos + r.dy,
  64. float64(y)*r.cos + float64(x)*r.sin + r.dx
  65. }
  66. func inBounds(b image.Rectangle, x, y float64) bool {
  67. if x < float64(b.Min.X) || x >= float64(b.Max.X) {
  68. return false
  69. }
  70. if y < float64(b.Min.Y) || y >= float64(b.Max.Y) {
  71. return false
  72. }
  73. return true
  74. }
  75. func offRGBA(src *image.RGBA, x, y int) int {
  76. return (y-src.Rect.Min.Y)*src.Stride + (x-src.Rect.Min.X)*4
  77. }