yjp 1 жил өмнө
parent
commit
b540333ca7
3 өөрчлөгдсөн 287 нэмэгдсэн , 0 устгасан
  1. 3 0
      go.mod
  2. 6 0
      go.sum
  3. 278 0
      imgutils/imgutils.go

+ 3 - 0
go.mod

@@ -8,9 +8,12 @@ require (
 	github.com/fatih/structs v1.1.0
 	github.com/go-ego/gpy v0.42.1
 	github.com/go-resty/resty/v2 v2.11.0
+	github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0
 	github.com/mitchellh/mapstructure v1.5.0
+	github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646
 	github.com/redis/go-redis/v9 v9.4.0
 	github.com/satori/go.uuid v1.2.0
+	golang.org/x/image v0.15.0
 	gopkg.in/yaml.v3 v3.0.1
 )
 

+ 6 - 0
go.sum

@@ -25,6 +25,8 @@ github.com/go-ego/gse v0.69.15 h1:QprXRGKim8fI2B38ItT4YwuY9/37gwUAw37TnA3exa0=
 github.com/go-ego/gse v0.69.15/go.mod h1:M9Xv8cEW7Of27BbE4p0iI3arqQHCYcm5N16/2b3pPPk=
 github.com/go-resty/resty/v2 v2.11.0 h1:i7jMfNOJYMp69lq7qozJP+bjgzfAzeOhuGlyDrqxT/8=
 github.com/go-resty/resty/v2 v2.11.0/go.mod h1:iiP/OpA0CkcL3IGt1O0+/SIItFUbkkyw5BGXiVdTu+A=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0 h1:DACJavvAHhabrF08vX0COfcOBJRhZ8lUbR+ZWIs0Y5g=
+github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k=
 github.com/google/uuid v1.1.1 h1:Gkbcsh/GbpXz7lPftLA3P6TYMwjCLYm83jiFQZF/3gY=
 github.com/google/uuid v1.1.1/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo=
 github.com/gorilla/websocket v1.5.0 h1:PPwGk2jz7EePpoHN/+ClbZu8SPxiqlu12wZP/3sWmnc=
@@ -39,6 +41,8 @@ github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyua
 github.com/mitchellh/mapstructure v1.5.0/go.mod h1:bFUtVrKA4DC2yAKiSyO/QUcy7e+RRV2QTWOzhPopBRo=
 github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY=
 github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw=
+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=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
 github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
 github.com/redis/go-redis/v9 v9.4.0 h1:Yzoz33UZw9I/mFhx4MNrB6Fk+XHO1VukNcCa1+lwyKk=
@@ -65,6 +69,8 @@ golang.org/x/crypto v0.3.0/go.mod h1:hebNnKkNXi2UzZN1eVRvBB7co0a+JxK6XbPiWVs/3J4
 golang.org/x/crypto v0.14.0/go.mod h1:MVFd36DqK4CsrnJYDkBA3VC4m2GkXAM0PvzMCn4JQf4=
 golang.org/x/crypto v0.18.0 h1:PGVlW0xEltQnzFZ55hkuX5+KLyrMYhHld1YHO4AKcdc=
 golang.org/x/crypto v0.18.0/go.mod h1:R0j02AL6hcrfOiy9T4ZYp/rcWeMxM3L6QYxlOuEG1mg=
+golang.org/x/image v0.15.0 h1:kOELfmgrmJlw4Cdb7g/QGuB3CvDrXbqEIww/pNtNBm8=
+golang.org/x/image v0.15.0/go.mod h1:HUYqC05R2ZcZ3ejNQsIHQDQiwWM4JBqmm6MKANTp4LE=
 golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
 golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
 golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=

+ 278 - 0
imgutils/imgutils.go

