Golang压缩Jpeg图片和PNG图片的操作
来源:脚本之家
时间:2022-12-29 10:17:10 407浏览 收藏
本篇文章给大家分享《Golang压缩Jpeg图片和PNG图片的操作》,覆盖了Golang的常见基础知识,其实一个语言的全部知识点一篇文章是不可能说完的,但希望通过这些问题,让读者对自己的掌握程度有一定的认识(B 数),从而弥补自己的不足,更好的掌握它。
博主一直在维护一个导出PDF的服务,但是这个服务导出的PDF文件是真的巨大,动辄就上百MB。这里面主要是图片占据了大多数体积,所以考虑在导出前压缩一下图片。
Jpeg的图片压缩是很好做的,因为jpeg这个协议本身就支持调整图片质量的。在golang中,我们只需要使用标准库的image/jpeg,将图片从二进制数据解码后,降低质量再编码为二进制数据即可实现压缩。而且质量和压缩比例相对而言还不错。
func compressImageResource(data []byte) []byte { img, _, err := image.Decode(bytes.NewReader(data)) if err != nil { return data } buf := bytes.Buffer{} err = jpeg.Encode(&buf, img, &jpeg.Options{Quality: 40}) if err != nil { return data } if buf.Len() > len(data) { return data } return buf.Bytes() }
比较麻烦的是压缩PNG图片,在网上找了很多相关的库,感觉都没什么即可以保持质量,又可以尽可能压缩的办法。
//下面这两个库都比较偏重于转换图片大小,在保持宽高不变的情况下,压缩比例很一般 https://github.com/discord/lilliput //这个库是一家海外公司基于C语言的一个开源图片处理库,但是封装的很好,不需要安装额外依赖 https://github.com/disintegration/imaging //下面这个库可以对PNG图片进行较大的压缩,可惜压缩比例过大时会严重失真 https://github.com/foobaz/lossypng/
后来,借鉴一篇博客的做法,还是先把PNG图片转换为Jpeg图片,然后再将jpeg图片的质量降低。相对上边这些库,压缩比例和质量都比较令人满意
func compressImageResource(data []byte) []byte { imgSrc, _, err := image.Decode(bytes.NewReader(data)) if err != nil { return data } newImg := image.NewRGBA(imgSrc.Bounds()) draw.Draw(newImg, newImg.Bounds(), &image.Uniform{C: color.White}, image.Point{}, draw.Src) draw.Draw(newImg, newImg.Bounds(), imgSrc, imgSrc.Bounds().Min, draw.Over) buf := bytes.Buffer{} err = jpeg.Encode(&buf, newImg, &jpeg.Options{Quality: 40}) if err != nil { return data } if buf.Len() > len(data) { return data } return buf.Bytes() }
最后给大家分享一个超级好用PDF处理的golang 库: https://github.com/unidoc/unipdf。一开始使用这个库将生成后的PDF压缩的,可以将一个200M的PDF(里面都是图片)直接压缩到7M左右。可惜的是这个库商用需要购买商业版权,所以最后只能采取了导出前压缩图片的做法。
这个库没有授权的情况下会在处理后的PDF中加上水印,这个想去掉也简单,fork下来改一下代码就好了。虽然我这里因为是商业的场景不能这么用,但是我还是尝试了下,仓库在这:https://github.com/lianggx6/unipdf。然后再在go.mod文件中将依赖替换即可。大家如果有个人开发实践需要的可以直接这样拿来用,商用务必购买版权。
replace ( github.com/unidoc/unipdf/v3 => github.com/lianggx6/unipdf v0.0.0-20200409043947-1c871b2c4951 )
补充:golang中image/jpeg包和image/png包用法
jpeg包实现了jpeg图片的编码和解码
func Decode(r io.Reader) (image.Image, error) //Decode读取一个jpeg文件,并将他作为image.Image返回 func DecodeConfig(r io.Reader) (image.Config, error) //无需解码整个图像,DecodeConfig变能够返回整个图像的尺寸和颜色(Config具体定义查看gif包中的定义) func Encode(w io.Writer, m image.Image, o *Options) error //按照4:2:0的基准格式将image写入w中,如果options为空的话,则传递默认参数 type Options struct { Quality int }
Options是编码参数,它的取值范围是1-100,值越高质量越好
type FormatError //用来报告一个输入不是有效的jpeg格式 type FormatError string func (e FormatError) Error() string type Reader //不推荐使用Reader type Reader interface { io.ByteReader io.Reader } type UnsupportedError func (e UnsupportedError) Error() string //报告输入使用一个有效但是未实现的jpeg功能
利用程序画一条直线,代码如下:
package main import ( "fmt" "image" "image/color" "image/jpeg" "math" "os" ) const ( dx = 500 dy = 300 ) type Putpixel func(x, y int) func drawline(x0, y0, x1, y1 int, brush Putpixel) { dx := math.Abs(float64(x1 - x0)) dy := math.Abs(float64(y1 - y0)) sx, sy := 1, 1 if x0 >= x1 { sx = -1 } if y0 >= y1 { sy = -1 } err := dx - dy for { brush(x0, y0) if x0 == x1 && y0 == y1 { return } e2 := err * 2 if e2 > -dy { err -= dy x0 += sx } if e2根据已经得到的图像test.jpg,我们创建一个新的图像test1.jpg
package main import ( "fmt" "image/jpeg" "os" ) func main() { file, err := os.Open("test.jpg") if err != nil { fmt.Println(err) } defer file.Close() file1, err := os.Create("test1.jpg") if err != nil { fmt.Println(err) } defer file1.Close() img, err := jpeg.Decode(file) //解码 if err != nil { fmt.Println(err) } jpeg.Encode(file1, img, &jpeg.Options{5}) //编码,但是将图像质量从100改成5 }对比图像质量为100和5的图像:
image/png包用法:
image/png实现了png图像的编码和解码
png和jpeg实现方法基本相同,都是对图像进行了编码和解码操作。
func Decode(r io.Reader) (image.Image, error) //Decode从r中读取一个图片,并返回一个image.image,返回image类型取决于png图片的内容 func DecodeConfig(r io.Reader) (image.Config, error) //无需解码整个图像变能够获取整个图片的尺寸和颜色 func Encode(w io.Writer, m image.Image) error //Encode将图片m以PNG的格式写到w中。任何图片都可以被编码,但是哪些不是image.NRGBA的图片编码可能是有损的。 type FormatError func (e FormatError) Error() string //FormatError会提示一个输入不是有效PNG的错误。 type UnsupportedError func (e UnsupportedError) Error() string //UnsupportedError会提示输入使用一个合法的,但是未实现的PNG特性。利用png包实现一个png的图像,代码如下:
package main import ( "fmt" "image" "image/color" "image/png" "os" ) const ( dx = 256 dy = 256 ) func Pic(dx, dy int) [][]uint8 { pic := make([][]uint8, dx) for i := range pic { pic[i] = make([]uint8, dy) for j := range pic[i] { pic[i][j] = uint8(i * j % 255) } } return pic } func main() { file, err := os.Create("test.png") if err != nil { fmt.Println(err) } defer file.Close() rgba := image.NewRGBA(image.Rect(0, 0, dx, dy)) for x := 0; x图像如下:
由此可见,png和jpeg使用方法类似,只是两种不同的编码和解码方式。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持golang学习网。如有错误或未考虑完全的地方,望不吝赐教。
好了,本文到此结束,带大家了解了《Golang压缩Jpeg图片和PNG图片的操作》,希望本文对你有所帮助!关注golang学习网公众号,给大家分享更多Golang知识!
-
427 收藏
-
421 收藏
-
500 收藏
-
425 收藏
-
164 收藏
-
266 收藏
-
444 收藏
-
311 收藏
-
266 收藏
-
188 收藏
-
- 前端进阶之JavaScript设计模式
- 设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
- 立即学习 542次学习
-
- GO语言核心编程课程
- 本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
- 立即学习 507次学习
-
- 简单聊聊mysql8与网络通信
- 如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
- 立即学习 497次学习
-
- JavaScript正则表达式基础与实战
- 在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
- 立即学习 487次学习
-
- 从零制作响应式网站—Grid布局
- 本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
- 立即学习 484次学习