imgutils.go 6.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278
  1. package imgutils
  2. import (
  3. "bytes"
  4. "encoding/base64"
  5. "github.com/golang/freetype"
  6. "github.com/golang/freetype/truetype"
  7. "github.com/nfnt/resize"
  8. "golang.org/x/image/font"
  9. "image"
  10. "image/color"
  11. "image/draw"
  12. _ "image/gif"
  13. _ "image/jpeg"
  14. _ "image/png"
  15. "io"
  16. "net/http"
  17. )
  18. // GetFromBase64 base64->image.image
  19. func GetFromBase64(base64Img string) (image.Image, error) {
  20. empty := image.NewRGBA(image.Rectangle{
  21. Min: image.Point{},
  22. Max: image.Point{},
  23. })
  24. if len(base64Img) == 0 {
  25. return empty, nil
  26. }
  27. imgBytes, err := base64.StdEncoding.DecodeString(base64Img)
  28. if err != nil {
  29. return empty, err
  30. }
  31. img, _, err := image.Decode(bytes.NewBuffer(imgBytes))
  32. if err != nil {
  33. return empty, err
  34. }
  35. return img, nil
  36. }
  37. // GetFromBytes bytes->image.image
  38. func GetFromBytes(imgBytes []byte) (image.Image, error) {
  39. empty := image.NewRGBA(image.Rectangle{
  40. Min: image.Point{},
  41. Max: image.Point{},
  42. })
  43. if len(imgBytes) == 0 {
  44. return empty, nil
  45. }
  46. img, _, err := image.Decode(bytes.NewBuffer(imgBytes))
  47. if err != nil {
  48. return empty, err
  49. }
  50. return img, nil
  51. }
  52. // ResizeImg 缩放原始图片 只给width,height,按比例缩放
  53. func Resize(src image.Image, width, height uint) image.Image {
  54. return resize.Resize(width, height, src, resize.Lanczos3)
  55. }
  56. func TransBackground(src image.Image) image.Image {
  57. newRgba := image.NewRGBA(src.Bounds())
  58. for i := 0; i < src.Bounds().Dx(); i++ {
  59. for j := 0; j < src.Bounds().Dy(); j++ {
  60. colorRgb := src.At(i, j)
  61. r, g, b, a := colorRgb.RGBA()
  62. nR := uint16(r)
  63. nG := uint16(g)
  64. nB := uint16(b)
  65. nA := uint16(a)
  66. if nA == 0 {
  67. nR = 65535
  68. nG = 65535
  69. nB = 65535
  70. nA = 65535
  71. }
  72. newRgba.Set(i, j, color.RGBA64{R: nR, G: nG, B: nB, A: nA})
  73. }
  74. }
  75. return newRgba
  76. }
  77. // 圆形遮罩结构 实现 image.image
  78. type circle struct {
  79. // 圆心位置
  80. p image.Point
  81. // 半径
  82. r int
  83. }
  84. func (c *circle) ColorModel() color.Model {
  85. return color.AlphaModel
  86. }
  87. func (c *circle) Bounds() image.Rectangle {
  88. return image.Rect(c.p.X-c.r, c.p.Y-c.r, c.p.X+c.r, c.p.Y+c.r)
  89. }
  90. func (c *circle) At(x, y int) color.Color {
  91. xx, yy, rr := float64(x-c.p.X)+0.5, float64(y-c.p.Y)+0.5, float64(c.r)
  92. if xx*xx+yy*yy < rr*rr {
  93. return color.Alpha{A: 255} // 半径以内的图案设成完全不透明
  94. }
  95. return color.Alpha{}
  96. }
  97. // CircleMask 从图片中间取圆形遮罩
  98. func CircleMask(src image.Image) image.Image {
  99. c := circle{
  100. p: src.Bounds().Max.Div(2),
  101. r: src.Bounds().Dx() / 2,
  102. }
  103. circleImg := image.NewRGBA(image.Rect(0, 0, src.Bounds().Dx(), src.Bounds().Dy()))
  104. draw.DrawMask(circleImg, circleImg.Bounds(), src, image.Point{}, &c, image.Point{}, draw.Over)
  105. return circleImg
  106. }
  107. // MiddleCoverCoordinate 中间覆盖图片到背景图片坐标计算
  108. func MiddleCoverCoordinate(background image.Image, coverImg image.Image) image.Rectangle {
  109. minPoint := background.Bounds().Max.Div(2).Sub(coverImg.Bounds().Max.Div(2))
  110. maxPoint := minPoint.Add(coverImg.Bounds().Max)
  111. return image.Rectangle{
  112. Min: minPoint,
  113. Max: maxPoint,
  114. }
  115. }
  116. // RGBA RGBA
  117. func RGBA(img image.Image) *image.RGBA {
  118. baseSrcBounds := img.Bounds().Max
  119. newWidth := baseSrcBounds.X
  120. newHeight := baseSrcBounds.Y
  121. // 底板
  122. des := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight))
  123. //首先将一个图片信息存入jpg
  124. draw.Draw(des, des.Bounds(), img, img.Bounds().Min, draw.Over)
  125. return des
  126. }
  127. // DrawTextInfo 图片绘字信息
  128. type DrawTextInfo struct {
  129. Text string
  130. X int
  131. Y int
  132. }
  133. // TextBrush 字体相关
  134. type TextBrush struct {
  135. FontType *truetype.Font
  136. FontSize float64
  137. FontColor *image.Uniform
  138. TextWidth int
  139. DrawInfo *DrawTextInfo
  140. }
  141. func NewTextBrush(font *truetype.Font, FontSize float64, FontColor *image.Uniform, textWidth int, drawInfo *DrawTextInfo) (*TextBrush, error) {
  142. if textWidth <= 0 {
  143. textWidth = 20
  144. }
  145. return &TextBrush{FontType: font, FontSize: FontSize, FontColor: FontColor, TextWidth: textWidth, DrawInfo: drawInfo}, nil
  146. }
  147. func (tb *TextBrush) DrawFontOnRGBA(rgba *image.RGBA) error {
  148. c := freetype.NewContext()
  149. c.SetDPI(72)
  150. c.SetFont(tb.FontType)
  151. c.SetHinting(font.HintingFull)
  152. c.SetFontSize(tb.FontSize)
  153. c.SetClip(rgba.Bounds())
  154. c.SetDst(rgba)
  155. c.SetSrc(tb.FontColor)
  156. _, err := c.DrawString(tb.DrawInfo.Text, freetype.Pt(tb.DrawInfo.X, tb.DrawInfo.Y))
  157. if err != nil {
  158. return err
  159. }
  160. return nil
  161. }
  162. func DrawStringAndSave(img image.Image, infos []*TextBrush) (image.Image, error) {
  163. // 创建画板
  164. desImg := RGBA(img)
  165. for _, brush := range infos {
  166. err := brush.DrawFontOnRGBA(desImg)
  167. if err != nil {
  168. return nil, err
  169. }
  170. }
  171. return desImg, nil
  172. }
  173. func CreateWhiteBackground(w int, h int) *image.RGBA {
  174. newRgba := image.NewRGBA(image.Rectangle{
  175. Min: image.Point{},
  176. Max: image.Point{X: w, Y: h},
  177. })
  178. for i := 0; i < newRgba.Bounds().Dx(); i++ {
  179. for j := 0; j < newRgba.Bounds().Dy(); j++ {
  180. colorRgb := newRgba.At(i, j)
  181. r, g, b, a := colorRgb.RGBA()
  182. nR := uint16(r)
  183. nG := uint16(g)
  184. nB := uint16(b)
  185. nA := uint16(a)
  186. if nA == 0 {
  187. nR = 65535
  188. nG = 65535
  189. nB = 65535
  190. nA = 65535
  191. }
  192. newRgba.Set(i, j, color.RGBA64{R: nR, G: nG, B: nB, A: nA})
  193. }
  194. }
  195. return newRgba
  196. }
  197. func MergeImagesHighLow(highImg image.Image, lowImg image.Image) image.Image {
  198. var x, y int
  199. if highImg.Bounds().Dx() >= lowImg.Bounds().Dx() {
  200. x = highImg.Bounds().Dx()
  201. } else {
  202. x = lowImg.Bounds().Dx()
  203. }
  204. y = highImg.Bounds().Dy() + lowImg.Bounds().Dy()
  205. destDraw := CreateWhiteBackground(x, y)
  206. // 先画风景图
  207. draw.Draw(destDraw, destDraw.Bounds(), highImg, highImg.Bounds().Min, draw.Over)
  208. // 画微信图
  209. draw.Draw(destDraw, image.Rectangle{
  210. Min: image.Point{Y: highImg.Bounds().Max.Y},
  211. Max: destDraw.Bounds().Max,
  212. }, lowImg, lowImg.Bounds().Min, draw.Over)
  213. return destDraw
  214. }
  215. func GetBase64FromUrl(url string) (string, error) {
  216. res, err := http.Get(url)
  217. if err != nil {
  218. return "", err
  219. }
  220. defer func(Body io.ReadCloser) {
  221. err := Body.Close()
  222. if err != nil {
  223. }
  224. }(res.Body)
  225. data, err := io.ReadAll(res.Body)
  226. if err != nil {
  227. return "", err
  228. }
  229. return base64.StdEncoding.EncodeToString(data), nil
  230. }