golang 合成的圖片

熊先生不开玩笑發表於2024-09-09
package picture_service

import (
	"errors"
	"github.com/nfnt/resize"
	"image"
	"image/draw"
	"image/jpeg"
	"image/png"
	"log"
	"net/http"
	"os"
)

type PictureService struct{}

func NewPictureService() *PictureService {
	return &PictureService{}
}

func (service *PictureService) PictureMerge(sign string, pic string, newImagePath string, left int, up int, picWidth int, picHeight int, signWidth int, signHeight int) (err error) {
	signFile, err := os.Open(sign)
	if err != nil {
		return
	}
	defer signFile.Close()
	sImage, _, err := image.Decode(signFile)
	if err != nil {
		return
	}
	signImage := resize.Resize(uint(signWidth), uint(signHeight), sImage, resize.Lanczos3)
	picFile, err := os.Open(pic)
	if err != nil {
		return
	}
	defer picFile.Close()
	picBytes, err := os.ReadFile(pic)
	if err != nil {
		return
	}
	contentType := http.DetectContentType(picBytes)
	var picImage image.Image
	if contentType == "image/jpeg" || contentType == "image/jpg" {
		picImage, err = jpeg.Decode(picFile)
		if err != nil {
			return
		}
	} else if contentType == "image/png" {
		picImage, err = png.Decode(picFile)
		if err != nil {
			return
		}
	} else {
		return errors.New("未知圖片型別")
	}
	// 重置底圖大小
	resizePicImage := resize.Resize(uint(picWidth), uint(picHeight), picImage, resize.Lanczos3)
	// 新建畫布,邊界與底圖一致
	templateImage := image.NewRGBA(resizePicImage.Bounds())
	// 將底圖覆蓋畫布上,座標起點為0,0
	draw.Draw(templateImage, resizePicImage.Bounds(), resizePicImage, resizePicImage.Bounds().Min, draw.Over)
	if err != nil {
		log.Panicln(err.Error())
		return
	}
	// 簽章圖片的高、寬的 1/2 就是,簽章圖片中心到右下角距離。文字資訊的中心:向左距離(left),向上距離(up)
	// left -寬 = l,up - 高 = h
	// 向左移動 l,向上移動 h,就可以讓印章圖的中心點和文字的中心點總是重合,這樣印章就是總是在文字上面
	imaCenterLeft := signImage.Bounds().Dx() / 2
	imaCenterUp := signImage.Bounds().Dy() / 2
	l := left - imaCenterLeft
	h := up - imaCenterUp
	// 向左移動X減少,向上移動Y減少
	offset := image.Pt(templateImage.Bounds().Dx()-signImage.Bounds().Dx()-l, templateImage.Bounds().Dy()-signImage.Bounds().Dy()-h)
	draw.Draw(
		templateImage,
		signImage.Bounds().Add(offset),
		signImage,
		// 0,0 為起點
		image.Point{},
		draw.Over)
	err = service.savePng(templateImage, newImagePath)
	return
}

func (service *PictureService) savePng(pic *image.RGBA, path string) (err error) {
	dstFile, err := os.Create(path)
	if err != nil {
		return
	}
	defer dstFile.Close()
	err = png.Encode(dstFile, pic)
	return
}

相關文章