Skip to content

Instantly share code, notes, and snippets.

@ghandic
Last active March 15, 2024 14:16
Show Gist options
  • Star 37 You must be signed in to star a gist
  • Fork 8 You must be signed in to fork a gist
  • Save ghandic/a48f450f3c011f44d42eea16a0c7014d to your computer and use it in GitHub Desktop.
Save ghandic/a48f450f3c011f44d42eea16a0c7014d to your computer and use it in GitHub Desktop.
Load image from S3 directly into memory as PIL image and write to S3 directly from memory from PIL image
import boto3
from PIL import Image
from io import BytesIO
import os
class S3ImagesInvalidExtension(Exception):
pass
class S3ImagesUploadFailed(Exception):
pass
class S3Images(object):
"""Useage:
images = S3Images(aws_access_key_id='fjrn4uun-my-access-key-589gnmrn90',
aws_secret_access_key='4f4nvu5tvnd-my-secret-access-key-rjfjnubu34un4tu4',
region_name='eu-west-1')
im = images.from_s3('my-example-bucket-9933668', 'pythonlogo.png')
im
images.to_s3(im, 'my-example-bucket-9933668', 'pythonlogo2.png')
"""
def __init__(self, aws_access_key_id, aws_secret_access_key, region_name):
self.s3 = boto3.client('s3', aws_access_key_id=aws_access_key_id,
aws_secret_access_key=aws_secret_access_key,
region_name=region_name)
def from_s3(self, bucket, key):
file_byte_string = self.s3.get_object(Bucket=bucket, Key=key)['Body'].read()
return Image.open(BytesIO(file_byte_string))
def to_s3(self, img, bucket, key):
buffer = BytesIO()
img.save(buffer, self.__get_safe_ext(key))
buffer.seek(0)
sent_data = self.s3.put_object(Bucket=bucket, Key=key, Body=buffer)
if sent_data['ResponseMetadata']['HTTPStatusCode'] != 200:
raise S3ImagesUploadFailed('Failed to upload image {} to bucket {}'.format(key, bucket))
def __get_safe_ext(self, key):
ext = os.path.splitext(key)[-1].strip('.').upper()
if ext in ['JPG', 'JPEG']:
return 'JPEG'
elif ext in ['PNG']:
return 'PNG'
else:
raise S3ImagesInvalidExtension('Extension is invalid')
@terminalh2t3
Copy link

I just warn you that Line 32 probably the cause of memory leaking if you running on a multi-threading job.

@ghandic
Copy link
Author

ghandic commented Oct 20, 2020

Thanks @terminalh2t3 did you have a fix for that?

@shivam-tripathi
Copy link

shivam-tripathi commented Jan 30, 2021

@terminalh2t3 Would running this after getting the image and running whatever processing is required be enough?

image.close()

@ghandic
Copy link
Author

ghandic commented Jan 30, 2021

I think @terminalh253 is referring to spawning multiple clients?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment