golang给图片添加文字水印

  1. pdf
import (
	"bytes"
	"github.com/pdfcpu/pdfcpu/pkg/api"
	"github.com/pdfcpu/pdfcpu/pkg/font"
	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
	"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/validate"
	"io"
	"strconv"
)

func addWatermark(text string, in io.ReadSeeker) (*bytes.Buffer, error) {
	desc := hackWM(0)

	var wm *model.Watermark
	wm, err := api.TextWatermark(text, desc, true, false, types.POINTS)
	if err != nil {
		return nil, err
	}

	realFontSize := wm.ScaledFontSize
	if realFontSize <= 0 {
		realFontSize = wm.FontSize
	}
	lineHeight := font.LineHeight(wm.FontName, realFontSize)
	singleLineWidth := font.TextWidth(text, wm.FontName, realFontSize)
	targetLineWidth := singleLineWidth
	targetText := text

	lineSpace := int(lineHeight)
	var ctxCpu *model.Context
	ctxCpu, err = readValidateAndOptimize(in, api.LoadConfiguration())
	if err != nil {
		return nil, err
	}
	var dms []types.Dim
	dms, err = ctxCpu.PageDims()
	if err != nil {
		return nil, err
	}

	var wmsSliceMap = map[int][]*model.Watermark{}
	for k, dm := range dms {
		curPage := k + 1
		dy := 0
		//重复水印文字
		for dm.Width >= targetLineWidth {
			targetText += "    " + text
			targetLineWidth = font.TextWidth(targetText, wm.FontName, realFontSize)
		}
		for float64(dy)*-1 < dm.Height {
			wm, err = api.TextWatermark(targetText, hackWM(dy), true, false, types.POINTS)
			wmsSliceMap[curPage] = append(wmsSliceMap[curPage], wm)
			dy -= lineSpace + int(lineHeight)
		}
	}
	out := new(bytes.Buffer)
	err = api.AddWatermarksSliceMap(in, out, wmsSliceMap, nil)
	if err != nil {
		return nil, err
	}

	return out, nil
}
  1. jpg、png
package watermark

import (
	"bytes"
	"fmt"
	"github.com/disintegration/imaging"
	"github.com/golang/freetype"
	"golang.org/x/image/colornames"
	"image"
	"image/color"
	"image/draw"
	"image/gif"
	"image/jpeg"
	"image/png"
	"io"
	"os"

	"github.com/golang/freetype/truetype"
)

func AddTextWatermark2Pic(text string, source io.ReadSeeker, inch float64) ([]byte, error) {
	// 使用自定义参数创建Watermarker
	wm, err := NewWatermarker(
		WithWatermarkString(text),                  // 水印文字
		WithWatermarkColor(colornames.Map["grey"]), // 水印颜色
		WithSkew(30),   // 倾斜角度
		WithStepX(250), // 水平间距
		WithStepY(130), // 垂直间距
		WithFontPath("src/font/NotoSansSC-Regular.ttf"), // 字体文件路径
	)
	if inch == 0 {
		inch = 15.6
	}
	wm.inch = inch
	if err != nil {
		fmt.Println("创建自定义Watermarker出错:", err)
		return nil, err
	}
	watermarkedData, err := wm.AddWatermark(source, "image/jpeg")
	if err != nil {
		fmt.Println("添加水印出错:", err)
		return nil, err
	}
	return watermarkedData, nil
}

func main() {
	// 使用自定义参数创建Watermarker
	customColor := color.RGBA{R: 255, G: 0, B: 0, A: 80} // 红色
	wm, err := NewWatermarker(
		WithWatermarkString("自定义水印"),    // 水印文字
		WithWatermarkColor(customColor), // 水印颜色
		WithSkew(30),                    // 倾斜角度
		WithStepX(250),                  // 水平间距
		WithStepY(130),                  // 垂直间距
		WithFontPath("customFont.ttf"),  // 字体文件路径
	)
	if err != nil {
		fmt.Println("创建自定义Watermarker出错:", err)
		return
	}

	// 打开要添加水印的图像文件
	file, err := os.Open("path_to_image.jpg")
	if err != nil {
		fmt.Println("打开图像文件出错:", err)
		return
	}
	defer file.Close()

	// 为图像添加水印
	watermarkedData, err := wm.AddWatermark(file, "image/jpeg")
	if err != nil {
		fmt.Println("添加水印出错:", err)
		return
	}

	// 保存处理后的图像到当前目录
	outputFile, err := os.Create("watermarked_image.jpg")
	if err != nil {
		fmt.Println("创建输出文件出错:", err)
		return
	}
	defer outputFile.Close()

	_, err = outputFile.Write(watermarkedData)
	if err != nil {
		fmt.Println("写入输出文件出错:", err)
		return
	}

	fmt.Println("水印图像已成功保存为 watermarked_image.jpg")
}

