Jorge Olivero
Jorge Olivero

Reputation: 3853

Go Resizing Images

I am using the Go resize package here: https://github.com/nfnt/resize

  1. I am pulling an Image from S3, as such:

    image_data, err := mybucket.Get(key)
    // this gives me data []byte
    
  2. After that, I need to resize the image:

    new_image := resize.Resize(160, 0, original_image, resize.Lanczos3)
    // problem is that the original_image has to be of type image.Image
    
  3. Upload the image to my S3 bucket

    err : = mybucket.Put('newpath', new_image, 'image/jpg', 'aclstring')
    // problem is that new image needs to be data []byte
    

How do I transform a data []byte to ---> image.Image and back to ----> data []byte?

Upvotes: 43

Views: 76415

Answers (5)

Hesam Eskandari
Hesam Eskandari

Reputation: 96

No third party package. The following code can reduce the image size to minimum 50px height.

func resizeImage(img image.RGBA, height int) image.RGBA {
    if height < 50 {
        return img
    }
    bounds := img.Bounds()
    imgHeight := bounds.Dy()
    if height >= imgHeight {
        return img
    }
    imgWidth := bounds.Dx()
    resizeFactor := float32(imgHeight) / float32(height)
    ratio := float32(imgWidth) / float32(imgHeight)
    width := int(float32(height) * ratio)
    resizedImage := image.NewRGBA(image.Rect(0, 0, width, height))
    var imgX, imgY int
    var imgColor color.Color
    for x := 0; x < width; x++ {
        for y := 0; y < height; y++ {
            imgX = int(resizeFactor*float32(x) + 0.5)
            imgY = int(resizeFactor*float32(y) + 0.5)
            imgColor = img.At(imgX, imgY)
            resizedImage.Set(x, y, imgColor)
        }
    }
    return *resizedImage
}

Upvotes: 0

Inkeliz
Inkeliz

Reputation: 1091

The OP is using a specific library/package, but I think that the issue of "Go Resizing Images" can be solved without that package.

You can resize de image using golang.org/x/image/draw:

input, _ := os.Open("your_image.png")
defer input.Close()

output, _ := os.Create("your_image_resized.png")
defer output.Close()

// Decode the image (from PNG to image.Image):
src, _ := png.Decode(input)

// Set the expected size that you want:
dst := image.NewRGBA(image.Rect(0, 0, src.Bounds().Max.X/2, src.Bounds().Max.Y/2))

// Resize:
draw.NearestNeighbor.Scale(dst, dst.Rect, src, src.Bounds(), draw.Over, nil)

// Encode to `output`:      
png.Encode(output, dst)

In that case I choose draw.NearestNeighbor, because it's faster, but looks worse. but there's other methods, you can see on https://pkg.go.dev/golang.org/x/image/draw#pkg-variables:

  • draw.NearestNeighbor
    NearestNeighbor is the nearest neighbor interpolator. It is very fast, but usually gives very low quality results. When scaling up, the result will look 'blocky'.

  • draw.ApproxBiLinear
    ApproxBiLinear is a mixture of the nearest neighbor and bi-linear interpolators. It is fast, but usually gives medium quality results.

  • draw.BiLinear
    BiLinear is the tent kernel. It is slow, but usually gives high quality results.

  • draw.CatmullRom
    CatmullRom is the Catmull-Rom kernel. It is very slow, but usually gives very high quality results.

Upvotes: 59

Mr_Pink
Mr_Pink

Reputation: 109367

Read http://golang.org/pkg/image

// you need the image package, and a format package for encoding/decoding
import (
    "bytes"
    "image"
    "image/jpeg" // if you don't need to use jpeg.Encode, use this line instead 
    // _ "image/jpeg"

    "github.com/nfnt/resize"

    
)

// Decoding gives you an Image.
// If you have an io.Reader already, you can give that to Decode 
// without reading it into a []byte.
image, _, err := image.Decode(bytes.NewReader(data))
// check err

newImage := resize.Resize(160, 0, original_image, resize.Lanczos3)

// Encode uses a Writer, use a Buffer if you need the raw []byte
err = jpeg.Encode(someWriter, newImage, nil)
// check err

Upvotes: 66

Tomas
Tomas

Reputation: 135

You could use bimg, which is powered by libvips (a fast image processing library written in C).

If you are looking for a image resizing solution as a service, take a look to imaginary

Upvotes: 5

Maxim Kachurovskiy
Maxim Kachurovskiy

Reputation: 3022

Want to do it 29 times faster? Try amazing vipsthumbnail instead:

sudo apt-get install libvips-tools
vipsthumbnail --help-all

This will resize and nicely crop saving result to a file:

vipsthumbnail original.jpg -s 700x200 -o 700x200.jpg -c

Calling from Go:

func resizeExternally(from string, to string, width uint, height uint) error {
    var args = []string{
        "--size", strconv.FormatUint(uint64(width), 10) + "x" +
            strconv.FormatUint(uint64(height), 10),
        "--output", to,
        "--crop",
        from,
    }
    path, err := exec.LookPath("vipsthumbnail")
    if err != nil {
        return err
    }
    cmd := exec.Command(path, args...)
    return cmd.Run()
}

Upvotes: 10

Related Questions