github.com/status-im/status-go@v1.1.0/images/adjust.go (about) 1 package images 2 3 import ( 4 "bytes" 5 "errors" 6 "fmt" 7 "image" 8 "io" 9 "io/ioutil" 10 "net/http" 11 "os" 12 "strings" 13 ) 14 15 const ( 16 maxChatMessageImageSize = 400000 17 resizeTargetImageSize = 350000 18 idealTargetImageSize = 50000 19 ) 20 21 var DefaultBounds = FileSizeLimits{Ideal: idealTargetImageSize, Max: resizeTargetImageSize} 22 23 func FetchAndStoreRemoteImage(url string) (string, error) { 24 resp, err := http.Get(url) //nolint 25 if err != nil { 26 return "", fmt.Errorf("error fetching image from URL: %w", err) 27 } 28 defer resp.Body.Close() 29 30 if resp.StatusCode != http.StatusOK { 31 return "", fmt.Errorf("bad status code: %s", resp.Status) 32 } 33 34 tempFile, err := ioutil.TempFile("", "image-*") 35 if err != nil { 36 return "", fmt.Errorf("error creating a temporary file: %w", err) 37 } 38 defer tempFile.Close() 39 40 _, err = io.Copy(tempFile, resp.Body) 41 if err != nil { 42 os.Remove(tempFile.Name()) // Ensure temporary file is deleted on error 43 return "", fmt.Errorf("error writing image to temp file: %w", err) 44 } 45 46 return tempFile.Name(), nil 47 } 48 49 func OpenAndDecodeImage(imagePath string) (image.Image, error) { 50 file, err := os.Open(imagePath) 51 if err != nil { 52 return nil, fmt.Errorf("error opening image file: %w", err) 53 } 54 defer file.Close() 55 56 img, err := Decode(imagePath) 57 if err != nil { 58 return nil, fmt.Errorf("error decoding image: %w", err) 59 } 60 61 return img, nil 62 } 63 64 func AdjustImage(img image.Image, crop bool, inputImage CroppedImage) ([]byte, error) { 65 if crop { 66 cropRect := image.Rectangle{ 67 Min: image.Point{X: inputImage.X, Y: inputImage.Y}, 68 Max: image.Point{X: inputImage.X + inputImage.Width, Y: inputImage.Y + inputImage.Height}, 69 } 70 var err error 71 img, err = Crop(img, cropRect) 72 if err != nil { 73 return nil, fmt.Errorf("error cropping image: %w", err) 74 } 75 } 76 77 bb := bytes.NewBuffer([]byte{}) 78 err := CompressToFileLimits(bb, img, DefaultBounds) 79 if err != nil { 80 return nil, fmt.Errorf("error compressing image: %w", err) 81 } 82 83 payload := bb.Bytes() 84 if len(payload) > maxChatMessageImageSize { 85 return nil, errors.New("image too large") 86 } 87 88 return payload, nil 89 } 90 func OpenAndAdjustImage(inputImage CroppedImage, crop bool) ([]byte, error) { 91 var imgPath string = inputImage.ImagePath 92 var err error 93 94 // Check if the image is from a remote source 95 if strings.HasPrefix(inputImage.ImagePath, "http://") || strings.HasPrefix(inputImage.ImagePath, "https://") { 96 imgPath, err = FetchAndStoreRemoteImage(inputImage.ImagePath) 97 if err != nil { 98 return nil, err 99 } 100 defer os.Remove(imgPath) // Clean up the temporary file 101 } 102 103 // Decode the image 104 img, err := OpenAndDecodeImage(imgPath) 105 if err != nil { 106 return nil, err 107 } 108 109 // Adjust (crop and compress) the image 110 return AdjustImage(img, crop, inputImage) 111 }