fix(wallet)_: Fix handling of remote image URLs in image processing

- Addressed the issue where remote image URLs failed to be processed due to local file handling restrictions.
    - Introduced `FetchAndStoreRemoteImage` to download and save remote images to a temporary file, enabling compatibility with existing processing functions.
    - Split the main image handling logic into smaller functions (`OpenAndDecodeImage`, `AdjustImage`) for better modularity and maintainability.
    - Updated `OpenAndAdjustImage` to use these new functions, ensuring a streamlined flow for both local and remote images.
    - Added cleanup steps for temporary files to prevent resource leaks.

    resolves: #15691
This commit is contained in:
belalshehab 2024-07-22 04:01:05 +03:00 committed by Anthony Laibe
parent 130c995b92
commit 7ed92531c2
1 changed files with 65 additions and 17 deletions

View File

@ -3,9 +3,13 @@ package images
import (
"bytes"
"errors"
"fmt"
"image"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
)
const (
@ -16,48 +20,92 @@ const (
var DefaultBounds = FileSizeLimits{Ideal: idealTargetImageSize, Max: resizeTargetImageSize}
func OpenAndAdjustImage(inputImage CroppedImage, crop bool) ([]byte, error) {
file, err := os.Open(inputImage.ImagePath)
func FetchAndStoreRemoteImage(url string) (string, error) {
resp, err := http.Get(url) //nolint
if err != nil {
return nil, err
return "", fmt.Errorf("error fetching image from URL: %w", err)
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", fmt.Errorf("bad status code: %s", resp.Status)
}
tempFile, err := ioutil.TempFile("", "image-*")
if err != nil {
return "", fmt.Errorf("error creating a temporary file: %w", err)
}
defer tempFile.Close()
_, err = io.Copy(tempFile, resp.Body)
if err != nil {
os.Remove(tempFile.Name()) // Ensure temporary file is deleted on error
return "", fmt.Errorf("error writing image to temp file: %w", err)
}
return tempFile.Name(), nil
}
func OpenAndDecodeImage(imagePath string) (image.Image, error) {
file, err := os.Open(imagePath)
if err != nil {
return nil, fmt.Errorf("error opening image file: %w", err)
}
defer file.Close()
payload, err := ioutil.ReadAll(file)
img, err := Decode(imagePath)
if err != nil {
return nil, err
return nil, fmt.Errorf("error decoding image: %w", err)
}
img, err := Decode(inputImage.ImagePath)
if err != nil {
return nil, err
}
return img, nil
}
func AdjustImage(img image.Image, crop bool, inputImage CroppedImage) ([]byte, error) {
if crop {
cropRect := image.Rectangle{
Min: image.Point{X: inputImage.X, Y: inputImage.Y},
Max: image.Point{X: inputImage.X + inputImage.Width, Y: inputImage.Y + inputImage.Height},
}
var err error
img, err = Crop(img, cropRect)
if err != nil {
return nil, err
return nil, fmt.Errorf("error cropping image: %w", err)
}
}
bb := bytes.NewBuffer([]byte{})
err = CompressToFileLimits(bb, img, DefaultBounds)
err := CompressToFileLimits(bb, img, DefaultBounds)
if err != nil {
return nil, err
}
// We keep the smallest one
if len(payload) > len(bb.Bytes()) {
payload = bb.Bytes()
return nil, fmt.Errorf("error compressing image: %w", err)
}
payload := bb.Bytes()
if len(payload) > maxChatMessageImageSize {
return nil, errors.New("image too large")
}
return payload, nil
}
func OpenAndAdjustImage(inputImage CroppedImage, crop bool) ([]byte, error) {
var imgPath string = inputImage.ImagePath
var err error
// Check if the image is from a remote source
if strings.HasPrefix(inputImage.ImagePath, "http://") || strings.HasPrefix(inputImage.ImagePath, "https://") {
imgPath, err = FetchAndStoreRemoteImage(inputImage.ImagePath)
if err != nil {
return nil, err
}
defer os.Remove(imgPath) // Clean up the temporary file
}
// Decode the image
img, err := OpenAndDecodeImage(imgPath)
if err != nil {
return nil, err
}
// Adjust (crop and compress) the image
return AdjustImage(img, crop, inputImage)
}