SaveUploadedFile仅做原始字节流拷贝,不解析EXIF;上传的JPG若含方向信息(如手机竖拍),后续image.Decode默认忽略exif.Orientation,导致旋转错乱。

为什么直接用 gin.Context.SaveUploadedFile 会丢失 EXIF 信息?
因为 SaveUploadedFile 底层调用的是 os.Create + io.Copy,它只做原始字节流拷贝,不解析图像元数据。上传的 JPG 若含方向信息(比如手机竖拍),后续用 image.Decode 加载时默认忽略 exif.Orientation,导致旋转错乱——压缩后图片“歪了”就是这个原因。
- 必须先用
jpeg.Decode或png.Decode解码,再通过exif.Read(需引入github.com/rwcarlsen/go-exif)提取方向 - 解码后调用
exifcommon.ApplyOrientation修正像素数据,再编码保存 - 别在保存后再读取文件二次解码——浪费 IO,且可能因并发写入出错
如何用 golang.org/x/image 实现宽高自适应缩放?
原生 image 包只提供基础裁剪和重采样,但不带“保持比例、限定最大宽高”的逻辑。你需要手动计算目标尺寸,再用 draw.ApproxBiLinear 或 draw.CatmullRom 缩放:
- 先读取原始尺寸:
img.Bounds().Dx()和img.Bounds().Dy() - 按约束条件算新尺寸:比如最大宽 1200、最大高 800,取
scale := math.Min(1200.0/float64(w), 800.0/float64(h)) - 创建目标图像:
dst := image.NewRGBA(image.Rect(0, 0, int(w*scale), int(h*scale))) - 缩放时务必用
draw.CatmullRom(比ApproxBiLinear质量高,尤其对线条和文字)
gin.Context.Request.MultipartReader 和 FormFile 选哪个?
如果只传一张图,FormFile 简单够用;但一旦要支持多图、校验文件头、或限制总上传体积,就必须用 MultipartReader 手动解析:
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
-
FormFile会把整个文件读进内存(或临时磁盘),无法中途 abort 大文件 -
MultipartReader允许边读边校验:比如检查前 4 字节是否为JPEG签名(0xFF 0xD8),不是就直接返回 400 - 配合
http.MaxBytesReader包裹c.Request.Body,可全局限制单次请求最大体积,防 DoS
压缩质量参数设多少才平衡清晰度与体积?
jpeg.Encode 的 *jpeg.Options 中 Quality 取值范围是 1–100,但实际敏感区间很窄:
立即学习“go语言免费学习笔记(深入)”;
- 75 是分水岭:低于 75,肉眼可见块状模糊(尤其文字边缘);高于 85,体积增幅快但观感提升极小
- 对 PNG 不适用——
png.Encode没有 quality 参数,靠png.Encoder的CompressionLevel(推荐flate.BestCompression或flate.DefaultCompression) - WebP 可用
golang.org/x/image/webp,支持LossyQ(70–85 较稳妥),但注意 iOS Safari 不支持 WebP
真正容易被忽略的是:缩放和压缩必须串行执行,且顺序不能颠倒——先缩放再压缩,否则高频噪声会被放大,同等质量下体积反而更大。

















