package data import ( "context" "fm-upload/internal/biz" "fm-upload/internal/data/model" "fm-upload/utils" "fmt" "math" "os" "regexp" "strconv" "strings" "github.com/go-kratos/kratos/v2/log" ) type imageRepo struct { storage biz.StorageRepo log *log.Helper } // NewGreeterRepo . func NewImageRepo(storage biz.StorageRepo, logger log.Logger) biz.ImageRepo { return &imageRepo{ storage: storage, log: log.NewHelper(logger), } } func (r *imageRepo) ImageDeal(ctx context.Context, tmpfile string, width uint, height uint, x *model.ImageParams, ofmt, fileM, fileId, bucket string) (ret *model.MyPutRet, resUrl, errd string, code int, err error) { var key string bucket0 := bucket tt := strings.Index(bucket, ":") if tt >= 0 && tt < len(bucket)-1 { t1 := strings.Index(bucket, ":") key = bucket[t1+1:] bucket0 = bucket[:t1] } else if tt < 0 { key = strings.ReplaceAll(x.ProcessImageName, " ", "") //指定 if key != "" { re := regexp.MustCompile("[\u4e00-\u9fa5_\\-a-zA-Z0-9\\.]+") t := re.FindAllString(key, -1) key = fileM + strings.Join(t, "") } } if key == "" && x.ProcessImageSuffix != "" { key = fileId + x.ProcessImageSuffix } if tt == len(bucket)-1 { bucket0 = bucket[:len(bucket)-1] if key == "" { bucket = bucket0 } else { bucket += key } } // width0 := width // width0 := height var dwidth, dheight, xx, yy uint if x.Crop != nil { xx = uint(math.Floor(x.Crop.X + 0.5)) yy = uint(math.Floor(x.Crop.Y + 0.5)) t1 := uint(math.Floor(x.Crop.W + 0.5)) t2 := uint(math.Floor(x.Crop.H + 0.5)) if xx+t1 > width { width = width - xx } else { width = t1 } if yy+t2 > height { height = height - yy } else { height = t2 } } if x.Ratio > 0 { dwidth = uint(float32(width) * x.Ratio) dheight = uint(float32(height) * x.Ratio) } else if x.Width > 0 || x.Height > 0 { if x.Height == 0 { dwidth = x.Width dheight = uint(float32(height*dwidth) / float32(width)) } else if x.Width == 0 { dheight = x.Height dwidth = uint(float32(width*dheight) / float32(height)) } else { dwidth = x.Width dheight = x.Height } } else if x.MaxHeight > 0 { if height > x.MaxHeight { dheight = x.MaxHeight dwidth = uint(float32(width*dheight) / float32(height)) } } else if x.MaxWidth > 0 { if width > x.MaxWidth { dwidth = x.MaxWidth dheight = uint(float32(height*dwidth) / float32(width)) } } else if x.Reshape != "" { t1 := strings.Split(x.Reshape, ":") if len(t1) != 2 || t1[0] == "" || t1[1] == "" { errd = "reshape参数错误" code = 425 return } var t2 float64 t2, err = strconv.ParseFloat(t1[0], 32) var t3 float64 if err == nil { t3, err = strconv.ParseFloat(t1[1], 32) } if err != nil { errd = "reshape参数错误" code = 425 return } th := int(t2 / t3 * float64(width)) a := int(height) - th if a > 0 { height = uint(th) yy += uint(a / 2) } else if a < 0 { tw := uint(t3 / t2 * float64(height)) xx += width - tw width = tw } } if key == "" { if dwidth > 0 { key = fileId + fmt.Sprintf("%s_%dx%d.%s", utils.GetUUID()[:4], dwidth, dheight, x.Format) } else { key = fileId + fmt.Sprintf("%s_%dx%d.%s", utils.GetUUID()[:4], width, height, x.Format) } } re := regexp.MustCompile(`([0-9\.]+)(\w?)`) t := re.FindStringSubmatch(strings.ToLower(x.ImageSize)) limitSize := int64(0) if len(t) > 0 { a, _ := strconv.ParseFloat(t[1], 32) if a > 0 { if t[2] == "k" { a *= 1024 } else if t[2] == "m" { a *= 1048576 } limitSize = int64(a) } } var out []byte var cmdString string var tmpfile2 string x.Format = strings.ToLower(x.Format) if x.Format == "webp" { if x.Quality == 0 { if x.ImageSize != "" { if limitSize > 0 { cmdString = fmt.Sprintf("cwebp -quiet -m 6 -size %d", limitSize) } } if cmdString == "" { cmdString = "cwebp -quiet -q 100 -m 6" } } else { if x.Quality > 100 { x.Quality = 100 } cmdString = fmt.Sprintf("cwebp -quiet -q %d -alpha_q 1 -m 6", x.Quality) } if x.Crop != nil { cmdString += fmt.Sprintf(" -crop %d %d %d %d", xx, yy, width, height) } if dwidth > 0 { cmdString += fmt.Sprintf(" -resize %d %d", dwidth, dheight) } // cmdString += " -o - -- -" cmdString += fmt.Sprintf(" -blend_alpha 0xffffff %s -o -", tmpfile) out, err = utils.RunCommand(cmdString, nil, true) if err == nil { ret, err = r.storage.SaveToHw(ctx, out, key, bucket) } } else { var tof string if x.Format == "heic" { tof = "HEIF" } else if x.Format == "jpg" || x.Format == "jpeg" { tof = "JPEG" } else { tof = strings.ToUpper(x.Format) } if tof == "JPEG" { tmpfile2 = tmpfile + ".jpg" defer func() { _ = os.Remove(tmpfile2) }() // if ofmt != "JPEG" || dwidth > 0 || x.Crop != nil || x.Reshape != "" { cmdString = fmt.Sprintf("convert %s -background white -alpha remove -alpha off -flatten -compress LOSSLESS", tmpfile) if x.Crop != nil || x.Reshape != "" { cmdString += fmt.Sprintf(" -crop %dx%d+%d+%d", width, height, xx, yy) } if dwidth > 0 { cmdString += fmt.Sprintf(" -resize %dx%d", dwidth, dheight) } cmdString += fmt.Sprintf(" %s", tmpfile2) _, err = utils.RunCommand(cmdString, nil, false) // } if err == nil { q := uint(0) if x.Quality > 0 { q = x.Quality - 1 if q == 0 { q = 1 } } cmdString := "jpegoptim -q" if x.Progressive { cmdString += " --all-progressive" x.Progressive = false } if q > 0 { cmdString += fmt.Sprintf(" -m %d", q) } if x.ImageSize != "" { cmdString += fmt.Sprintf(" --size %s", x.ImageSize) } cmdString += fmt.Sprintf(" %s", tmpfile2) _, err = utils.RunCommand(cmdString, nil, false) } if err != nil { code = 425 errd = "image process error" return } ret, err = r.storage.SaveFileToHw(ctx, tmpfile2, key, bucket) } else if tof == "PNG" { tmpfile0 := tmpfile tmpfile2 = tmpfile + ".png" tmpfile3 := tmpfile + "3.png" defer func() { _ = os.Remove(tmpfile2) _ = os.Remove(tmpfile3) }() q := uint(0) if x.Quality > 0 { q = x.Quality - 1 if q == 0 { q = 1 } } if ofmt != "PNG" || dwidth > 0 || x.Crop != nil || x.Reshape != "" { cmdString = fmt.Sprintf("convert %s -compress LOSSLESS", tmpfile) if x.Crop != nil || x.Reshape != "" { cmdString += fmt.Sprintf(" -crop %dx%d+%d+%d", width, height, xx, yy) } if x.Progressive { cmdString += " -interlace Plane" } if q > 0 { cmdString += fmt.Sprintf(" -m %d", q) } if dwidth > 0 { cmdString += fmt.Sprintf(" -resize %dx%d", dwidth, dheight) } cmdString += fmt.Sprintf(" %s", tmpfile2) _, err = utils.RunCommand(cmdString, nil, false) tmpfile0 = tmpfile2 // err = mw.ResizeImage(dwidth, dheight, imagick.FILTER_LANCZOS) } if err == nil { cmdString := fmt.Sprintf("optipng -quiet %s -out %s", tmpfile0, tmpfile2) _, err = utils.RunCommand(cmdString, nil, false) } if limitSize > 0 { qs := []uint{90, 80, 70, 60, 40} fi, _ := os.Stat(tmpfile2) lastSize := fi.Size() _, err = utils.RunCommand(fmt.Sprintf("cp %s %s", tmpfile2, tmpfile3), nil, false) for i := 0; i < 5 && err == nil; i++ { if qs[i] > q { continue } cmdString := fmt.Sprintf("convert %s -m %d %s", tmpfile3, qs[i], tmpfile2) _, err = utils.RunCommand(cmdString, nil, false) if err != nil { break } cmdString = fmt.Sprintf("optipng -quiet %s -out %s", tmpfile2, tmpfile2) _, err = utils.RunCommand(cmdString, nil, false) fi, _ := os.Stat(tmpfile2) if fi.Size() <= limitSize || fi.Size() >= lastSize { break } lastSize = fi.Size() } } if err != nil { code = 425 errd = "image process error" return } ret, err = r.storage.SaveFileToHw(ctx, tmpfile2, key, bucket) } else { tmpfile2 := tmpfile + "." + x.Format tmpfile3 := tmpfile + "3." + x.Format defer func() { _ = os.Remove(tmpfile2) _ = os.Remove(tmpfile3) }() cmdString = "convert " + tmpfile + " -background white -alpha remove -alpha off -flatten" if x.Crop != nil || x.Reshape != "" { cmdString += fmt.Sprintf(" -crop %dx%d+%d+%d", width, height, xx, yy) } if x.Progressive { cmdString += " -interlace Plane" } if x.Quality > 0 { cmdString += fmt.Sprintf(" -quality %d", x.Quality-1) } else { cmdString += " -compress LOSSLESS" } if dwidth > 0 { cmdString += fmt.Sprintf(" -resize %dx%d", dwidth, dheight) } cmdString += " " + tmpfile2 _, err = utils.RunCommand(cmdString, nil, false) if err == nil && limitSize > 0 { _, err = utils.RunCommand(fmt.Sprintf("cp %s %s", tmpfile2, tmpfile3), nil, false) for i := 0; i < 2 && err == nil; i++ { fi, _ := os.Stat(tmpfile2) q := uint(float64(limitSize) / float64(fi.Size()) * 100) if q >= 100 { break } if q < 5 { q = 5 } cmdString += fmt.Sprintf("convert %s -m %d %s", tmpfile3, q, tmpfile2) _, err = utils.RunCommand(cmdString, nil, false) } } if err != nil { code = 425 errd = "image process error" return } ret, err = r.storage.SaveFileToHw(ctx, tmpfile2, key, bucket) } } if err != nil { code = 426 errd = "error upload to qiniuyun" return } resUrl = ret.ReturnPrefix + key return }