当然!在 Golang 中为图片添加水印和文字是一个非常常见的需求。下面我将提供一个完整的、可直接运行的示例代码,并详细解释其中的关键步骤。
![图片[1]_Golang实现为图片添加水印和文字的示例代码_知途无界](https://zhituwujie.com/wp-content/uploads/2026/02/d2b5ca33bd20260207104143.png)
我们将使用 Go 标准库中的 image 包来处理图片,以及 draw 包来合成图像,font 包来处理文字。
核心思路
- 打开并解码原始图片:读取作为底图的图片文件(如 JPEG、PNG)。
- 创建绘图上下文:准备一个可以在原始图片上进行绘制的画布。
- 加载字体:为了渲染清晰的中文文字,我们需要加载一个 TTF 字体文件。这是关键一步,否则中文会显示为乱码或方框。
- 绘制文字水印:设置文字颜色、大小、位置和对齐方式,然后在画布上绘制文字。
- 打开并解码水印图片:读取作为水印的图片(通常是 PNG 格式,支持透明背景)。
- 绘制图片水印:计算水印图片的位置(例如右下角),并将其绘制到原始图片上。
- 编码并保存新图片:将绘制好的最终图像编码为指定格式(如 JPEG 或 PNG)并保存到文件。
示例代码
首先,确保你的项目目录结构如下,并下载一个中文字体文件(如思源黑体、阿里巴巴普惠体等)。
your-project/
├── go.mod
├── main.go
└── fonts/
└── SourceHanSansCN-Regular.ttf # 你需要自己下载这个字体文件
└── images/
├── background.jpg # 你的原始图片
└── watermark.png # 你的水印图片 (最好是带透明通道的PNG)
以下是 main.go 的完整代码:
package main
import (
"flag"
"fmt"
"image"
"image/color"
"image/draw"
"image/jpeg"
"image/png"
"io/ioutil"
"log"
"os"
"golang.org/x/image/font"
"golang.org/x/image/font/opentype"
"golang.org/x/image/math/fixed"
)
// 命令行参数
var (
bgImagePath = flag.String("bg", "images/background.jpg", "背景图片路径")
textWatermark = flag.String("text", "机密文件 请勿外传", "文字水印内容")
watermarkImage = flag.String("logo", "images/watermark.png", "Logo水印图片路径")
outputPath = flag.String("output", "output.jpg", "输出图片路径")
fontPath = flag.String("font", "fonts/SourceHanSansCN-Regular.ttf", "TTF字体文件路径")
)
func main() {
flag.Parse()
// 1. 打开并解码背景图片
bgFile, err := os.Open(*bgImagePath)
if err != nil {
log.Fatalf("打开背景图片失败: %v", err)
}
defer bgFile.Close()
bgImg, _, err := image.Decode(bgFile)
if err != nil {
log.Fatalf("解码背景图片失败: %v", err)
}
// 2. 创建一个与背景图同样大小的RGBA图像作为画布
// RGBA 支持透明度,非常适合用于合成
rgba := image.NewRGBA(bgImg.Bounds())
draw.Draw(rgba, rgba.Bounds(), bgImg, image.Point{}, draw.Src)
// 3. 加载字体
fontBytes, err := ioutil.ReadFile(*fontPath)
if err != nil {
log.Fatalf("读取字体文件失败: %v", err)
}
// 解析TTF字体文件
ft, err := opentype.Parse(fontBytes)
if err != nil {
log.Fatalf("解析字体文件失败: %v", err)
}
// 根据字体大小创建字体face
const fontSize = 40
face, err := opentype.NewFace(ft, &opentype.FaceOptions{
Size: fontSize,
DPI: 72,
Hinting: font.HintingFull,
})
if err != nil {
log.Fatalf("创建字体失败: %v", err)
}
// 4. 在画布上绘制文字水印
drawer := &font.Drawer{
Dst: rgba,
Src: image.NewUniform(color.RGBA{R: 255, G: 0, B: 0, A: 128}), // 半透明的红色
Face: face,
Dot: fixed.P(50, 50+fontSize), // 起始点坐标 (X, Y)。Y坐标是基线位置,所以要加上字体大小。
}
// 设置要绘制的文字
drawer.Dot.X = fixed.I((rgba.Bounds().Dx() - drawer.MeasureString(*textWatermark).Round()) / 2) // 水平居中
drawer.DrawString(*textWatermark)
// 5. 打开并解码Logo水印图片
logoFile, err := os.Open(*watermarkImage)
if err != nil {
log.Fatalf("打开Logo水印图片失败: %v", err)
}
defer logoFile.Close()
logoImg, _, err := image.Decode(logoFile)
if err != nil {
log.Fatalf("解码Logo水印图片失败: %v", err)
}
// 6. 在画布上绘制Logo水印 (例如,放在右下角)
logoBounds := logoImg.Bounds()
logoWidth := logoBounds.Dx()
logoHeight := logoBounds.Dy()
// 计算放置位置 (距离右边缘和下边缘各20像素)
position := image.Point{
X: rgba.Bounds().Dx() - logoWidth - 20,
Y: rgba.Bounds().Dy() - logoHeight - 20,
}
// 使用 draw.Over 模式,使Logo的透明通道生效
draw.Draw(rgba, image.Rectangle{Min: position, Max: position.Add(logoImg.Bounds().Size())}, logoImg, logoImg.Bounds().Min, draw.Over)
// 7. 创建输出文件并编码为新图片
outputFile, err := os.Create(*outputPath)
if err != nil {
log.Fatalf("创建输出文件失败: %v", err)
}
defer outputFile.Close()
// 根据输出文件扩展名决定编码器
switch *outputPath {
case "output.png":
err = png.Encode(outputFile, rgba)
default: // 默认为 jpeg
// 将RGBA转换为NRGBA以满足JPEG编码器的要求,并设置质量
jpegImg := image.NewNRGBA(rgba.Bounds())
draw.Draw(jpegImg, jpegImg.Bounds(), rgba, image.Point{}, draw.Src)
err = jpeg.Encode(outputFile, jpegImg, &jpeg.Options{Quality: 90})
}
if err != nil {
log.Fatalf("编码输出图片失败: %v", err)
}
fmt.Printf("成功生成带水印的图片: %s\n", *outputPath)
}
如何运行
- 初始化 Go Module:
go mod init image-watermark-example - 获取依赖:
代码中使用了golang.org/x/image下的非标准库,需要手动获取。go get golang.org/x/image/font go get golang.org/x/image/font/opentype go get golang.org/x/image/math/fixed go get golang.org/x/image/draw # 通常draw在image包内,但为了清晰列出注意:由于网络原因,直接获取可能会失败。如果失败,请设置 GOPROXY:go env -w GOPROXY=https://goproxy.cn,direct go get ... - 准备文件:
- 将你的背景图片放到
images/background.jpg。 - 将你的Logo水印(最好是透明PNG)放到
images/watermark.png。 - 下载一个中文字体(如 思源黑体),解压后将
.ttf文件(如SourceHanSansCN-Regular.ttf)放到fonts/目录下。
- 将你的背景图片放到
- 运行程序:
go run main.go或者使用自定义参数:go run main.go -bg my_bg.png -text "我的水印" -logo my_logo.png -output result.png -font fonts/my_font.ttf
运行成功后,你会在项目根目录下看到生成的 output.jpg 文件,上面已经添加了居中的红色半透明文字水印和右下的Logo水印。
关键点解释
- **
image.RGBA**: 我们创建了一个 RGBA 图像作为绘制画布,因为它支持 Alpha 通道(透明度),这对于叠加水印而不完全遮盖原图至关重要。 - **
golang.org/x/image/font**: 这是处理字体的关键。标准库的image包不支持直接渲染文字,必须借助这个扩展库。 - 字体加载:
opentype.Parse和opentype.NewFace是从 TTF 文件创建可用字体对象的必经之路。没有这一步,任何非ASCII字符(如中文)都无法正确渲染。 - **
font.Drawer**: 这是一个强大的工具,用于控制文字的绘制。MeasureString方法可以测量文字的宽度,从而实现居中或右对齐等效果。Dot属性设置了文字绘制的起始点。 - **
draw.Draw和draw.Over**:draw.Draw是基础绘制函数。draw.Over操作符会考虑源图像和目标图像的Alpha值,实现正确的“正片叠底”混合效果,对于透明Logo水印是必须的。而draw.Src则会直接覆盖目标区域的像素。 - JPEG 与 PNG: JPEG 不支持透明度,所以在编码为 JPEG 前,我们从 RGBA 转换到了 NRGBA。
jpeg.Options可以设置压缩质量。PNG 则完美支持透明度。
© 版权声明
文中内容均来源于公开资料,受限于信息的时效性和复杂性,可能存在误差或遗漏。我们已尽力确保内容的准确性,但对于因信息变更或错误导致的任何后果,本站不承担任何责任。如需引用本文内容,请注明出处并尊重原作者的版权。
THE END























暂无评论内容