@@ -0,0 +1,278 @@
+package imgutils
+
+import (
+	"bytes"
+	"encoding/base64"
+	"github.com/golang/freetype"
+	"github.com/golang/freetype/truetype"
+	"github.com/nfnt/resize"
+	"golang.org/x/image/font"
+	"image"
+	"image/color"
+	"image/draw"
+	_ "image/gif"
+	_ "image/jpeg"
+	_ "image/png"
+	"io"
+	"net/http"
+)
+
+// GetImageFromBase64 base64->image.image
+func GetImageFromBase64(base64Img string) (image.Image, error) {
+	empty := image.NewRGBA(image.Rectangle{
+		Min: image.Point{},
+		Max: image.Point{},
+	})
+	if len(base64Img) == 0 {
+		return empty, nil
+	}
+
+	imgBytes, err := base64.StdEncoding.DecodeString(base64Img)
+	if err != nil {
+		return empty, err
+	}
+
+	img, _, err := image.Decode(bytes.NewBuffer(imgBytes))
+	if err != nil {
+		return empty, err
+	}
+
+	return img, nil
+}
+
+// GetImageFromBytes bytes->image.image
+func GetImageFromBytes(imgBytes []byte) (image.Image, error) {
+	empty := image.NewRGBA(image.Rectangle{
+		Min: image.Point{},
+		Max: image.Point{},
+	})
+	if len(imgBytes) == 0 {
+		return empty, nil
+	}
+
+	img, _, err := image.Decode(bytes.NewBuffer(imgBytes))
+	if err != nil {
+		return empty, err
+	}
+
+	return img, nil
+}
+
+// ResizeImg 缩放原始图片 只给width,height,按比例缩放
+func ResizeImg(src image.Image, width, height uint) image.Image {
+	return resize.Resize(width, height, src, resize.Lanczos3)
+}
+
+func TransBackground(src image.Image) image.Image {
+	newRgba := image.NewRGBA(src.Bounds())
+	for i := 0; i < src.Bounds().Dx(); i++ {
+		for j := 0; j < src.Bounds().Dy(); j++ {
+			colorRgb := src.At(i, j)
+			r, g, b, a := colorRgb.RGBA()
+			nR := uint16(r)
+			nG := uint16(g)
+			nB := uint16(b)
+			nA := uint16(a)
+			if nA == 0 {
+				nR = 65535
+				nG = 65535
+				nB = 65535
+				nA = 65535
+			}
+			newRgba.Set(i, j, color.RGBA64{R: nR, G: nG, B: nB, A: nA})
+		}
+	}
+	return newRgba
+}
+
+// 圆形遮罩结构 实现 image.image
+type circle struct {
+	// 圆心位置
+	p image.Point
+
+	// 半径
+	r int
+}
+
+func (c *circle) ColorModel() color.Model {
+	return color.AlphaModel
+}
+
+func (c *circle) Bounds() image.Rectangle {
+	return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
+}
+
+func (c *circle) At(x, y int) color.Color {
+	xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
+	if xx*xx+yy*yy < rr*rr {
+		return color.Alpha{A: 255} // 半径以内的图案设成完全不透明
+	}
+	return color.Alpha{}
+}
+
+// CircleImage 从图片中间取圆形遮罩
+func CircleImage(src image.Image) image.Image {
+	c := circle{
+		p: src.Bounds().Max.Div(2),
+		r: src.Bounds().Dx() / 2,
+	}
+
+	circleImg := image.NewRGBA(image.Rect(0, 0, src.Bounds().Dx(), src.Bounds().Dy()))
+	draw.DrawMask(circleImg, circleImg.Bounds(), src, image.Point{}, &c, image.Point{}, draw.Over)
+
+	return circleImg
+}
+
+// MiddleCoverCoordinate 中间覆盖图片到背景图片坐标计算
+func MiddleCoverCoordinate(background, coverImg image.Image) image.Rectangle {
+	minPoint := background.Bounds().Max.Div(2).Sub(coverImg.Bounds().Max.Div(2))
+	maxPoint := minPoint.Add(coverImg.Bounds().Max)
+
+	return image.Rectangle{
+		Min: minPoint,
+		Max: maxPoint,
+	}
+}
+
+// Image2RGBA Image2RGBA
+func Image2RGBA(img image.Image) *image.RGBA {
+	baseSrcBounds := img.Bounds().Max
+
+	newWidth := baseSrcBounds.X
+	newHeight := baseSrcBounds.Y
+
+	// 底板
+	des := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight))
+
+	//首先将一个图片信息存入jpg
+	draw.Draw(des, des.Bounds(), img, img.Bounds().Min, draw.Over)
+
+	return des
+}
+
+// DrawTextInfo 图片绘字信息
+type DrawTextInfo struct {
+	Text string
+	X    int
+	Y    int
+}
+
+// TextBrush 字体相关
+type TextBrush struct {
+	FontType  *truetype.Font
+	FontSize  float64
+	FontColor *image.Uniform
+	TextWidth int
+	DrawInfo  *DrawTextInfo
+}
+
+func NewTextBrush(font *truetype.Font, FontSize float64, FontColor *image.Uniform, textWidth int, drawInfo *DrawTextInfo) (*TextBrush, error) {
+	if textWidth <= 0 {
+		textWidth = 20
+	}
+
+	return &TextBrush{FontType: font, FontSize: FontSize, FontColor: FontColor, TextWidth: textWidth, DrawInfo: drawInfo}, nil
+}
+
+func (tb *TextBrush) DrawFontOnRGBA(rgba *image.RGBA) error {
+	c := freetype.NewContext()
+	c.SetDPI(72)
+	c.SetFont(tb.FontType)
+	c.SetHinting(font.HintingFull)
+	c.SetFontSize(tb.FontSize)
+	c.SetClip(rgba.Bounds())
+	c.SetDst(rgba)
+	c.SetSrc(tb.FontColor)
+
+	_, err := c.DrawString(tb.DrawInfo.Text, freetype.Pt(tb.DrawInfo.X, tb.DrawInfo.Y))
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
+
+func DrawStringOnImageAndSave(img image.Image, infos []*TextBrush) (image.Image, error) {
+	// 创建画板
+	desImg := Image2RGBA(img)
+	for _, brush := range infos {
+		err := brush.DrawFontOnRGBA(desImg)
+		if err != nil {
+			return nil, err
+		}
+	}
+
+	return desImg, nil
+}
+
+func CreateWhiteBackgroundImg(w, h int) *image.RGBA {
+	newRgba := image.NewRGBA(image.Rectangle{
+		Min: image.Point{},
+		Max: image.Point{X: w, Y: h},
+	})
+
+	for i := 0; i < newRgba.Bounds().Dx(); i++ {
+		for j := 0; j < newRgba.Bounds().Dy(); j++ {
+			colorRgb := newRgba.At(i, j)
+			r, g, b, a := colorRgb.RGBA()
+			nR := uint16(r)
+			nG := uint16(g)
+			nB := uint16(b)
+			nA := uint16(a)
+			if nA == 0 {
+				nR = 65535
+				nG = 65535
+				nB = 65535
+				nA = 65535
+			}
+			newRgba.Set(i, j, color.RGBA64{R: nR, G: nG, B: nB, A: nA})
+		}
+	}
+
+	return newRgba
+}
+
+func MergeImagesHighLow(highImg, lowImg image.Image) image.Image {
+	var x, y int
+
+	if highImg.Bounds().Dx() >= lowImg.Bounds().Dx() {
+		x = highImg.Bounds().Dx()
+	} else {
+		x = lowImg.Bounds().Dx()
+	}
+
+	y = highImg.Bounds().Dy() + lowImg.Bounds().Dy()
+	destDraw := CreateWhiteBackgroundImg(x, y)
+
+	// 先画风景图
+	draw.Draw(destDraw, destDraw.Bounds(), highImg, highImg.Bounds().Min, draw.Over)
+
+	// 画微信图
+	draw.Draw(destDraw, image.Rectangle{
+		Min: image.Point{Y: highImg.Bounds().Max.Y},
+		Max: destDraw.Bounds().Max,
+	}, lowImg, lowImg.Bounds().Min, draw.Over)
+
+	return destDraw
+}
+
+func GetUrlBase64(url string) (string, error) {
+	res, err := http.Get(url)
+	if err != nil {
+		return "", err
+	}
+
+	defer func(Body io.ReadCloser) {
+		err := Body.Close()
+		if err != nil {
+
+		}
+	}(res.Body)
+
+	data, err := io.ReadAll(res.Body)
+	if err != nil {
+		return "", err
+	}
+
+	return base64.StdEncoding.EncodeToString(data), nil
+}