file.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295
  1. package services
  2. import (
  3. "bytes"
  4. "errors"
  5. "eta/eta_api/models"
  6. "eta/eta_api/utils"
  7. "fmt"
  8. "github.com/pdfcpu/pdfcpu/pkg/api"
  9. "github.com/pdfcpu/pdfcpu/pkg/font"
  10. "github.com/pdfcpu/pdfcpu/pkg/pdfcpu"
  11. "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model"
  12. "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
  13. "io"
  14. "math"
  15. "mime/multipart"
  16. "os"
  17. "os/exec"
  18. "strings"
  19. "time"
  20. )
  21. // UploadToOssAndFileName 上传到oss并使用这个名称
  22. func UploadToOssAndFileName(fileMulti multipart.File, newFileName string) (resourceUrl string, err error) {
  23. dateDir := time.Now().Format("20060102")
  24. uploadDir := utils.STATIC_DIR + "hongze/" + dateDir
  25. err = os.MkdirAll(uploadDir, utils.DIR_MOD)
  26. if err != nil {
  27. err = errors.New("存储目录创建失败,Err:" + err.Error())
  28. return
  29. }
  30. //本地地址
  31. fpath := uploadDir + "/" + newFileName
  32. err = saveToFile(fileMulti, fpath)
  33. if err != nil {
  34. err = errors.New("文件上传失败,Err:" + err.Error())
  35. return
  36. }
  37. //上传到阿里云 和 minio
  38. //if utils.ObjectStorageClient == "minio" {
  39. // resourceUrl, err = UploadImgToMinIo(newFileName, fpath)
  40. // if err != nil {
  41. // err = errors.New("文件上传失败,Err:" + err.Error())
  42. // return
  43. // }
  44. //} else {
  45. // resourceUrl, err = UploadAliyunV2(newFileName, fpath)
  46. // if err != nil {
  47. // err = errors.New("文件上传失败,Err:" + err.Error())
  48. // return
  49. // }
  50. //}
  51. ossClient := NewOssClient()
  52. if ossClient == nil {
  53. err = fmt.Errorf("初始化OSS服务失败")
  54. return
  55. }
  56. resourceUrl, err = ossClient.UploadFile(newFileName, fpath, "")
  57. if err != nil {
  58. err = fmt.Errorf("文件上传失败, Err: %s", err.Error())
  59. return
  60. }
  61. defer func() {
  62. os.Remove(fpath)
  63. }()
  64. item := new(models.Resource)
  65. item.ResourceUrl = resourceUrl
  66. item.ResourceType = 1
  67. item.CreateTime = time.Now()
  68. _, err = models.AddResource(item)
  69. if err != nil {
  70. err = errors.New("资源上传失败,Err:" + err.Error())
  71. return
  72. }
  73. return
  74. }
  75. // saveToFile 保存到本地文件
  76. func saveToFile(fileMulti multipart.File, tofile string) error {
  77. f, err := os.OpenFile(tofile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666)
  78. if err != nil {
  79. return err
  80. }
  81. defer f.Close()
  82. io.Copy(f, fileMulti)
  83. return nil
  84. }
  85. // GetResourceUrlBySvgImg
  86. // @Description: 通过svg图片生成图片资源地址(传到OSS后的地址)
  87. // @author: Roc
  88. // @datetime 2024-07-16 10:18:09
  89. // @param imgData string
  90. // @return resourceUrl string
  91. // @return err error
  92. // @return errMsg string
  93. func GetResourceUrlBySvgImg(imgData string) (resourceUrl string, err error, errMsg string) {
  94. errMsg = "图表保存失败"
  95. uploadDir := "static/images/"
  96. if !utils.FileIsExist(uploadDir) {
  97. err = os.MkdirAll(uploadDir, utils.DIR_MOD)
  98. if err != nil {
  99. err = errors.New("存储目录创建失败,Err:" + err.Error())
  100. return
  101. }
  102. }
  103. //var saveToOssPath string
  104. randStr := utils.GetRandStringNoSpecialChar(28)
  105. var fileName, outFileName string
  106. fileName = randStr + ".txt"
  107. fileName = uploadDir + fileName
  108. err = utils.SaveToFile(imgData, fileName)
  109. if err != nil {
  110. err = errors.New("图片保存失败,Err:" + err.Error())
  111. return
  112. }
  113. // 删除临时存储的svg文件
  114. defer func() {
  115. err = os.Remove(fileName)
  116. if err != nil {
  117. utils.FileLog.Info("删除临时存储的svg文件失败, err: " + err.Error())
  118. }
  119. }()
  120. outFileName = randStr + ".png"
  121. doneChannel := make(chan bool, 1)
  122. errorChannel := make(chan error, 1)
  123. cmd := exec.Command("highcharts-export-server", "--infile", fileName, "--constr", "Chart", "--scale", "2", "--workers", "10", "--workLimit", "3", "--outfile", outFileName)
  124. go func() {
  125. output, err := cmd.CombinedOutput()
  126. if err != nil {
  127. utils.FileLog.Info("execute command failed, output: , error: \n" + string(output) + err.Error())
  128. errorChannel <- err
  129. return
  130. }
  131. doneChannel <- true
  132. }()
  133. defer func() {
  134. _ = os.Remove(outFileName)
  135. if err != nil {
  136. utils.FileLog.Info("删除生产的图片文件失败, err: " + err.Error())
  137. }
  138. }()
  139. select {
  140. case <-time.After(30 * time.Second):
  141. utils.FileLog.Info("执行超过30秒 杀死超时进程")
  142. e := cmd.Process.Kill()
  143. if e != nil {
  144. fmt.Println("cmd kill err: ", e.Error())
  145. utils.FileLog.Info(fmt.Sprintf("cmd kill err: %s", e.Error()))
  146. errMsg = "图片生成失败"
  147. err = errors.New("图片生成失败, 执行超时" + e.Error())
  148. return
  149. }
  150. fmt.Println("timeout kill process")
  151. case <-doneChannel:
  152. fmt.Println("done")
  153. case e := <-errorChannel:
  154. errMsg = "文件上传失败"
  155. err = errors.New(fmt.Sprintf("execute command failure err: %s", e.Error()))
  156. fmt.Println("execute command failure err:" + e.Error())
  157. return
  158. }
  159. //上传到阿里云 和 minio
  160. ossClient := NewOssClient()
  161. if ossClient == nil {
  162. errMsg = "上传失败"
  163. err = errors.New("初始化OSS服务失败")
  164. return
  165. }
  166. resourceUrl, err = ossClient.UploadFile(outFileName, outFileName, "")
  167. if err != nil {
  168. errMsg = "文件上传失败"
  169. err = errors.New("文件上传失败,Err:" + err.Error())
  170. return
  171. }
  172. return
  173. }
  174. func GeneralWaterMarkPdf(pdfPath, waterMarkStr string) (f2 *bytes.Buffer, err error) {
  175. onTop := true
  176. update := false
  177. //fontDir := `C:\Users\123\go\src\eta\eta_api\static`
  178. fontDir := `static`
  179. font.UserFontDir = fontDir
  180. ttfList := fontDir + `/SimHei.ttf`
  181. err = api.InstallFonts([]string{ttfList})
  182. if err != nil {
  183. fmt.Println("InstallFonts err:", err)
  184. }
  185. api.DisableConfigDir()
  186. f1, err := os.Open(pdfPath)
  187. if err != nil {
  188. fmt.Println("文件不存在")
  189. return
  190. }
  191. defer func() {
  192. _ = f1.Close()
  193. }()
  194. f2 = &bytes.Buffer{}
  195. points := "24" //字号大小
  196. rows := 6 //行数
  197. // 处理文字
  198. textLen := len(waterMarkStr)
  199. count := int(math.Round(250.0 / (float64(textLen) + 18)))
  200. if textLen > 102 {
  201. count = 1
  202. }
  203. if textLen > 210 {
  204. points = "20"
  205. rows = 7
  206. }
  207. var sb1 strings.Builder
  208. for i := 0; i < count; i++ {
  209. sb1.WriteString(waterMarkStr)
  210. }
  211. //单行文字制作完成
  212. sb1Str := sb1.String()
  213. //拼接成多行文字
  214. var sb2 strings.Builder
  215. lineSpace := "\n \n \n \n \n \n"
  216. for i := 0; i < rows; i++ {
  217. sb2.WriteString(sb1Str)
  218. if i < rows-1 {
  219. sb2.WriteString(lineSpace)
  220. }
  221. }
  222. wmList := make([]*model.Watermark, 0)
  223. //for i := types.TopLeft; i <= 9; i++ {
  224. wm, tmpErr := api.TextWatermark(sb2.String(), "fo:SimHei, points:"+points+", col: 0.75 0.75 0.75, scale:1 abs, opacity:0.3", onTop, update, types.POINTS)
  225. if tmpErr != nil {
  226. fmt.Println("TextWatermark err:", tmpErr)
  227. return
  228. }
  229. //wm.Pos = types.Center
  230. wm.Pos = types.TopCenter
  231. wmList = append(wmList, wm)
  232. //}
  233. err = AddWatermarks(f1, f2, nil, wmList, nil)
  234. return
  235. }
  236. func AddWatermarks(rs io.ReadSeeker, w io.Writer, selectedPages []string, wmList []*model.Watermark, conf *model.Configuration) error {
  237. if rs == nil {
  238. return errors.New("pdfcpu: AddWatermarks: missing rs")
  239. }
  240. if conf == nil {
  241. conf = model.NewDefaultConfiguration()
  242. }
  243. conf.Cmd = model.ADDWATERMARKS
  244. conf.OptimizeDuplicateContentStreams = false
  245. if len(wmList) <= 0 {
  246. return errors.New("pdfcpu: missing watermark configuration")
  247. }
  248. ctx, err := api.ReadValidateAndOptimize(rs, conf)
  249. if err != nil {
  250. return err
  251. }
  252. var pages types.IntSet
  253. pages, err = api.PagesForPageSelection(ctx.PageCount, selectedPages, true, true)
  254. if err != nil {
  255. return err
  256. }
  257. for _, wm := range wmList {
  258. if err = pdfcpu.AddWatermarks(ctx, pages, wm); err != nil {
  259. return err
  260. }
  261. }
  262. return api.Write(ctx, w, conf)
  263. }