You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
357 lines
9.3 KiB
357 lines
9.3 KiB
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
|
|
}
|
|
|