golang进行图片缩放的坑

782 阅读2分钟

错误的原因

图片缩放要用这个包: "golang.org/x/image/draw",标准库里面的包不支持缩放。

解析图片的时候,需要先注册解析器,才能去解析,否则会报错 image.png

func TrimImage() {
	// 打开原始图片文件
	f, err := os.Open("../../../uml/add_favor.png")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	// 解码图片
	img, ff, err := image.Decode(f) //这个方法需要先注册对应图片类型的解析器,否则会报错,png和jpeg的解析器都在对应包的init方法里面
	if err != nil {
		log.Fatal(err, ff)
	}
	trimImage(img)
}

不注册解析器对应的报错 image.png

正确的代码

package utils

import (
	"bytes"
	"encoding/base64"
	"image"
	_ "image/gif" //注册gif对应的解析器
	"image/jpeg"
	_ "image/png" //注册png对应的解析器
	"log"
	"os"

	_ "golang.org/x/image/bmp" //注册bmp对应的解析器
	"golang.org/x/image/draw"
	_ "golang.org/x/image/tiff" //注册tiff对应的解析器
	_ "golang.org/x/image/webp" //注册webp对应的解析器
)

func TrimImage() {
	// 打开原始图片文件
	f, err := os.Open("../../../uml/add_favor.png")
	if err != nil {
		log.Fatal(err)
	}
	defer f.Close()
	// 解码图片
	img, ff, err := image.Decode(f)
	if err != nil {
		log.Fatal(err, ff)
	}
	trimImage(img)
}

type ImageTrimRes struct {
	Width     int
	Height    int
	ThumbData []byte
}

func trimImage(img image.Image) *ImageTrimRes {
	// 计算宽高比
	width := img.Bounds().Dx()
	height := img.Bounds().Dy()
	ratio := float64(width) / float64(height)

	// 计算目标宽高
	var targetWidth, targetHeight int
	if width > height {
		targetWidth = 50
		targetHeight = int(float64(targetWidth) / ratio)
	} else {
		targetHeight = 50
		targetWidth = int(float64(targetHeight) * ratio)
	}

	// 缩放图片
	dst := image.NewRGBA(image.Rect(0, 0, targetWidth, targetHeight))
	draw.CatmullRom.Scale(dst, dst.Bounds(), img, img.Bounds(), draw.Over, nil)

	// 保存图片
	//out, err := os.Create("cropped.png")
	//if err != nil {
	//	log.Fatal(err)
	//}
	//defer out.Close()
	//png.Encode(out, dst)

	// 转jpeg
	//out, err := os.Create("cropped.jpeg")
	//if err != nil {
	//	log.Fatal(err)
	//}
	//defer out.Close()

	// 将图片保存为JPEG格式
	//err := jpeg.Encode(out, dst, &opts)
	//if err != nil {
	//	log.Fatal(err)
	//}

	// 设置JPEG压缩选项
	opts := &jpeg.Options{
		Quality: 90, // 设置压缩质量为90%
	}
	// 将图片转为字节流
	var buf bytes.Buffer
	err := jpeg.Encode(&buf, img, opts)
	if err != nil {
		log.Fatal(err)
	}

	// 字节流进行base64编码
	byteSlice := buf.Bytes()
	var resBytes []byte
	base64.StdEncoding.Encode(resBytes, byteSlice)
	return &ImageTrimRes{
		Width:     width,
		Height:    height,
		ThumbData: resBytes,
	}
}


func TestTrimImage(t *testing.T) {
	TrimImage()
}

使用场景

比如发图片消息的时候,需要缩略模糊图和长宽信息让客户端进行预览和渲染,所以需要服务端处理图片。

一般云服务厂商也提供了这种能力,比如阿里云你在长传一个图片以后,支持你下载该图片对应的缩略图,只是url需要做一些处理