Go语言批量压缩JPG图片与添加水印实现方案
在使用Go语言进行图片自动化处理时,核心在于文件遍历、图像解码缩放及图层合成。本指南基于github.com/nfnt/resize库,详解如何批量压缩JPG格式图片至指定宽度,并演示如何通过PNG透明图叠加实现水印功能,附带完整的可执行代码结构。
项目准备与依赖
在开始编码前,需要确保本地环境已安装Go语言开发工具链。本项目主要依赖一个第三方图像处理库 github.com/nfnt/resize,该库专注于高性能的JPG图片尺寸调整。
操作顺序如下:
- 创建新的Go模块或进入现有项目目录。
- 初始化依赖:运行命令
go get github.com/nfnt/resize以获取最新稳定版本。 - 准备好待处理的源图片文件夹(建议为jpg格式)以及用于水印的半透明PNG背景图片。
核心功能实现步骤
第1步:递归遍历目标目录
目的:自动查找指定路径下所有子文件夹中的JPG图片,避免逐个手动选择。
入口:主函数 main() 中调用自定义的 cmd(path string) 函数,传入起始目录如 "data/"。
动作说明:
- 使用标准库
ioutil.ReadDir读取目录下所有文件和子文件夹。 - 判断对象类型:若为文件夹,则递归调用自身进入下一层;若为文件,则检查文件名是否包含
.jpg后缀(忽略大小写)。
第2步:执行图片压缩与重命名
目的:将原始大图压缩为适合网页展示的尺寸,并生成随机文件名以防冲突。
参数设置:
- 目标宽度:
2048像素。 - 算法选择:
resize.Lanczos3,提供高质量的缩放效果。 - 输出质量:
jpeg.Options{80},平衡文件大小与视觉清晰度。
动作说明:
- 打开原始图片并解码为
image.Image接口。 - 调用
resize.Resize方法计算新尺寸,保持宽高比(高度传0表示自适应)。 - 创建新的输出文件并使用
jpeg.Encode写入磁盘。 - 原文示例中使用了随机文件名
random_name()以避免覆盖,实际生产环境中建议保留原文件名或增加时间戳。
第3步:生成缩略图(可选)
目的:为列表页或预览区生成更小尺寸的封面图。
动作说明:
- 复用原始解码后的图像数据。
- 调用
resize.Thumbnail方法,严格限制宽和高(如480x360),若比例不符将裁剪居中部分。 - 保存为独立的小图文件,通常命名为带特定后缀(如
@small.jpg)。
第4步:添加文字或图形水印
目的:保护版权或在图片上叠加品牌标识。
入口逻辑:虽然原文注释掉了水印功能,但提供了完整实现思路 cmd_watermark。
动作说明:
- 加载素材:同时打开目标图片和水印底图(
watermark.png)。 - 创建画布:实例化
image.NewNRGBA作为最终合成的画布,大小与原图一致。 - 绘制底层:使用
draw.Draw将原图内容复制到画布上,混合模式为draw.Src。 - 绘制上层:再次使用
draw.Draw将水印图贴到画布上。通过image.Pt(30, 30)设置偏移量,使水印距离左上角有一定间距,混合模式选draw.Over以支持透明通道。 - 保存结果:通常水印环节建议使用更高的JPEG质量(如95)以减少噪点。
完整源代码参考
以下代码整合了上述所有功能,可直接复制修改后运行。请注意,实际使用时需根据本地路径调整输入输出目录。
package main
import (
"fmt"
"github.com/nfnt/resize"
"image"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"log"
"math/rand"
"os"
"strconv"
"strings"
"time"
)
func main() {
// 优化并发性能,默认Go已根据CPU核数设置,此处显式声明
runtime.GOMAXPROCS(runtime.NumCPU())
cmd("data/")
fmt.Println("OK!")
}
// 执行操作 - 递归遍历与调度
func cmd(path string) {
files, _ := ioutil.ReadDir(path)
for _, file := range files {
if file.IsDir() {
fmt.Println("目录" + file.Name())
cmd(path + file.Name() + "/")
} else {
// 仅处理JPG文件
if strings.Contains(strings.ToLower(file.Name()), ".jpg") {
// 随机名称,防止重复
to := path + random_name() + ".jpg"
origin := path + file.Name()
fmt.Println("正在处理" + origin + ">>>>" + to)
// 压缩主图
cmd_resize(origin, 2048, 0, to)
// 注意:原文此处直接删除了原文件,生产环境请谨慎操作!
// defer os.Remove(origin)
}
}
}
}
// 改变大小 - 等比缩放
func cmd_resize(file string, width uint, height uint, to string) {
file_origin, _ := os.Open(file)
origin, _ := jpeg.Decode(file_origin)
defer file_origin.Close()
canvas := resize.Resize(width, height, origin, resize.Lanczos3)
file_out, err := os.Create(to)
if err != nil {
log.Fatal(err)
}
defer file_out.Close()
jpeg.Encode(file_out, canvas, &jpeg.Options{80})
// 如需自动生成缩略图,可取消下面注释
// cmd_thumbnail(to, 480, 360, strings.Replace(to, ".jpg", "@small.jpg", 1))
// 如需添加水印,可调用 cmd_watermark
// cmd_watermark(to, strings.Replace(to, ".jpg", "_wm.jpg", 1))
}
// 生成缩略图 - 强制尺寸
func cmd_thumbnail(file string, width uint, height uint, to string) {
file_origin, _ := os.Open(file)
origin, _ := jpeg.Decode(file_origin)
defer file_origin.Close()
canvas := resize.Thumbnail(width, height, origin, resize.Lanczos3)
file_out, err := os.Create(to)
if err != nil {
log.Fatal(err)
}
defer file_out.Close()
jpeg.Encode(file_out, canvas, &jpeg.Options{80})
}
// 水印处理
func cmd_watermark(file string, to string) {
file_origin, _ := os.Open(file)
origin, _ := jpeg.Decode(file_origin)
defer file_origin.Close()
// 打开水印图 (需保证是PNG格式以支持透明)
file_watermark, _ := os.Open("watermark.png")
watermark, _ := png.Decode(file_watermark)
defer file_watermark.Close()
// 原始图界限
origin_size := origin.Bounds()
// 创建新图层
canvas := image.NewNRGBA(origin_size)
// 贴原始图
draw.Draw(canvas, origin_size, origin, image.ZP, draw.Src)
// 贴水印图,Pt(30,30)为右上角偏移
draw.Draw(canvas, watermark.Bounds().Add(image.Pt(30, 30)), watermark, image.ZP, draw.Over)
// 生成新图片,高质量保存
create_image, _ := os.Create(to)
jpeg.Encode(create_image, canvas, &jpeg.Options{95})
defer create_image.Close()
}
// 随机生成文件名
func random_name() string {
rand.Seed(time.Now().UnixNano())
return strconv.Itoa(rand.Int())
}
注意事项与排错
风险提醒:原文代码中包含 os.Remove(origin) 用于删除原图,这在自动化脚本中极具破坏性。在执行前务必备份原始数据,或将该行注释掉,仅执行“另存为新文件”的操作。
格式限制:当前代码硬编码了 jpeg.Decode 和 .jpg 匹配,若需支持 PNG/WebP,需引入 image/png 或相关转换库,并动态判断文件格式。
性能优化:对于海量图片处理,建议结合 sync.WaitGroup 或协程池并发处理,以提升 CPU 利用率。
总结
通过Go语言的 image 系列包配合第三方缩放库,可以高效地完成图片的后处理任务。从基础的尺寸压缩到高级的图层水印,逻辑清晰且易于扩展。以上就是Go语言实现批量压缩图片和水印的详细内容,更多关于Go语言图像处理技巧的资料请关注本站其它相关文章!
免责声明:本文内容仅供参考,不代表本站观点。转载或引用请注明出处。









