package services import ( "bytes" "errors" "eta/eta_api/models" "eta/eta_api/utils" "fmt" "github.com/pdfcpu/pdfcpu/pkg/api" "github.com/pdfcpu/pdfcpu/pkg/font" "github.com/pdfcpu/pdfcpu/pkg/pdfcpu" "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/model" "github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types" "io" "mime/multipart" "os" "os/exec" "strings" "time" ) // UploadToOssAndFileName 上传到oss并使用这个名称 func UploadToOssAndFileName(fileMulti multipart.File, newFileName string) (resourceUrl string, err error) { dateDir := time.Now().Format("20060102") uploadDir := utils.STATIC_DIR + "hongze/" + dateDir err = os.MkdirAll(uploadDir, utils.DIR_MOD) if err != nil { err = errors.New("存储目录创建失败,Err:" + err.Error()) return } //本地地址 fpath := uploadDir + "/" + newFileName err = saveToFile(fileMulti, fpath) if err != nil { err = errors.New("文件上传失败,Err:" + err.Error()) return } //上传到阿里云 和 minio //if utils.ObjectStorageClient == "minio" { // resourceUrl, err = UploadImgToMinIo(newFileName, fpath) // if err != nil { // err = errors.New("文件上传失败,Err:" + err.Error()) // return // } //} else { // resourceUrl, err = UploadAliyunV2(newFileName, fpath) // if err != nil { // err = errors.New("文件上传失败,Err:" + err.Error()) // return // } //} ossClient := NewOssClient() if ossClient == nil { err = fmt.Errorf("初始化OSS服务失败") return } resourceUrl, err = ossClient.UploadFile(newFileName, fpath, "") if err != nil { err = fmt.Errorf("文件上传失败, Err: %s", err.Error()) return } defer func() { os.Remove(fpath) }() item := new(models.Resource) item.ResourceUrl = resourceUrl item.ResourceType = 1 item.CreateTime = time.Now() _, err = models.AddResource(item) if err != nil { err = errors.New("资源上传失败,Err:" + err.Error()) return } return } // saveToFile 保存到本地文件 func saveToFile(fileMulti multipart.File, tofile string) error { f, err := os.OpenFile(tofile, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0666) if err != nil { return err } defer f.Close() io.Copy(f, fileMulti) return nil } // GetResourceUrlBySvgImg // @Description: 通过svg图片生成图片资源地址(传到OSS后的地址) // @author: Roc // @datetime 2024-07-16 10:18:09 // @param imgData string // @return resourceUrl string // @return err error // @return errMsg string func GetResourceUrlBySvgImg(imgData string) (resourceUrl string, err error, errMsg string) { errMsg = "图表保存失败" uploadDir := "static/images/" if !utils.FileIsExist(uploadDir) { err = os.MkdirAll(uploadDir, utils.DIR_MOD) if err != nil { err = errors.New("存储目录创建失败,Err:" + err.Error()) return } } //var saveToOssPath string randStr := utils.GetRandStringNoSpecialChar(28) var fileName, outFileName string fileName = randStr + ".txt" fileName = uploadDir + fileName err = utils.SaveToFile(imgData, fileName) if err != nil { err = errors.New("图片保存失败,Err:" + err.Error()) return } // 删除临时存储的svg文件 defer func() { err = os.Remove(fileName) if err != nil { utils.FileLog.Info("删除临时存储的svg文件失败, err: " + err.Error()) } }() outFileName = randStr + ".png" doneChannel := make(chan bool, 1) errorChannel := make(chan error, 1) cmd := exec.Command("highcharts-export-server", "--infile", fileName, "--constr", "Chart", "--scale", "2", "--workers", "10", "--workLimit", "3", "--outfile", outFileName) go func() { output, err := cmd.CombinedOutput() if err != nil { utils.FileLog.Info("execute command failed, output: , error: \n" + string(output) + err.Error()) errorChannel <- err return } doneChannel <- true }() defer func() { _ = os.Remove(outFileName) if err != nil { utils.FileLog.Info("删除生产的图片文件失败, err: " + err.Error()) } }() select { case <-time.After(30 * time.Second): utils.FileLog.Info("执行超过30秒 杀死超时进程") e := cmd.Process.Kill() if e != nil { fmt.Println("cmd kill err: ", e.Error()) utils.FileLog.Info(fmt.Sprintf("cmd kill err: %s", e.Error())) errMsg = "图片生成失败" err = errors.New("图片生成失败, 执行超时" + e.Error()) return } fmt.Println("timeout kill process") case <-doneChannel: fmt.Println("done") case e := <-errorChannel: errMsg = "文件上传失败" err = errors.New(fmt.Sprintf("execute command failure err: %s", e.Error())) fmt.Println("execute command failure err:" + e.Error()) return } //上传到阿里云 和 minio ossClient := NewOssClient() if ossClient == nil { errMsg = "上传失败" err = errors.New("初始化OSS服务失败") return } resourceUrl, err = ossClient.UploadFile(outFileName, outFileName, "") if err != nil { errMsg = "文件上传失败" err = errors.New("文件上传失败,Err:" + err.Error()) return } return } func GeneralWaterMarkPdf(pdfPath, waterMarkStr string) (f2 *bytes.Buffer, err error) { onTop := true update := false desc := "fo:SimHei, points:38, rot:30, col: 0.75 0.75 0.75, scale:1 abs, opacity:0.3" fontDir := `static` font.UserFontDir = fontDir ttfList := fontDir + `/SimHei.ttf` err = api.InstallFonts([]string{ttfList}) if err != nil { fmt.Println("InstallFonts err:", err) } api.DisableConfigDir() f1, err := os.Open(pdfPath) if err != nil { fmt.Println("文件不存在") return } defer func() { _ = f1.Close() }() fmt.Println(len(waterMarkStr)) f2 = &bytes.Buffer{} wm, tmpErr := api.TextWatermark(waterMarkStr, desc, onTop, update, types.POINTS) if tmpErr != nil { fmt.Println("TextWatermark err:", tmpErr) return } wm.Pos = types.TopCenter realFontSize := wm.ScaledFontSize if realFontSize <= 0 { realFontSize = wm.FontSize } targetLineWidth := font.TextWidth(waterMarkStr, wm.FontName, realFontSize) targetText := waterMarkStr var ctxCpu *model.Context ctxCpu, err = api.ReadValidateAndOptimize(f1, api.LoadConfiguration()) if err != nil { return nil, err } var dms []types.Dim dms, err = ctxCpu.PageDims() if err != nil { return nil, err } dm := dms[0] fmt.Println("targetLineWidth", targetLineWidth) if targetLineWidth*2 > dm.Width { targetText += " " for _, v := range waterMarkStr { if dm.Width <= targetLineWidth { break } targetText += fmt.Sprintf("%c", v) targetLineWidth = font.TextWidth(targetText, wm.FontName, realFontSize) } } else { for dm.Width >= targetLineWidth { targetText += " " + waterMarkStr targetLineWidth = font.TextWidth(targetText, wm.FontName, realFontSize) } } fmt.Println("dm.Width", dm.Width, " dm.Height", dm.Height) var sb2 strings.Builder lineSpace := "\n \n \n" rows := 8 targetText1 := "" targetLength := len(targetText) for _, v := range targetText { if targetLength-len(targetText1) < 8 { break } targetText1 += fmt.Sprintf("%c", v) } //fmt.Println(targetText1) for i := 0; i < rows; i++ { if i%2 == 0 { sb2.WriteString(targetText) } else { sb2.WriteString(strings.Repeat(" ", 8)) sb2.WriteString(targetText1) } if i < rows-1 { sb2.WriteString(lineSpace) } } //fmt.Println(sb2.String()) wmList := make([]*model.Watermark, 0) wm, tmpErr = api.TextWatermark(sb2.String(), desc, onTop, update, types.POINTS) if tmpErr != nil { fmt.Println("TextWatermark err:", tmpErr) return } wm.Pos = types.TopCenter wmList = append(wmList, wm) err = AddWatermarks(f1, f2, nil, wmList, nil) return } func AddWatermarks(rs io.ReadSeeker, w io.Writer, selectedPages []string, wmList []*model.Watermark, conf *model.Configuration) error { if rs == nil { return errors.New("pdfcpu: AddWatermarks: missing rs") } if conf == nil { conf = model.NewDefaultConfiguration() } conf.Cmd = model.ADDWATERMARKS conf.OptimizeDuplicateContentStreams = false if len(wmList) <= 0 { return errors.New("pdfcpu: missing watermark configuration") } ctx, err := api.ReadValidateAndOptimize(rs, conf) if err != nil { return err } var pages types.IntSet pages, err = api.PagesForPageSelection(ctx.PageCount, selectedPages, true, true) if err != nil { return err } for _, wm := range wmList { if err = pdfcpu.AddWatermarks(ctx, pages, wm); err != nil { return err } } return api.Write(ctx, w, conf) }