image.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162
  1. package dao
  2. import (
  3. "bufio"
  4. "bytes"
  5. "context"
  6. "fmt"
  7. "image"
  8. "image/color"
  9. "image/draw"
  10. "image/jpeg"
  11. "image/png"
  12. "io/ioutil"
  13. "net/http"
  14. "os"
  15. "regexp"
  16. "go-common/app/admin/openplatform/sug/model"
  17. "go-common/library/log"
  18. "code.google.com/p/graphics-go/graphics"
  19. "errors"
  20. "github.com/golang/freetype"
  21. "golang.org/x/image/font"
  22. "golang.org/x/image/math/fixed"
  23. )
  24. const (
  25. _Width = 1125
  26. _Height = 234
  27. _HeaderLength = 168
  28. )
  29. var (
  30. _RGBA = []int{244, 245, 247, 255}
  31. _HeadArea = []int{36, 33, 204, 201}
  32. _LabelArea = []int{234, 156, 348, 201}
  33. _BriefText = []int{234, 72}
  34. _NameText = []int{234, 129}
  35. _BriefSize = 44
  36. _NameSize = 36
  37. _BriefRGBA = []int{33, 33, 33, 255}
  38. _NameRGBA = []int{153, 153, 153, 255}
  39. _BriefLimit = 1000
  40. _NameLimit = 1000
  41. )
  42. // CreateItemPNG make a pic
  43. func (d *Dao) CreateItemPNG(item model.Item) (location string, err error) {
  44. var r *image.NRGBA64
  45. if r, err = d.makeBoard(item.Img); err != nil {
  46. log.Error("Create picture board error(%v)", err)
  47. return
  48. }
  49. if item.Brief == "" {
  50. item.Brief = item.Name
  51. }
  52. r = d.drawText(r, item.Brief, item.Name)
  53. buf := new(bytes.Buffer)
  54. png.Encode(buf, r)
  55. bufReader := bufio.NewReader(buf)
  56. if location, err = d.Upload(context.TODO(), "image/png", fmt.Sprintf("season_sug_%s/%d.png", d.c.Env, item.ItemsID), bufReader); err != nil {
  57. log.Error("Upload pic png error (%v)", err)
  58. return
  59. }
  60. reg, _ := regexp.CompilePOSIX(`//(.*)+`)
  61. location = reg.FindString(location)
  62. return
  63. }
  64. func (d *Dao) makeBoard(headerURL string) (board *image.NRGBA64, err error) {
  65. var header image.Image
  66. radius, _ := os.Open(d.c.SourcePath + "radius.png")
  67. label, _ := os.Open(d.c.SourcePath + "label.png")
  68. defer radius.Close()
  69. defer label.Close()
  70. resp, err := http.Get("http:" + headerURL)
  71. if err != nil {
  72. log.Error("http get error(%v)(%s)", "http:"+headerURL)
  73. return
  74. }
  75. bs, err := ioutil.ReadAll(resp.Body)
  76. if err != nil {
  77. log.Error("ioutil.ReadAll img error(%v)", err)
  78. return
  79. }
  80. imgType := http.DetectContentType(bs)
  81. buf := bytes.NewBuffer(bs)
  82. resp.Body = ioutil.NopCloser(buf)
  83. if err != nil {
  84. log.Error("http download head img error(%v)", err)
  85. return
  86. }
  87. defer resp.Body.Close()
  88. switch imgType {
  89. case "image/png":
  90. header, err = png.Decode(resp.Body)
  91. if err != nil {
  92. log.Error("png picture decode error(%v)", err)
  93. return
  94. }
  95. case "image/jpeg", "image/jpg":
  96. header, err = jpeg.Decode(resp.Body)
  97. if err != nil {
  98. log.Error("jpg picture decode err(%v)", err)
  99. return
  100. }
  101. default:
  102. err = errors.New("invaild picture type")
  103. log.Error("invaild picture type (%s)", headerURL)
  104. return
  105. }
  106. board = image.NewNRGBA64(image.Rect(0, 0, _Width, _Height))
  107. draw.Draw(board, board.Bounds(), image.White, image.ZP, draw.Src)
  108. radiusPNG, _ := png.Decode(radius)
  109. cover := image.NewRGBA64(image.Rect(0, 0, _HeaderLength, _HeaderLength))
  110. border := image.NewNRGBA64(image.Rect(0, 0, _HeaderLength, _HeaderLength))
  111. headBoard := image.NewRGBA64(image.Rect(0, 0, _HeaderLength, _HeaderLength))
  112. draw.Draw(headBoard, headBoard.Bounds(), image.NewUniform(color.NRGBA{uint8(_RGBA[0]), uint8(_RGBA[1]), uint8(_RGBA[2]), uint8(_RGBA[3])}), image.ZP, draw.Over)
  113. graphics.Thumbnail(border, radiusPNG)
  114. graphics.Thumbnail(cover, header)
  115. labelPNG, _ := png.Decode(label)
  116. draw.Draw(headBoard, headBoard.Bounds(), cover, image.ZP, draw.Over)
  117. draw.Draw(headBoard, headBoard.Bounds(), border, image.ZP, draw.Over)
  118. draw.Draw(board, image.Rect(_HeadArea[0], _HeadArea[1], _HeadArea[2], _HeadArea[3]), headBoard, image.ZP, draw.Over)
  119. draw.Draw(board, image.Rect(_LabelArea[0], _LabelArea[1], _LabelArea[2], _LabelArea[3]), labelPNG, image.ZP, draw.Over)
  120. return
  121. }
  122. func (d *Dao) drawText(r *image.NRGBA64, brief string, name string) *image.NRGBA64 {
  123. ptBrief := fixed.P(_BriefText[0], _BriefText[1])
  124. ptName := fixed.P(_NameText[0], _NameText[1])
  125. freetypeC := d.Context(r)
  126. d.Text(freetypeC, brief, &ptBrief, _BriefSize, image.NewUniform(color.NRGBA{uint8(_BriefRGBA[0]), uint8(_BriefRGBA[1]), uint8(_BriefRGBA[2]), uint8(_BriefRGBA[3])}), fixed.I(_BriefLimit))
  127. d.Text(freetypeC, name, &ptName, _NameSize, image.NewUniform(color.NRGBA{uint8(_NameRGBA[0]), uint8(_NameRGBA[1]), uint8(_NameRGBA[2]), uint8(_RGBA[3])}), fixed.I(_NameLimit))
  128. return r
  129. }
  130. // Context make object for write letters
  131. func (d *Dao) Context(r *image.NRGBA64) (c *freetype.Context) {
  132. c = freetype.NewContext()
  133. c.SetClip(r.Bounds())
  134. c.SetDst(r)
  135. c.SetHinting(font.HintingNone)
  136. return
  137. }
  138. // Text write letters
  139. func (d *Dao) Text(c *freetype.Context, s string, pt *fixed.Point26_6, size int, color image.Image, length fixed.Int26_6) (err error) {
  140. c.SetFontSize(float64(size))
  141. c.SetSrc(color)
  142. ttf, _ := ioutil.ReadFile(d.c.SourcePath + "font.ttf")
  143. font, _ := freetype.ParseFont(ttf)
  144. c.SetFont(font)
  145. for _, r := range s {
  146. c.DrawString(string(r), *pt)
  147. pt.X += font.HMetric(fixed.Int26_6(size*64), font.Index(r)).AdvanceWidth
  148. if pt.X > length {
  149. break
  150. }
  151. }
  152. return
  153. }