status-go/images/adjust.go
belalshehab 7ed92531c2 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
2024-08-14 12:50:10 +02:00

112 lines
2.7 KiB
Go

package images
import (
"bytes"
"errors"
"fmt"
"image"
"io"
"io/ioutil"
"net/http"
"os"
"strings"
)
const (
maxChatMessageImageSize = 400000
resizeTargetImageSize = 350000
idealTargetImageSize = 50000
)
var DefaultBounds = FileSizeLimits{Ideal: idealTargetImageSize, Max: resizeTargetImageSize}
func FetchAndStoreRemoteImage(url string) (string, error) {
resp, err := http.Get(url) //nolint
if err != nil {
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()
img, err := Decode(imagePath)
if err != nil {
return nil, fmt.Errorf("error decoding image: %w", 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, fmt.Errorf("error cropping image: %w", err)
}
}
bb := bytes.NewBuffer([]byte{})
err := CompressToFileLimits(bb, img, DefaultBounds)
if err != nil {
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)
}