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 }