// Watermarker 结构体,封装了添加水印所需的属性
type Watermarker struct {
	watermarkString string         // 水印文字
	watermarkColor  *image.Uniform // 水印颜色
	skew            float64        // 倾斜度
	stepX, stepY    int            // X轴和Y轴的步长
	font            *truetype.Font // 字体
	fontSize        float64        // 字体大小
	dpi             float64        // dpi
	inch            float64        // 英寸
}

func (w *Watermarker) SetDpi(dpi float64) {
	w.dpi = dpi
}

type WatermarkerOptions struct {
	WatermarkString *string
	WatermarkColor  *color.RGBA
	Skew            *float64
	StepX, StepY    *int
	FontPath        *string
}

type WatermarkerOptionSetter func(*WatermarkerOptions)

func WithWatermarkString(s string) WatermarkerOptionSetter {
	return func(opt *WatermarkerOptions) {
		opt.WatermarkString = &s
	}
}

func WithWatermarkColor(c color.RGBA) WatermarkerOptionSetter {
	return func(opt *WatermarkerOptions) {
		opt.WatermarkColor = &c
	}
}

func WithSkew(s float64) WatermarkerOptionSetter {
	return func(opt *WatermarkerOptions) {
		opt.Skew = &s
	}
}

func WithStepX(x int) WatermarkerOptionSetter {
	return func(opt *WatermarkerOptions) {
		opt.StepX = &x
	}
}

func WithStepY(y int) WatermarkerOptionSetter {
	return func(opt *WatermarkerOptions) {
		opt.StepY = &y
	}
}

func WithFontPath(path string) WatermarkerOptionSetter {
	return func(opt *WatermarkerOptions) {
		opt.FontPath = &path
	}
}

func NewWatermarker(setters ...WatermarkerOptionSetter) (*Watermarker, error) {
	opt := &WatermarkerOptions{}

	for _, setter := range setters {
		setter(opt)
	}

	watermarkString := "Default Watermark" // 默认值
	if opt.WatermarkString != nil {
		watermarkString = *opt.WatermarkString
	}

	watermarkColor := color.RGBA{R: 128, G: 128, B: 128, A: 80} // 默认灰色,半透明
	if opt.WatermarkColor != nil {
		watermarkColor = *opt.WatermarkColor
	}

	skew := 22.5 // 默认倾斜度
	if opt.Skew != nil {
		skew = *opt.Skew
	}

	stepX := 240 // 默认X轴步长
	if opt.StepX != nil {
		stepX = *opt.StepX
	}

	stepY := 120 // 默认Y轴步长
	if opt.StepY != nil {
		stepY = *opt.StepY
	}

	fontPath := "SourceHanSansCN-Bold.ttf" // 默认字体路径
	if opt.FontPath != nil {
		fontPath = *opt.FontPath
	}

	fontBytes, err := os.ReadFile(fontPath)
	if err != nil {
		return nil, fmt.Errorf("读取字体文件出错: %w", err)
	}

	fnt, err := truetype.Parse(fontBytes)
	if err != nil {
		return nil, fmt.Errorf("解析字体出错: %w", err)
	}

	return &Watermarker{
		watermarkString: watermarkString,
		watermarkColor:  image.NewUniform(watermarkColor),
		skew:            skew,
		stepX:           stepX,
		stepY:           stepY,
		font:            fnt,
		fontSize:        12,
	}, nil
}

