diff --git a/image-scale-and-addwatermark/go.mod b/image-scale-and-addwatermark/go.mod new file mode 100644 index 0000000..481f121 --- /dev/null +++ b/image-scale-and-addwatermark/go.mod @@ -0,0 +1,10 @@ +module hatter.ink/tool/image-scale-and-addwatermark + +go 1.25.5 + +require ( + github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 + golang.org/x/image v0.36.0 +) + +require golang.org/x/text v0.34.0 // indirect diff --git a/image-scale-and-addwatermark/go.sum b/image-scale-and-addwatermark/go.sum new file mode 100644 index 0000000..a4c3c93 --- /dev/null +++ b/image-scale-and-addwatermark/go.sum @@ -0,0 +1,6 @@ +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ= +github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8= +golang.org/x/image v0.36.0 h1:Iknbfm1afbgtwPTmHnS2gTM/6PPZfH+z2EFuOkSbqwc= +golang.org/x/image v0.36.0/go.mod h1:YsWD2TyyGKiIX1kZlu9QfKIsQ4nAAK9bdgdrIsE7xy4= +golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= +golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= diff --git a/image-scale-and-addwatermark/main.go b/image-scale-and-addwatermark/main.go new file mode 100644 index 0000000..0334321 --- /dev/null +++ b/image-scale-and-addwatermark/main.go @@ -0,0 +1,136 @@ +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 main() { + inputImagePath := "input.jpg" // 输入图片路径 + outputImagePath := "output.jpg" // 输出图片路径 + + maxSize := 1200 // 默认最大尺寸 + + 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 > maxSize && height > maxSize { + if width < height { + resizedImg = resize.Resize(uint(maxSize), 0, img, resize.Lanczos3) + } else { + resizedImg = resize.Resize(0, uint(maxSize), 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, "email@example.com", 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, nil) + if err != nil { + fmt.Println("Error encoding image:", err) + return + } + + fmt.Println("Image processed and saved as", filepath.Base(outputImagePath)) +}