fonchain-fiee/pkg/utils/picture.go
2025-02-19 14:24:15 +08:00

206 lines
5.1 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

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
}