如何使用Golang对图片进行渐进式加载和压缩处理

概述

在日常应用中,图片的处理是一个经常需要解决的问题,不论是在web前端还是后台(如博客),对于一张高清大图可能面临到加载缓慢、占用带宽过高等问题。本文将通过Golang来实现一种图片的渐进式加载和压缩处理,以解决这些问题。图片渐进式加载是指通过在缩略图中使用渐进式处理算法,使得在网络环境差的情况下,也可以快速的展示图片的轮廓和大概的内容,对于用户体验有很大的提升。

环境及依赖

Golang版本: 1.16.2

使用的相关依赖包: github.com/disintegration/imaging

使用Golang对图片进行操作,需要安装相关依赖包。本文中使用的是github上的disintegration/imaging包,该包是一个用来处理图片和图像的基本包,支持图片压缩、裁剪、旋转等功能。

渐进式加载实现

1. 读取原始图片并重新编码

在渐进式加载的实现过程中,我们需要将需要进行处理的原始图片重新编码为webp格式。webp是一种基于WebM格式的谷歌专利的免费的、开放源代码的图像格式,旨在提供更高的压缩率和更好的图像质量。

func getProgressiveImage(rawImgDir, progressiveImgDir string) error {

file, err := os.Open(rawImgDir)

if err != nil {

return err

}

defer file.Close()

img, _, err := image.Decode(file)

if err != nil {

return err

}

err = ioutil.WriteFile(progressiveImgDir, []byte(""), 0666)

if err != nil {

return err

}

writer, err := webp.NewEncoderFile(progressiveImgDir, webp.EncoderPreset(4))

if err != nil {

return err

}

err = writer.Encode(img)

if err != nil {

return err

}

writer.Close()

return nil

}

通过os.Open()读取需要进行处理的图片,使用image.Decode解码,然后使用webp.NewEncoderFile()创建一个webp编码器,将图片及编码器的实例传输给Encode()进行编码处理。最后返回的就是处理好的webp图片对象。需要注意的是,此时的图片已经由原来的类型,例如jpg,转换成了webp类型。

2. 生成渐进式图片

有了处理好的webp图片以后,我们需要对其进行渐进式处理,使得在加载图片时,使用者可以较快地看到图片轮廓。后续的图片细节渲染则是由更高质量的图片按需加载来完成。

func getProgressiveJpeg(rawImgDir, progressiveJpegDir string) error {

img, err := imaging.Open(rawImgDir)

if err != nil {

return err

}

progressiveImg := imaging.Encode(img, imaging.JPEGEncoder(writers.Options{Quality: 90}))

os.Remove(progressiveJpegDir)

outputFile, err := os.OpenFile(progressiveJpegDir, os.O_WRONLY|os.O_CREATE, 0666)

if err != nil {

return err

}

defer outputFile.Close()

writer, err := progressivejpeg.NewWriter(outputFile)

if err != nil {

return err

}

writer.SetBaseline(qualityFilter(90))

defer writer.Close()

_, err = outputFile.Seek(0, io.SeekStart)

if err != nil {

return err

}

_, err = io.Copy(writer, bytes.NewReader(progressiveImg))

if err != nil {

return err

}

return nil

}

这里的实现采用disintegration/imaging包的Encode()方法对图片重新编码,同时采用progressivejpeg包将其生成为渐进式Jpeg格式,以实现更快速的展示。其中, progressivejpeg.NewWriter()方法会将传入的io.Writer接口封装成一个用于逐渐的写入JPEG文件的Writer。而接下来的writer.SetBaseline()方法就是设置基线过滤器,并且返回一个基于导入器质量的过滤器。通过qualityFilter()函数进行过滤,采用90的输出质量。

3. Webp图片压缩

有些情况下,图片过大可能会造成带宽满载和页面加载过慢的情况,因此采用图片压缩方式可以有效解决这个问题。下面针对webp图片格式实现压缩处理。

func resizeImage(size int, inputPath, outputPath string, q float32, progressive bool) error {

img, err := imaging.Open(inputPath)

if err != nil {

return err

}

dstSize := size

if img.Bounds().Max.X < size && img.Bounds().Max.Y < size {

dstSize = img.Bounds().Max.X

if img.Bounds().Max.Y < dstSize {

dstSize = img.Bounds().Max.Y

}

dstSize = int(float32(dstSize) / q)

}

var finalImg *image.NRGBA

if progressive {

finalImg = imaging.New(dstSize, dstSize, color.NRGBA{0x0, 0x0, 0x0, 0x0})

} else {

finalImg = imaging.Resize(img, dstSize, dstSize, imaging.Lanczos)

}

opts := webp.Options{

Quality: qualityFilter(int(q * 100)),

TargetSize: 500,

TargetPSNR: 42,

Method: webp.PreprocessingMixed,

ImageHint: webp.Photo,

AlphaQuality: 7,

FilterStrength: 6,

FilterSharpness: 0,

FilterType: webp.AutoFilter,

ShowCompressed: true,

Segments: 4,

}

err = webp.EncodeFile(outputPath, finalImg, &opts)

if err != nil {

return err

}

return nil

}

在压缩的实现中,采用了imaging.Resize()方法对图片进行一定的缩小处理,来达到压缩的效果。同时,设置了压缩的配置选项,包括压缩质量、压缩大小、压缩方法、颜色历史记录等等。其中qualityFilter()是一个辅助函数,用于将压缩质量从0-100映射到0-9。

总结

在本文中,我们介绍了使用Golang对图片进行渐进式加载和压缩处理。其中,通过disintegration/imaging包和progressivejpeg包实现了图片的编码和渐进式处理,而通过webp包实现了对webp格式图片的压缩处理。通过这些操作,我们可以在保证图片质量的同时,提升了图片加载的速度,并且减小了图片占用的带宽。

后端开发标签