fonchain-fiee/pkg/utils/picture.go

206 lines
5.1 KiB
Go
Raw Normal View History

2025-02-19 06:24:15 +00:00
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
}