drawtext.go 6.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330
  1. package utils
  2. import (
  3. "bytes"
  4. "fmt"
  5. "image"
  6. "image/color"
  7. "image/draw"
  8. "image/gif"
  9. "image/jpeg"
  10. "image/png"
  11. "io/ioutil"
  12. "net/http"
  13. "os"
  14. "github.com/golang/freetype"
  15. "github.com/golang/freetype/truetype"
  16. "golang.org/x/image/font"
  17. )
  18. type DrawTextInfo struct {
  19. Text string
  20. X int
  21. Y int
  22. FontSize int
  23. }
  24. type DrawRectInfo struct {
  25. X1 int
  26. Y1 int
  27. X2 int
  28. Y2 int
  29. }
  30. type TextBrush struct {
  31. FontType *truetype.Font
  32. FontSize float64
  33. FontColor *image.Uniform
  34. TextWidth int
  35. }
  36. func NewTextBrush(FontFilePath string, FontSize float64, FontColor *image.Uniform, textWidth int) (*TextBrush, error) {
  37. fontFile, err := ioutil.ReadFile(FontFilePath)
  38. if err != nil {
  39. return nil, err
  40. }
  41. fontType, err := truetype.Parse(fontFile)
  42. if err != nil {
  43. return nil, err
  44. }
  45. if textWidth <= 0 {
  46. textWidth = 20
  47. }
  48. return &TextBrush{FontType: fontType, FontSize: FontSize, FontColor: FontColor, TextWidth: textWidth}, nil
  49. }
  50. func (fb *TextBrush) DrawFontOnRGBA(rgba *image.RGBA, pt image.Point, content string) {
  51. c := freetype.NewContext()
  52. c.SetDPI(72)
  53. c.SetFont(fb.FontType)
  54. c.SetHinting(font.HintingFull)
  55. c.SetFontSize(fb.FontSize)
  56. c.SetClip(rgba.Bounds())
  57. c.SetDst(rgba)
  58. c.SetSrc(fb.FontColor)
  59. c.DrawString(content, freetype.Pt(pt.X, pt.Y))
  60. }
  61. func Image2RGBA(img image.Image) *image.RGBA {
  62. baseSrcBounds := img.Bounds().Max
  63. newWidth := baseSrcBounds.X
  64. newHeight := baseSrcBounds.Y
  65. des := image.NewRGBA(image.Rect(0, 0, newWidth, newHeight)) // 底板
  66. draw.Draw(des, des.Bounds(), img, img.Bounds().Min, draw.Over)
  67. return des
  68. }
  69. type FontRGBA struct {
  70. R uint8
  71. G uint8
  72. B uint8
  73. A uint8
  74. }
  75. func DrawStringOnImageAndSave(imagePath string, imageData []byte, infos []*DrawTextInfo, colorRGBA FontRGBA) (err error) {
  76. var backgroud image.Image
  77. filetype := http.DetectContentType(imageData)
  78. switch filetype {
  79. case "image/jpeg", "image/jpg":
  80. backgroud, err = jpeg.Decode(bytes.NewReader(imageData))
  81. if err != nil {
  82. fmt.Println("jpeg error")
  83. return err
  84. }
  85. case "image/gif":
  86. backgroud, err = gif.Decode(bytes.NewReader(imageData))
  87. if err != nil {
  88. return err
  89. }
  90. case "image/png":
  91. backgroud, err = png.Decode(bytes.NewReader(imageData))
  92. if err != nil {
  93. return err
  94. }
  95. default:
  96. return err
  97. }
  98. des := Image2RGBA(backgroud)
  99. ttfPath := "static/ttf/songti.ttf"
  100. textBrush, _ := NewTextBrush(ttfPath, 25, image.Black, 50)
  101. c := freetype.NewContext()
  102. c.SetDPI(72)
  103. c.SetFont(textBrush.FontType)
  104. c.SetHinting(font.HintingFull)
  105. c.SetFontSize(textBrush.FontSize)
  106. c.SetClip(des.Bounds())
  107. c.SetDst(des)
  108. textBrush.FontColor = image.NewUniform(color.RGBA{
  109. R: colorRGBA.R,
  110. G: colorRGBA.G,
  111. B: colorRGBA.B,
  112. A: colorRGBA.A,
  113. })
  114. c.SetSrc(textBrush.FontColor)
  115. for _, info := range infos {
  116. c.DrawString(info.Text, freetype.Pt(info.X, info.Y))
  117. }
  118. fSave, err := os.Create(imagePath)
  119. if err != nil {
  120. return err
  121. }
  122. defer fSave.Close()
  123. err = jpeg.Encode(fSave, des, nil)
  124. if err != nil {
  125. return err
  126. }
  127. return nil
  128. }
  129. func DrawRectOnImageAndSave(imagePath string, imageData []byte, infos []*DrawRectInfo) (err error) {
  130. var backgroud image.Image
  131. filetype := http.DetectContentType(imageData)
  132. switch filetype {
  133. case "image/jpeg", "image/jpg":
  134. backgroud, err = jpeg.Decode(bytes.NewReader(imageData))
  135. if err != nil {
  136. fmt.Println("jpeg error")
  137. return err
  138. }
  139. case "image/gif":
  140. backgroud, err = gif.Decode(bytes.NewReader(imageData))
  141. if err != nil {
  142. return err
  143. }
  144. case "image/png":
  145. backgroud, err = png.Decode(bytes.NewReader(imageData))
  146. if err != nil {
  147. return err
  148. }
  149. default:
  150. return err
  151. }
  152. des := Image2RGBA(backgroud)
  153. textBrush, _ := NewTextBrush("arial.ttf", 15, image.Black, 15)
  154. for _, info := range infos {
  155. var c *freetype.Context
  156. c = freetype.NewContext()
  157. c.SetDPI(72)
  158. c.SetFont(textBrush.FontType)
  159. c.SetHinting(font.HintingFull)
  160. c.SetFontSize(textBrush.FontSize)
  161. c.SetClip(des.Bounds())
  162. c.SetDst(des)
  163. cGreen := image.NewUniform(color.RGBA{
  164. R: 0,
  165. G: 0xFF,
  166. B: 0,
  167. A: 255,
  168. })
  169. c.SetSrc(cGreen)
  170. for i := info.X1; i < info.X2; i++ {
  171. c.DrawString("·", freetype.Pt(i, info.Y1))
  172. c.DrawString("·", freetype.Pt(i, info.Y2))
  173. }
  174. for j := info.Y1; j < info.Y2; j++ {
  175. c.DrawString("·", freetype.Pt(info.X1, j))
  176. c.DrawString("·", freetype.Pt(info.X2, j))
  177. }
  178. }
  179. fSave, err := os.Create(imagePath)
  180. if err != nil {
  181. return err
  182. }
  183. defer fSave.Close()
  184. err = jpeg.Encode(fSave, des, nil)
  185. if err != nil {
  186. return err
  187. }
  188. return nil
  189. }
  190. func DrawStringOnImage(imageData []byte, infos []*DrawTextInfo, colorRGBA FontRGBA, fontSize float64, fontWidth int) (picBytes bytes.Buffer, err error) {
  191. var backgroud image.Image
  192. filetype := http.DetectContentType(imageData)
  193. switch filetype {
  194. case "image/jpeg", "image/jpg":
  195. backgroud, err = jpeg.Decode(bytes.NewReader(imageData))
  196. if err != nil {
  197. fmt.Println("jpeg error")
  198. return
  199. }
  200. case "image/gif":
  201. backgroud, err = gif.Decode(bytes.NewReader(imageData))
  202. if err != nil {
  203. return
  204. }
  205. case "image/png":
  206. backgroud, err = png.Decode(bytes.NewReader(imageData))
  207. if err != nil {
  208. return
  209. }
  210. default:
  211. return
  212. }
  213. des := Image2RGBA(backgroud)
  214. ttfPath := "static/ttf/songti.ttf"
  215. textBrush, _ := NewTextBrush(ttfPath, fontSize, image.Black, fontWidth)
  216. c := freetype.NewContext()
  217. c.SetDPI(72)
  218. c.SetFont(textBrush.FontType)
  219. c.SetHinting(font.HintingFull)
  220. c.SetFontSize(textBrush.FontSize)
  221. c.SetClip(des.Bounds())
  222. c.SetDst(des)
  223. textBrush.FontColor = image.NewUniform(color.RGBA{
  224. R: colorRGBA.R,
  225. G: colorRGBA.G,
  226. B: colorRGBA.B,
  227. A: colorRGBA.A,
  228. })
  229. c.SetSrc(textBrush.FontColor)
  230. for _, info := range infos {
  231. c.DrawString(info.Text, freetype.Pt(info.X, info.Y))
  232. }
  233. err = jpeg.Encode(&picBytes, des, nil)
  234. return
  235. }
  236. func DrawStringRowsOnImage(imageData []byte, infos []*DrawTextInfo, colorRGBA FontRGBA, fontSize float64, fontWidth int) (picBytes bytes.Buffer, err error) {
  237. var backgroud image.Image
  238. filetype := http.DetectContentType(imageData)
  239. switch filetype {
  240. case "image/jpeg", "image/jpg":
  241. backgroud, err = jpeg.Decode(bytes.NewReader(imageData))
  242. if err != nil {
  243. fmt.Println("jpeg error")
  244. return
  245. }
  246. case "image/gif":
  247. backgroud, err = gif.Decode(bytes.NewReader(imageData))
  248. if err != nil {
  249. return
  250. }
  251. case "image/png":
  252. backgroud, err = png.Decode(bytes.NewReader(imageData))
  253. if err != nil {
  254. return
  255. }
  256. default:
  257. return
  258. }
  259. des := Image2RGBA(backgroud)
  260. ttfPath := "static/ttf/songti.ttf"
  261. textBrush, _ := NewTextBrush(ttfPath, fontSize, image.Black, fontWidth)
  262. for _, info := range infos {
  263. c := freetype.NewContext()
  264. c.SetDPI(72)
  265. c.SetFont(textBrush.FontType)
  266. c.SetHinting(font.HintingFull)
  267. c.SetFontSize(float64(info.FontSize))
  268. c.SetClip(des.Bounds())
  269. c.SetDst(des)
  270. textBrush.FontColor = image.NewUniform(color.RGBA{
  271. R: colorRGBA.R,
  272. G: colorRGBA.G,
  273. B: colorRGBA.B,
  274. A: colorRGBA.A,
  275. })
  276. c.SetSrc(textBrush.FontColor)
  277. c.DrawString(info.Text, freetype.Pt(info.X, info.Y))
  278. }
  279. err = jpeg.Encode(&picBytes, des, nil)
  280. return
  281. }