Skip to content

Commit 1f343c4

Browse files
Added code to reduce image size before sending to bedrock
1 parent 5a3d111 commit 1f343c4

File tree

1 file changed

+68
-14
lines changed

1 file changed

+68
-14
lines changed

src/fmcore/algorithm/bedrock.py

Lines changed: 68 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,68 @@ class ConfigSelectionStrategy(AutoEnum):
5252
import boto3
5353
import imageio
5454
from botocore.exceptions import ClientError
55+
from PIL import Image
56+
57+
def _compress_image_for_bedrock(image_bytes: bytes, max_size_mb: float = 4.5) -> bytes:
58+
"""
59+
Compress an image to stay under the specified size limit for Bedrock.
60+
61+
Args:
62+
image_bytes (bytes): Original image bytes
63+
max_size_mb (float): Maximum size in MB (default 4.5 to stay well under 5MB limit)
64+
65+
Returns:
66+
bytes: Compressed image bytes in PNG format
67+
"""
68+
max_size_bytes = int(max_size_mb * 1024 * 1024)
69+
70+
# Load image using PIL for better compression control
71+
image = Image.open(BytesIO(image_bytes))
72+
73+
# Convert to RGB if necessary (for PNG compatibility)
74+
if image.mode in ('RGBA', 'LA', 'P'):
75+
# Convert RGBA/LA to RGB with white background
76+
background = Image.new('RGB', image.size, (255, 255, 255))
77+
if image.mode == 'P':
78+
image = image.convert('RGBA')
79+
background.paste(image, mask=image.split()[-1] if image.mode in ('RGBA', 'LA') else None)
80+
image = background
81+
elif image.mode != 'RGB':
82+
image = image.convert('RGB')
83+
84+
# Start with original size and progressively reduce if needed
85+
quality = 95
86+
scale_factor = 1.0
87+
88+
while True:
89+
# Scale down image if needed
90+
if scale_factor < 1.0:
91+
new_width = int(image.width * scale_factor)
92+
new_height = int(image.height * scale_factor)
93+
resized_image = image.resize((new_width, new_height), Image.Resampling.LANCZOS)
94+
else:
95+
resized_image = image
96+
97+
# Compress to PNG with specified quality
98+
output = BytesIO()
99+
resized_image.save(output, format='PNG', optimize=True)
100+
compressed_bytes = output.getvalue()
101+
102+
# Check if we're under the size limit
103+
if len(compressed_bytes) <= max_size_bytes:
104+
return compressed_bytes
105+
106+
# If still too large, try reducing quality or scale
107+
if quality > 60:
108+
quality -= 10
109+
elif scale_factor > 0.5:
110+
scale_factor -= 0.1
111+
quality = 95 # Reset quality when scaling
112+
else:
113+
# If we can't compress enough, return what we have
114+
Log.warning(f"Unable to compress image below {max_size_mb}MB limit. "
115+
f"Final size: {len(compressed_bytes) / (1024*1024):.2f}MB")
116+
return compressed_bytes
55117

56118
def process_image_url(image_url: str) -> Optional[str]:
57119
"""
@@ -74,15 +136,11 @@ def process_image_url(image_url: str) -> Optional[str]:
74136
response.raise_for_status()
75137
image_bytes = response.content
76138

77-
## Convert the image to a standard format (PNG):
78-
image_array = imageio.imread(BytesIO(image_bytes))
79-
memfile = BytesIO()
80-
imageio.imwrite(memfile, image_array, format="png")
81-
memfile.seek(0)
82-
png_bytes = memfile.read()
139+
## Compress the image to stay under Bedrock's 5MB limit:
140+
compressed_bytes = _compress_image_for_bedrock(image_bytes)
83141

84142
## Encode as base64:
85-
base64_image = base64.b64encode(png_bytes).decode("utf-8")
143+
base64_image = base64.b64encode(compressed_bytes).decode("utf-8")
86144
return base64_image
87145
except Exception as e:
88146
Log.error(f"Failed to process image from URL {image_url}: {e}")
@@ -125,15 +183,11 @@ def process_image_s3(s3_path: str, aws_session: Optional[Any] = None) -> Optiona
125183
response = s3_client.get_object(Bucket=bucket_name, Key=object_key)
126184
image_bytes = response["Body"].read()
127185

128-
# Convert the image to a standard format (PNG)
129-
image_array = imageio.imread(BytesIO(image_bytes))
130-
memfile = BytesIO()
131-
imageio.imwrite(memfile, image_array, format="png")
132-
memfile.seek(0)
133-
png_bytes = memfile.read()
186+
# Compress the image to stay under Bedrock's 5MB limit
187+
compressed_bytes = _compress_image_for_bedrock(image_bytes)
134188

135189
# Encode as base64
136-
base64_image = base64.b64encode(png_bytes).decode("utf-8")
190+
base64_image = base64.b64encode(compressed_bytes).decode("utf-8")
137191
return base64_image
138192
except Exception as e:
139193
Log.error(f"Failed to process image from S3 {s3_path}: {e}")

0 commit comments

Comments
 (0)