draw.draw 合成需确保源图和目标图均为 *image.rgba、op 选对(水印用 draw.over)、位置用 src.bounds().add(offset) 计算,否则出现黑块、白边、透明失效或贴歪。

直接用 image/draw 就能合成,但不处理 ColorModel 和 Op 就会贴出黑块、白边或透明失效——这不是 bug,是设计如此。
draw.Draw 报 invalid source image 怎么办
这是最常卡住的第一步。错误本质是源图和目标图的 ColorModel() 不兼容,draw.Draw 拒绝执行。
- 目标图必须用
image.NewRGBA创建(不是NewNRGBA或NewGray) - 源图如果是
*image.NRGBA、*image.Gray或其他类型,必须显式转成*image.RGBA;例如:rgbaImg := image.NewRGBA(src.Bounds()); draw.Draw(rgbaImg, rgbaImg.Bounds(), src, image.ZP, draw.Src) - 检查
src.Bounds().Max.X是否为 0——常见于 PNG 解码失败但没报错,结果得到空图 - 别依赖
image.Decode返回的图类型,它可能返回*image.NRGBA(尤其带 alpha 的 PNG),而draw.Draw对NRGBA源图行为未定义
draw.Src 和 draw.Over 混用导致水印发黑或背景残留
这两个 draw.Op 常量控制像素混合逻辑,选错就等于把 Photoshop 的“正常”模式切成了“背后”或“清除”。
-
draw.Src:源像素直接覆盖目标像素,完全忽略 alpha——适合清空区域、替换图标 -
draw.Over:按源像素 alpha 值做标准 alpha 混合(目标 × (1−α) + 源 × α),保留底层内容——所有含透明边缘的水印、文字、PNG 图标都必须用它 - 即使源图 alpha 全是 255,也建议统一用
draw.Over,避免后续加半透元素时漏改 - 如果合成后水印周围一圈纯黑/纯白,基本就是用了
draw.Src;换成draw.Over立刻修复
合成后的 PNG 保存没透明通道
你代码里明明用了 *image.RGBA 并设置了 alpha 值,但生成的 PNG 打开一看全是不透明——问题不在编码器,而在中间某步悄悄把 alpha 给“吃掉”了。
- 确保从头到尾只用
*image.RGBA:不要image.NewNRGBA()→ 转*image.RGBA,NRGBA 的 alpha 存储结构不同,转换会失真 - 检查是否在某处调用了
draw.Draw时用了draw.Src覆盖了原本带 alpha 的区域——Src会丢弃目标图 alpha,只写 RGB -
png.Encode本身支持 alpha,只要传入的是*image.RGBA且像素 alpha 值非全 255,就会写入透明通道 - 调试技巧:用
img.At(x, y)取几个点,打印c.(color.RGBA).A,确认 alpha 值确实被设进去了
位置偏移算错导致图标贴歪
draw.Draw 的第四个参数(dst 的 image.Rectangle)是以目标图坐标系为基准的,不是“贴到 (x,y)”,而是“把 src 的 Bounds() 映射到 dst 的哪一块矩形上”。
- 想把小图标贴到目标图坐标
(50, 30)处,正确写法是:draw.Draw(dst, src.Bounds().Add(image.Pt(50, 30)), src, image.ZP, draw.Over) - 错误写法:
draw.Draw(dst, image.Rect(50, 30, 50+src.Bounds().Dx(), 30+src.Bounds().Dy()), src, image.ZP, draw.Over)—— 看似一样,但若src.Bounds().Min != image.ZP(比如 src 是裁剪过的子图),就会错位 - 永远优先用
src.Bounds().Add(offset),而不是手算Rect,避免 Bounds 偏移带来的隐性偏差 - 调试建议:先用纯色小图(如 10×10 红块)测试偏移逻辑,确认位置再换真实图标
真正难的不是写几行 draw.Draw,而是记住每张图的 Bounds() 起点在哪、ColorModel() 是什么、Op 选对没——这些信息不会报错,只会静默地让结果变黑、变白、变歪。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











