206 lines
5.1 KiB
Go
206 lines
5.1 KiB
Go
package utils
|
||
|
||
import (
|
||
"bytes"
|
||
"fmt"
|
||
"github.com/fonchain_enterprise/fonchain-main/pkg/e"
|
||
"github.com/go-errors/errors"
|
||
"github.com/google/uuid"
|
||
"github.com/nfnt/resize"
|
||
"go.uber.org/zap"
|
||
"golang.org/x/image/bmp"
|
||
"image"
|
||
"image/jpeg"
|
||
"image/png"
|
||
"os"
|
||
"path"
|
||
"strings"
|
||
)
|
||
|
||
const (
|
||
CompressLimit = 1024 * 1024 * 1
|
||
MaxHeight uint = 600
|
||
)
|
||
|
||
// CompressJPG 压缩图片,并返回缩略图路径
|
||
func CompressJPG(dst string, newDst string) (err error) {
|
||
filebytes, err := os.ReadFile(dst)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
compressbytes := compressImageResource(filebytes)
|
||
fo, err := os.Create(newDst)
|
||
defer fo.Close()
|
||
if err != nil {
|
||
return err
|
||
}
|
||
_, err = fo.Write(compressbytes)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
return nil
|
||
}
|
||
|
||
func compressImageResource(data []byte) []byte {
|
||
if len(data) < CompressLimit {
|
||
return data
|
||
}
|
||
img, _, err := image.Decode(bytes.NewReader(data))
|
||
if err != nil {
|
||
return data
|
||
}
|
||
m := resize.Resize(0, MaxHeight, img, resize.Lanczos3)
|
||
buf := bytes.Buffer{}
|
||
|
||
err = jpeg.Encode(&buf, m, &jpeg.Options{Quality: 100})
|
||
if err != nil {
|
||
zap.L().Error("compressImageResource Encode err", zap.Error(err))
|
||
return data
|
||
}
|
||
if buf.Len() > len(data) {
|
||
return data
|
||
}
|
||
fmt.Println(buf.Len())
|
||
if buf.Len() >= CompressLimit {
|
||
bytes := compressImageResource(buf.Bytes())
|
||
return bytes
|
||
}
|
||
return buf.Bytes()
|
||
}
|
||
|
||
/*
|
||
**
|
||
// https://cdns.fontree.cn/fonchain-main/dev/file/artwork/config/1234.jpg
|
||
// https://cdns.fontree.cn/fonchain-main/dev/file/artwork/config/new_image.jpg
|
||
*/
|
||
func ResizeImg(url string) (newImgPath string, err error) {
|
||
var isCompress bool
|
||
widthLimit, heightLimit := 400, 5000
|
||
imgExt := strings.Replace(path.Ext(url), ".", "", 1)
|
||
uuidName := uuid.New().String()
|
||
fileName := fmt.Sprintf("%s.%s", uuidName, imgExt)
|
||
fullpath, _err := SaveUrlFileDisk(url, "./runtime/copyright/image", fileName)
|
||
if _err != nil {
|
||
err = _err
|
||
return
|
||
}
|
||
newImgCompressPath := fmt.Sprintf("./runtime/copyright/image/compress_%s", fileName)
|
||
if isCompress, err = CompressImage(fullpath, newImgCompressPath); err != nil {
|
||
return
|
||
}
|
||
if !isCompress {
|
||
newImgCompressPath = fullpath
|
||
}
|
||
newImgPath = newImgCompressPath
|
||
// 打开图片并解码
|
||
file, err := os.Open(newImgCompressPath)
|
||
if err != nil {
|
||
err = errors.New(e.GetMsg(e.ERROR_OPEN_FILE))
|
||
return
|
||
}
|
||
var img image.Image
|
||
switch imgExt {
|
||
case "jpg", "jpeg":
|
||
img, err = jpeg.Decode(file)
|
||
case "png":
|
||
img, err = png.Decode(file)
|
||
case "bmp":
|
||
img, err = bmp.Decode(file)
|
||
default:
|
||
err = errors.New(e.ErrorImgExt)
|
||
return
|
||
}
|
||
if img == nil {
|
||
zap.L().Error("ResizeImg decode err", zap.String("url", url))
|
||
err = errors.New(e.ErrorImgDecode)
|
||
return
|
||
}
|
||
if err != nil {
|
||
zap.L().Error("ResizeImg decode err", zap.Error(err), zap.String("url", url))
|
||
err = errors.New(e.GetMsg(e.ERROR_ROTATE_IMG))
|
||
return
|
||
}
|
||
file.Close()
|
||
// 获取原图片的尺寸
|
||
bounds := img.Bounds()
|
||
width, height := bounds.Max.X, bounds.Max.Y
|
||
|
||
// 如果图片的分辨率不在500和2000之间,则进行等比例缩放或拉伸
|
||
var newWidth, newHeight uint
|
||
if width < widthLimit || width > heightLimit || height < widthLimit || height > heightLimit {
|
||
if width > height {
|
||
newWidth = uint(heightLimit)
|
||
newHeight = uint(heightLimit) * uint(height) / uint(width)
|
||
} else {
|
||
newHeight = uint(heightLimit)
|
||
newWidth = uint(heightLimit) * uint(width) / uint(height)
|
||
}
|
||
} else {
|
||
return
|
||
}
|
||
defer os.Remove(fullpath)
|
||
// 调用resize库进行图片缩放
|
||
newImg := resize.Resize(newWidth, newHeight, img, resize.Lanczos3)
|
||
newImgPath = fmt.Sprintf("./runtime/copyright/image/resize_%s", fileName)
|
||
out, err := os.Create(newImgPath)
|
||
if err != nil {
|
||
err = errors.New(e.GetMsg(e.ErrorFileCreate))
|
||
return
|
||
}
|
||
defer out.Close()
|
||
switch imgExt {
|
||
case "jpg", "jpeg":
|
||
jpeg.Encode(out, newImg, nil)
|
||
case "png":
|
||
png.Encode(out, newImg)
|
||
case "bmp":
|
||
bmp.Encode(out, newImg)
|
||
}
|
||
return
|
||
}
|
||
|
||
func CompressImage(filepath string, newPath string) (isCompress bool, err error) {
|
||
var MaxFileSize int64 = 5 * 1024 * 1024 // 5MB
|
||
var MaxQuality int64 = 100
|
||
zap.L().Info("CompressImage 1")
|
||
src, err := os.Open(filepath)
|
||
fileInfo, _ := os.Stat(filepath)
|
||
zap.L().Info("CompressImage 2")
|
||
fileSize := fileInfo.Size()
|
||
if fileSize < MaxFileSize {
|
||
return
|
||
}
|
||
zap.L().Info("CompressImage 3")
|
||
qualityF := int64((float64(fileSize-MaxFileSize) / float64(fileSize)) * float64(MaxQuality))
|
||
qualityF = MaxQuality - qualityF
|
||
if qualityF < 0 {
|
||
qualityF = MaxFileSize
|
||
}
|
||
if err != nil {
|
||
err = errors.New(e.GetMsg(e.ErrorReadFile))
|
||
return
|
||
}
|
||
defer src.Close()
|
||
zap.L().Info("CompressImage 4")
|
||
img, _, err := image.Decode(src)
|
||
zap.L().Info("CompressImage 5")
|
||
if err != nil {
|
||
err = errors.New(e.GetMsg(e.ErrorReadFile))
|
||
return
|
||
}
|
||
zap.L().Info("CompressImage 6")
|
||
for quality := qualityF; quality >= 1; quality -= 5 { // decrease quality by 5 each time.
|
||
zap.L().Info("CompressImage 7")
|
||
buf := &bytes.Buffer{}
|
||
if err := jpeg.Encode(buf, img, &jpeg.Options{Quality: int(quality)}); err != nil {
|
||
continue
|
||
}
|
||
zap.L().Info("CompressImage 8")
|
||
if buf.Len() < int(MaxFileSize) {
|
||
return true, os.WriteFile(newPath, buf.Bytes(), 0644)
|
||
}
|
||
zap.L().Info("CompressImage 9")
|
||
}
|
||
return
|
||
}
|