// GifAddWaterMark 为GIF图像添加水印
func (w *Watermarker) GifAddWaterMark(imgFile io.Reader) ([]byte, error) {
	img, err := gif.DecodeAll(imgFile)
	if err != nil {
		return nil, fmt.Errorf("解码GIF出错: %w", err)
	}

	newGIF := &gif.GIF{}
	for i, frame := range img.Image {
		newImg := image.NewPaletted(frame.Bounds(), frame.Palette)
		draw.Draw(newImg, newImg.Bounds(), frame, frame.Bounds().Min, draw.Src)

		w.writeWatermark(newImg)

		newGIF.Image = append(newGIF.Image, newImg)
		newGIF.Delay = append(newGIF.Delay, img.Delay[i])
		newGIF.Disposal = append(newGIF.Disposal, img.Disposal[i])
	}

	var buf bytes.Buffer
	err = gif.EncodeAll(&buf, newGIF)
	if err != nil {
		return nil, fmt.Errorf("编码GIF出错: %w", err)
	}
	return buf.Bytes(), nil
}

// ImageAddWaterMark 为普通图像添加水印
func (w *Watermarker) ImageAddWaterMark(imgFile io.Reader, format string) ([]byte, error) {
	img, _, err := image.Decode(imgFile)
	if err != nil {
		return nil, fmt.Errorf("解码图像出错: %w", err)
	}

	newImg := image.NewNRGBA(img.Bounds())
	//dy := float64(img.Bounds().Dy())
	//dx := float64(img.Bounds().Dx())
	//dpi := math.Sqrt(math.Pow(dx, 2)+math.Pow(dy, 2)) / w.inch
	w.SetDpi(150)

	draw.Draw(newImg, newImg.Bounds(), img, img.Bounds().Min, draw.Src)

	w.writeWatermark(newImg)

	var buf bytes.Buffer
	switch format {
	case "jpeg", "jpg":
		err = jpeg.Encode(&buf, newImg, &jpeg.Options{Quality: 100})
	case "png":
		err = png.Encode(&buf, newImg)
	default:
		return nil, fmt.Errorf("不支持的图像格式: %s", format)
	}
	if err != nil {
		return nil, fmt.Errorf("编码图像出错: %w", err)
	}
	return buf.Bytes(), nil
}

// writeWatermark 是一个私有方法,用于在图像上写入水印
func (w *Watermarker) writeWatermark(newImg draw.Image) {
	for y := -w.stepY; y <= newImg.Bounds().Max.Y+w.stepY; y += w.stepY {
		for x := -w.stepX; x <= newImg.Bounds().Max.X+w.stepX; x += w.stepX {
			offsetX := 0
			if (y/w.stepY)%2 == 1 {
				offsetX = w.stepX / 2
			}

			c := freetype.NewContext()
			c.SetDPI(w.dpi)
			c.SetFont(w.font)
			c.SetFontSize(w.fontSize)
			c.SetSrc(w.watermarkColor)

			textImg := image.NewRGBA(image.Rect(0, 0, len(w.watermarkString)*int(c.PointToFixed(12)>>6), int(c.PointToFixed(12*1.5)>>6)))
			c.SetClip(textImg.Bounds())
			c.SetDst(textImg)

			pt := freetype.Pt(0, int(c.PointToFixed(12)>>6))
			_, _ = c.DrawString(w.watermarkString, pt)

			rotated := imaging.Rotate(textImg, w.skew, image.Transparent)
			draw.Draw(newImg, rotated.Bounds().Add(image.Pt(x+offsetX, y)), rotated, image.Pt(0, 0), draw.Over)
		}
	}
}

// AddWatermark 为文件添加水印
func (w *Watermarker) AddWatermark(file io.Reader, contentType string) ([]byte, error) {
	var fileType string
	switch contentType {
	case "image/jpeg":
		fileType = "jpeg"
	case "image/jpg":
		fileType = "jpg"
	case "image/png":
		fileType = "png"
	case "image/gif":
		fileType = "gif"
	default:
		return nil, fmt.Errorf("不支持的文件类型: %s", contentType)
	}

	switch fileType {
	case "gif":
		return w.GifAddWaterMark(file)
	default:
		return w.ImageAddWaterMark(file, fileType)
	}
}


  • 5
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值