1 package imagefn 2 3 import ( 4 "image" 5 "image/color" 6 ) 7 8 type rotate90 struct { 9 image.Image 10 ax, dy int 11 } 12 13 type rotate90Set struct { 14 rotate90 15 setter 16 } 17 18 func Rotate90(i image.Image) image.Image { 19 switch i := i.(type) { 20 case *empty: 21 return i 22 case *rotate90: 23 return Rotate180(i.Image) 24 case *rotate90Set: 25 return Rotate180(i.Image) 26 case *rotate180: 27 return Rotate270(i.Image) 28 case *rotate180Set: 29 return Rotate270(i.Image) 30 case *rotate270: 31 return i.Image 32 case *rotate270Set: 33 return i.Image 34 } 35 b := i.Bounds() 36 r := rotate90{ 37 Image: i, 38 ax: b.Max.Y - b.Min.X, // x = My - mx - x 39 dy: b.Min.X - b.Min.Y, // y = mx - my + y 40 } 41 if s, ok := i.(setter); ok { 42 return &rotate90Set{ 43 rotate90: r, 44 setter: s, 45 } 46 } 47 return &r 48 } 49 50 func (r rotate90) At(x, y int) color.Color { 51 return r.Image.At(r.dy+y, r.ax-x-1) 52 } 53 54 func (r rotate90) Bounds() image.Rectangle { 55 b := r.Image.Bounds() 56 b.Min.X, b.Min.Y = b.Min.Y, b.Min.X 57 b.Max.X, b.Max.Y = b.Max.Y, b.Max.X 58 return b 59 } 60 61 func (s rotate90) SubImage(r image.Rectangle) image.Image { 62 return s.Image 63 } 64 65 func (r rotate90Set) Set(x, y int, c color.Color) { 66 r.setter.Set(r.dy+y, r.ax-x-1, c) 67 } 68 69 type rotate180 struct { 70 image.Image 71 dx, dy int 72 } 73 74 type rotate180Set struct { 75 rotate180 76 setter 77 } 78 79 func Rotate180(i image.Image) image.Image { 80 switch i := i.(type) { 81 case *empty: 82 return i 83 case *flipX: 84 return FlipY(i.Image) 85 case *flipXSet: 86 return FlipY(i.Image) 87 case *flipY: 88 return FlipX(i.Image) 89 case *flipYSet: 90 return FlipX(i.Image) 91 case *rotate90: 92 return Rotate270(i.Image) 93 case *rotate90Set: 94 return Rotate270(i.Image) 95 case *rotate180: 96 return i.Image 97 case *rotate180Set: 98 return i.Image 99 } 100 b := i.Bounds() 101 r := rotate180{ 102 Image: i, 103 dx: b.Max.X + b.Min.X, 104 dy: b.Max.Y + b.Min.Y, 105 } 106 if s, ok := i.(setter); ok { 107 return &rotate180Set{ 108 rotate180: r, 109 setter: s, 110 } 111 } 112 return &r 113 } 114 115 func (r rotate180) At(x, y int) color.Color { 116 return r.Image.At(r.dx-x-1, r.dy-y-1) 117 } 118 119 func (s rotate180) SubImage(r image.Rectangle) image.Image { 120 return SubImage(s.Image, image.Rect( 121 s.dx-r.Min.X, 122 s.dy-r.Min.Y, 123 s.dx-r.Max.X, 124 s.dy-r.Max.Y, 125 )) 126 } 127 128 func (r rotate180Set) Set(x, y int, c color.Color) { 129 r.setter.Set(r.dx-x-1, r.dy-y-1, c) 130 } 131 132 type rotate270 struct { 133 image.Image 134 dx, ay int 135 } 136 137 type rotate270Set struct { 138 rotate270 139 setter 140 } 141 142 func Rotate270(i image.Image) image.Image { 143 switch i := i.(type) { 144 case *empty: 145 return i 146 case *rotate90: 147 return i.Image 148 case *rotate90Set: 149 return i.Image 150 case *rotate180: 151 return Rotate90(i.Image) 152 case *rotate180Set: 153 return Rotate90(i.Image) 154 case *rotate270: 155 return Rotate180(i.Image) 156 case *rotate270Set: 157 return Rotate180(i.Image) 158 } 159 b := i.Bounds() 160 r := rotate270{ 161 Image: i, 162 dx: b.Min.X - b.Min.Y, // y = mx - my + x 163 ay: b.Max.X - b.Min.X, // x = Mx - mx - y 164 } 165 if s, ok := i.(setter); ok { 166 return &rotate270Set{ 167 rotate270: r, 168 setter: s, 169 } 170 } 171 return &r 172 } 173 174 func (r rotate270) At(x, y int) color.Color { 175 return r.Image.At(r.ay-y-1, r.dx+x) 176 } 177 178 func (r rotate270) Bounds() image.Rectangle { 179 b := r.Image.Bounds() 180 b.Min.X, b.Min.Y = b.Min.Y, b.Min.X 181 b.Max.X, b.Max.Y = b.Max.Y, b.Max.X 182 return b 183 } 184 185 func (s rotate270) SubImage(r image.Rectangle) image.Image { 186 return s.Image 187 } 188 189 func (r rotate270Set) Set(x, y int, c color.Color) { 190 r.setter.Set(r.ay-y-1, r.dx+x, c) 191 }