diff --git a/resize.go b/resize.go index be7172e..ccd133a 100644 --- a/resize.go +++ b/resize.go @@ -1,45 +1,43 @@ package canvas import ( - "golang.org/x/image/draw" "image" + "math" ) -type InterpolationFunction int +func Resize(img image.Image, newWidth int, newHeight int, intFunc string) image.Image { -// InterpolationFunction constants -const ( - Bilinear InterpolationFunction = iota - CatmullRom -) - -// kernal, returns an InterpolationFunctions taps and kernel. -func (i InterpolationFunction) kernel() *draw.Kernel { - switch i { - case Bilinear: - return draw.BiLinear - case CatmullRom: - return draw.CatmullRom + if newWidth == 0 && newHeight == 0 { + newWidth = img.Bounds().Dx() + newHeight = img.Bounds().Dy() + } else if newWidth == 0 && newHeight != 0 { + newWidth = img.Bounds().Dx() / img.Bounds().Dy() * newHeight + } else if newWidth != 0 && newHeight == 0 { + newHeight = img.Bounds().Dy() / img.Bounds().Dx() * newWidth + } + // perform resizing + switch intFunc { + case "NearestNeighbor": + return ScaleNearestNeighbor(img, newWidth, newHeight) default: - return draw.CatmullRom + return ScaleNearestNeighbor(img, newWidth, newHeight) } } -func Resize(img image.Image, width int, height int, intFunc InterpolationFunction) (image.Image, error) { - - if width == 0 && height == 0 { - width = img.Bounds().Dx() - height = img.Bounds().Dy() - } else if width == 0 && height != 0 { - width = img.Bounds().Dx() / img.Bounds().Dy() * height - } else if width != 0 && height == 0 { - height = img.Bounds().Dy() / img.Bounds().Dx() * width +func ScaleNearestNeighbor(img image.Image, newWidth int, newHeight int) image.Image { + targetRect := image.Rect(0, 0, newWidth, newHeight) + targetImg := image.NewNRGBA(targetRect) + width := img.Bounds().Dx() + height := img.Bounds().Dy() + for x := 0; x <= width; x++ { + for y := 0; y <= height; y++ { + srcX := int(math.Round(float64(x) / float64(newWidth) * float64(width))) + srcY := int(math.Round(float64(y) / float64(newHeight) * float64(height))) + srcX = int(math.Min(float64(srcX), float64(width-1))) + srcX = int(math.Min(float64(srcY), float64(height-1))) + tarPixel := img.At(srcX, srcY) + targetImg.Set(x, y, tarPixel) + } } - // new size of image - dstRect := image.Rect(0, 0, width, height) - // perform resizing - dstImg := image.NewRGBA(dstRect) - intFunc.kernel().Scale(dstImg, dstRect, img, img.Bounds(), draw.Over, nil) - - return dstImg, nil + return targetImg } diff --git a/resize_test.go b/resize_test.go index 86eaa39..9410cc8 100644 --- a/resize_test.go +++ b/resize_test.go @@ -9,45 +9,46 @@ import ( ) var img = image.NewNRGBA(image.Rect(0, 0, 5, 5)) -var kernels = []InterpolationFunction{CatmullRom, Bilinear} func init() { runtime.GOMAXPROCS(runtime.NumCPU()) img.Set(5, 5, color.Black) } +func Test_NNScale(t *testing.T) { + newImg := Resize(img, 100, 100, "NearestNeighbor") + if newImg.Bounds().Dx() != 100 || newImg.Bounds().Dy() != 100 { + t.Fail() + } +} + func Test_SameSize(t *testing.T) { - for _, kernel := range kernels { - newImg, _ := Resize(img, 0, 0, kernel) - if newImg.Bounds() != img.Bounds() { - log.Print(img.Bounds().Dx(), "x", img.Bounds().Dy()) - log.Print(newImg.Bounds().Dx(), "x", newImg.Bounds().Dy()) - t.Fail() - } + + newImg := Resize(img, 0, 0, "NearestNeighbor") + if newImg.Bounds() != img.Bounds() { + log.Print(img.Bounds().Dx(), "x", img.Bounds().Dy()) + log.Print(newImg.Bounds().Dx(), "x", newImg.Bounds().Dy()) + t.Fail() } + } func Test_Height(t *testing.T) { - for _, kernel := range kernels { - newImg, err := Resize(img, 0, 100, kernel) - if err != nil || newImg.Bounds().Dy() != 100 || newImg.Bounds().Dx() != 100 { - t.Fail() - } + + newImg := Resize(img, 0, 100, "NearestNeighbor") + if newImg.Bounds().Dy() != 100 || newImg.Bounds().Dx() != 100 { + t.Fail() } } func Test_Width(t *testing.T) { - for _, kernel := range kernels { - newImg, err := Resize(img, 200, 0, kernel) - if err != nil || newImg.Bounds().Dy() != 200 || newImg.Bounds().Dx() != 200 { - t.Fail() - } + newImg := Resize(img, 200, 0, "NearestNeighbor") + if newImg.Bounds().Dy() != 200 || newImg.Bounds().Dx() != 200 { + t.Fail() } } func Test_WidthAndHeight(t *testing.T) { - for _, kernel := range kernels { - newImg, err := Resize(img, 300, 300, kernel) - if err != nil || newImg.Bounds() != image.Rect(0, 0, 300, 300) { - t.Fail() - } + newImg := Resize(img, 300, 300, "NearestNeighbor") + if newImg.Bounds() != image.Rect(0, 0, 300, 300) { + t.Fail() } }