Go图片大小调整

38

我在这里使用Go的resize包:https://github.com/nfnt/resize

  1. 我正在从S3中获取图像,如下所示:

    image_data, err := mybucket.Get(key)
    // this gives me data []byte
    
  2. 接下来,我需要调整图像大小:

    new_image := resize.Resize(160, 0, original_image, resize.Lanczos3)
    // problem is that the original_image has to be of type image.Image
    
  3. 将图像上传到我的S3存储桶中

    err : = mybucket.Put('newpath', new_image, 'image/jpg', 'aclstring')
    // problem is that new image needs to be data []byte
    
    我该如何将数据[]byte转换为image.Image,然后再将其转回数据[]byte

4个回答

66

阅读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

太棒了。在“image/jpeg”之前的下划线是用来干什么的?另外,如何让我访问字节变量?最后,如何重新编码为[]byte?非常感谢。 - Jorge Olivero
4
下划线用于仅导入某个模块的附带效果(在本例中是注册解码器)。如果要使用 jpeg.Encode,请不要使用下划线进行导入。 bytes 是标准库中的一个包。 - JimB
如果您知道输入图像是jpeg格式,可以使用jpeg.Decode(而不是image.Decode)进行解码。 - oliverpool
11
你从哪里导入这个“resize”包? - nmurthy
6
我看到很多人特别推荐这个库,但是我刚刚查了一下,它已经不再得到支持。你可能想要寻找其他选项,如@Inkeliz提供的答案。 - micker

45

OP使用了一个特定的库/包,但我认为“Go调整图像”的问题可以在不使用该包的情况下解决。

您可以使用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)

在这种情况下,我选择draw.NearestNeighbor,因为它更快,但外观较差。但还有其他方法,你可以在https://pkg.go.dev/golang.org/x/image/draw#pkg-variables上看到:

  • draw.NearestNeighbor
    NearestNeighbor是最近邻插值器。它非常快,但通常会产生非常低质量的结果。当缩放时,结果将看起来很“块状”。

  • draw.ApproxBiLinear
    ApproxBiLinear是最近邻和双线性插值器的混合物。它很快,但通常会产生中等质量的结果。

  • draw.BiLinear
    BiLinear是帐篷卷积核。它很慢,但通常会产生高质量的结果。

  • draw.CatmullRom
    CatmullRom是Catmull-Rom卷积核。它非常慢,但通常会产生非常高质量的结果。


9

想要将其速度加快 29倍 吗?尝试神奇的vipsthumbnail代替:

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

这将调整大小并进行漂亮的裁剪,结果将保存到文件中:
vipsthumbnail original.jpg -s 700x200 -o 700x200.jpg -c

来自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()
}

10
如果系统调用不可取,也有一个绑定可以使用。 - transistor09
5
使用这种方法可以实现可移植性,值得注意的是。使用纯Go语言可以在Go支持的每个操作系统/架构上实现可移植性。 - joonas.fi
@joonas.fi,这个库值得推荐吗? - gbenroscience
4
抱歉,我之前的回答有误。现在我正式翻译一下:@gbenroscience,抱歉打错字了,我本意是说“失去可移植性”。我的意思是,因为它调用了外部程序,所以你的Go程序不是自包含的,也不能像纯Go语言那样提供最高程度的可移植性。采用已接受回答中的代码能够更好地解决这个问题。 - joonas.fi
3
这个答案与原问题有什么关联? - Ariel Monaco
显示剩余2条评论

4
您可以使用由C编写的快速图像处理库libvips支持的bimg进行图像处理。

如果您正在寻找图像调整解决方案作为服务,请查看imaginary


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接