package main import ( "fmt" "image" "image/color" "image/draw" "image/jpeg" "os" "path/filepath" "github.com/nfnt/resize" "golang.org/x/image/font" "golang.org/x/image/font/opentype" "golang.org/x/image/math/fixed" ) func addWatermark(img *image.RGBA, text string, textColor color.Color, bgColor color.Color) { fontData, err := os.ReadFile("/System/Library/Fonts/Courier.ttc") if err != nil { fmt.Println("Error loading font:", err) return } ttCollection, err := opentype.ParseCollection(fontData) if err != nil { fmt.Println("Error parsing font collection:", err) return } ttFont, err := ttCollection.Font(0) if err != nil { fmt.Println("Error getting font from collection:", err) return } fontSize := 20.0 face, err := opentype.NewFace(ttFont, &opentype.FaceOptions{ Size: fontSize, DPI: 72, Hinting: font.HintingFull, }) if err != nil { fmt.Println("Error creating face:", err) return } // 计算文字尺寸 d := &font.Drawer{ Dst: img, Src: image.NewUniform(textColor), Face: face, Dot: fixed.Point26_6{}, } textBounds := d.MeasureString(text) textWidth := int(textBounds.Ceil()) textHeight := int(face.Metrics().Height.Ceil()) // 设置水印文字的位置为右下角,添加内边距 padding := 8 x := img.Bounds().Max.X - textWidth - padding y := img.Bounds().Max.Y - padding - textHeight/2 + 4 // 绘制背景矩形(上下左右居中于文字) bgRect := image.Rect(x-padding/2, y-textHeight/2-padding/2+4, x+textWidth+padding/2, y+textHeight/2+padding/2) draw.Draw(img, bgRect, image.NewUniform(bgColor), image.Point{}, draw.Src) // 绘制文字 d.Dot = fixed.Point26_6{X: fixed.I(x), Y: fixed.I(y + 8)} d.DrawString(text) } func scaleAndAddWatermark(inputImagePath, outputImagePath string, scaleSize int, watermarkText string) { file, err := os.Open(inputImagePath) if err != nil { fmt.Println("Error opening file:", err) return } defer file.Close() img, _, err := image.Decode(file) if err != nil { fmt.Println("Error decoding image:", err) return } bounds := img.Bounds() width := bounds.Max.X height := bounds.Max.Y fmt.Printf("Image %s, width: %d, height: %d\n", inputImagePath, width, height) var resizedImg image.Image if width > scaleSize && height > scaleSize { if width < height { resizedImg = resize.Resize(uint(scaleSize), 0, img, resize.Lanczos3) } else { resizedImg = resize.Resize(0, uint(scaleSize), img, resize.Lanczos3) } } else { resizedImg = img } // 将图片转换为 RGBA 格式以便添加水印 rgbaImg := image.NewRGBA(resizedImg.Bounds()) if rgbaImg.Stride != rgbaImg.Rect.Size().X*4 { fmt.Println("Unsupported image format") return } for y := rgbaImg.Rect.Min.Y; y < rgbaImg.Rect.Max.Y; y++ { for x := rgbaImg.Rect.Min.X; x < rgbaImg.Rect.Max.X; x++ { rgbaImg.Set(x, y, resizedImg.At(x, y)) } } // 添加水印(使用柔和的深灰色文字和米白色背景) softTextColor := color.RGBA{R: 60, G: 60, B: 60, A: 255} softBgColor := color.RGBA{R: 250, G: 250, B: 245, A: 255} addWatermark(rgbaImg, watermarkText, softTextColor, softBgColor) outFile, err := os.Create(outputImagePath) if err != nil { fmt.Println("Error creating file:", err) return } defer outFile.Close() err = jpeg.Encode(outFile, rgbaImg, &jpeg.Options{ Quality: 95, }) if err != nil { fmt.Println("Error encoding image:", err) return } fmt.Println("Image processed and saved as", filepath.Base(outputImagePath)) } func main() { inputImagePath := "input.jpg" // 输入图片路径 outputImagePath := "output.jpg" // 输出图片路径 imageSize := 1200 // 默认尺寸 scaleAndAddWatermark(inputImagePath, outputImagePath, imageSize, "email@example.com") }