1 package imagefn 2 3 import ( 4 "image" 5 "image/color" 6 ) 7 8 type scale struct { 9 image.Image 10 ScaleX, ScaleY float64 11 } 12 13 func Scale(i image.Image, xScale, yScale float64) image.Image { 14 switch im := i.(type) { 15 case *empty: 16 return i 17 case *scale: 18 xScale *= im.ScaleX 19 yScale *= im.ScaleY 20 i = im.Image 21 } 22 if xScale < 0 { 23 if yScale < 0 { 24 i = FlipX(i) 25 } else { 26 i = Rotate180(i) 27 yScale = -yScale 28 } 29 xScale = -xScale 30 } else if yScale < 0 { 31 i = FlipY(i) 32 yScale = -yScale 33 } 34 if xScale == 0 || yScale == 0 { 35 return newEmpty(i) 36 } 37 if xScale == 1 && yScale == 1 { 38 return i 39 } 40 return &scale{ 41 Image: i, 42 ScaleX: xScale, 43 ScaleY: yScale, 44 } 45 } 46 47 func ScaleDimensions(i image.Image, x, y int) image.Image { 48 b := i.Bounds() 49 return Scale(i, float64(x)/float64(b.Dx()), float64(y)/float64(b.Dy())) 50 } 51 52 func (s *scale) Bounds() image.Rectangle { 53 b := s.Image.Bounds() 54 return image.Rect( 55 b.Min.X, 56 b.Min.Y, 57 b.Min.X+int(float64(b.Dx())/s.ScaleX), 58 b.Min.Y+int(float64(b.Dy())/s.ScaleY), 59 ) 60 } 61 62 func (s *scale) At(x, y int) color.Color { 63 b := s.Image.Bounds() 64 return s.Image.At( 65 b.Min.X+int(float64(x-b.Min.X)/s.ScaleX), 66 b.Min.Y+int(float64(y-b.Min.Y)/s.ScaleY), 67 ) 68 } 69 70 type Scaler interface { 71 At(image.Image, int, int) color.Color 72 } 73 74 type smoothScale struct { 75 scale 76 scaler Scaler 77 } 78 79 func SmoothScale(i image.Image, xScale, yScale float64, scaler Scaler) image.Image { 80 switch s := Scale(i, xScale, yScale).(type) { 81 case *scale: 82 return &smoothScale{*s, scaler} 83 default: 84 return s 85 } 86 } 87 88 func SmoothScaleDimensions(i image.Image, x, y int, scaler Scaler) image.Image { 89 b := i.Bounds() 90 return SmoothScale(i, float64(x)/float64(b.Dx()), float64(y)/float64(b.Dy()), scaler) 91 } 92 93 func (s *smoothScale) At(x, y int) color.Color { 94 return s.ColorModel().Convert(s.scaler.At(s.Image, x, y)) 95 }