From 9d584333850ab231b57382f380515476a8fb0f3d Mon Sep 17 00:00:00 2001 From: Leon Wolf Date: Tue, 28 Jan 2020 23:56:57 +0100 Subject: [PATCH] Initial Resize Function --- .gitignore | 2 + LICENSE | 2 +- README.md | 153 ++++++++++++++++++++++++++++++++++++++++++++++++- resize.go | 45 +++++++++++++++ resize_test.go | 44 ++++++++++++++ 5 files changed, 243 insertions(+), 3 deletions(-) create mode 100644 resize.go create mode 100644 resize_test.go diff --git a/.gitignore b/.gitignore index 66fd13c..b986336 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +.idea/ \ No newline at end of file diff --git a/LICENSE b/LICENSE index c03c6a2..ece7bc1 100644 --- a/LICENSE +++ b/LICENSE @@ -18,4 +18,4 @@ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +SOFTWARE. \ No newline at end of file diff --git a/README.md b/README.md index 17b8218..372777d 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,151 @@ -# canvas -A simple go library for transforming images using mostly native go functionalitys +# This package is no longer being updated! Please look for alternatives if that bothers you. + +Resize +====== + +Image resizing for the [Go programming language](http://golang.org) with common interpolation methods. + +[![Build Status](https://travis-ci.org/nfnt/resize.svg)](https://travis-ci.org/nfnt/resize) + +Installation +------------ + +```bash +$ go get github.com/nfnt/resize +``` + +It's that easy! + +Usage +----- + +This package needs at least Go 1.1. Import package with + +```go +import "github.com/nfnt/resize" +``` + +The resize package provides 2 functions: + +* `resize.Resize` creates a scaled image with new dimensions (`width`, `height`) using the interpolation function `interp`. + If either `width` or `height` is set to 0, it will be set to an aspect ratio preserving value. +* `resize.Thumbnail` downscales an image preserving its aspect ratio to the maximum dimensions (`maxWidth`, `maxHeight`). + It will return the original image if original sizes are smaller than the provided dimensions. + +```go +resize.Resize(width, height uint, img image.Image, interp resize.InterpolationFunction) image.Image +resize.Thumbnail(maxWidth, maxHeight uint, img image.Image, interp resize.InterpolationFunction) image.Image +``` + +The provided interpolation functions are (from fast to slow execution time) + +- `NearestNeighbor`: [Nearest-neighbor interpolation](http://en.wikipedia.org/wiki/Nearest-neighbor_interpolation) +- `Bilinear`: [Bilinear interpolation](http://en.wikipedia.org/wiki/Bilinear_interpolation) +- `Bicubic`: [Bicubic interpolation](http://en.wikipedia.org/wiki/Bicubic_interpolation) +- `MitchellNetravali`: [Mitchell-Netravali interpolation](http://dl.acm.org/citation.cfm?id=378514) +- `Lanczos2`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=2 +- `Lanczos3`: [Lanczos resampling](http://en.wikipedia.org/wiki/Lanczos_resampling) with a=3 + +Which of these methods gives the best results depends on your use case. + +Sample usage: + +```go +package main + +import ( + "github.com/nfnt/resize" + "image/jpeg" + "log" + "os" +) + +func main() { + // open "test.jpg" + file, err := os.Open("test.jpg") + if err != nil { + log.Fatal(err) + } + + // decode jpeg into image.Image + img, err := jpeg.Decode(file) + if err != nil { + log.Fatal(err) + } + file.Close() + + // resize to width 1000 using Lanczos resampling + // and preserve aspect ratio + m := resize.Resize(1000, 0, img, resize.Lanczos3) + + out, err := os.Create("test_resized.jpg") + if err != nil { + log.Fatal(err) + } + defer out.Close() + + // write new image to file + jpeg.Encode(out, m, nil) +} +``` + +Caveats +------- + +* Optimized access routines are used for `image.RGBA`, `image.NRGBA`, `image.RGBA64`, `image.NRGBA64`, `image.YCbCr`, `image.Gray`, and `image.Gray16` types. All other image types are accessed in a generic way that will result in slow processing speed. +* JPEG images are stored in `image.YCbCr`. This image format stores data in a way that will decrease processing speed. A resize may be up to 2 times slower than with `image.RGBA`. + + +Downsizing Samples +------- + +Downsizing is not as simple as it might look like. Images have to be filtered before they are scaled down, otherwise aliasing might occur. +Filtering is highly subjective: Applying too much will blur the whole image, too little will make aliasing become apparent. +Resize tries to provide sane defaults that should suffice in most cases. + +### Artificial sample + +Original image +![Rings](http://nfnt.github.com/img/rings_lg_orig.png) + + + + + + + + + + + + + + +

Nearest-Neighbor

Bilinear

Bicubic

Mitchell-Netravali

Lanczos2

Lanczos3
+ +### Real-Life sample + +Original image +![Original](http://nfnt.github.com/img/IMG_3694_720.jpg) + + + + + + + + + + + + + + +

Nearest-Neighbor

Bilinear

Bicubic

Mitchell-Netravali

Lanczos2

Lanczos3
+ + +License +------- + +Copyright (c) 2012 Jan Schlicht +Resize is released under a MIT style license. diff --git a/resize.go b/resize.go new file mode 100644 index 0000000..be7172e --- /dev/null +++ b/resize.go @@ -0,0 +1,45 @@ +package canvas + +import ( + "golang.org/x/image/draw" + "image" +) + +type InterpolationFunction int + +// 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 + default: + return draw.CatmullRom + } +} + +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 + } + // 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 +} diff --git a/resize_test.go b/resize_test.go new file mode 100644 index 0000000..181ee2d --- /dev/null +++ b/resize_test.go @@ -0,0 +1,44 @@ +package canvas + +import ( + "image" + "image/color" + "log" + "runtime" + "testing" +) + +var img = image.NewNRGBA(image.Rect(0, 0, 5, 5)) + +func init() { + runtime.GOMAXPROCS(runtime.NumCPU()) + img.Set(5, 5, color.Black) +} + +func Test_SameSize(t *testing.T) { + newImg, _ := Resize(img, 0, 0, CatmullRom) + 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) { + newImg, err := Resize(img, 0, 100, CatmullRom) + if err != nil || newImg.Bounds().Dy() != 100 || newImg.Bounds().Dx() != 100 { + t.Fail() + } +} +func Test_Width(t *testing.T) { + newImg, err := Resize(img, 200, 0, CatmullRom) + if err != nil || newImg.Bounds().Dy() != 200 || newImg.Bounds().Dx() != 200 { + t.Fail() + } +} +func Test_WidthAndHeight(t *testing.T) { + newImg, err := Resize(img, 300, 300, CatmullRom) + if err != nil || newImg.Bounds() != image.Rect(0, 0, 300, 300) { + t.Fail() + } +}