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
|
|||
|
}
|