Upload Thumbnail Image to S3 using Boto3
Asked Answered
B

1

5

I'm using the Falcon framework and Pillow to upload a profile picture of a contact to S3, then resizing that picture for a thumbnail, and then uploading that thumbnail.

I've looked at other answers but some of them require having bucket write access activated and some use django's default_storage feature which I don't have available.

client = boto3.client('s3',
    aws_access_key_id=os.environ.get('AWS_ACCESS_KEY_ID'),
    aws_secret_access_key=os.environ.get('AWS_SECRET_ACCESS_KEY')
)


class UploadResource(object):

    def on_post(self, req, res):
        #gathering file from SPA
        contact_id = req.get_param('id')
        filename = req.get_param('file').filename
        file = req.get_param('file').file
        salt = ''.join(chr(random.randint(97, 122)) for i in range(20))
        filename = salt + '-' + filename
        filename_thumb = salt + '-thumb-' + filename

        #uploading normal sized image
        client.upload_fileobj(file, 'contacts-cloud-images', filename)  

        #pull down image again and resize
        img = Image.open(requests.get(image_url, stream=True).raw)
        img.thumbnail((50,50))
        print(img.format, img.size)

        #save it to BytesIO container
        io = BytesIO()
        img.save(io, img.format)

        #upload value of BytesIO container
--->    client.upload_fileobj(io.getvalue(), 'contacts-cloud-images', filename_thumb)

I get the following error from the line with the arrow (---->):

ValueError: Fileobj must implement read

Betsybetta answered 23/7, 2017 at 17:31 Comment(0)
H
6

The error means client.upload_fileobj is expecting a file-like object that implements a read method, but you're passing it the content of the file-like object (io.getvalue()) instead of the file-like object itself (io)

This is a link to the documentation of upload_fileobj

Important non-related note: An important thing to note is you're naming the variable that holds your buffer io. io is also the name of a module of the standard library, and you're overwriting it. That should be an absolute no-no. Despite the local scope of your variable, I recommend you rename it to something meaninful, like file_content or image_content.

Hades answered 23/7, 2017 at 17:44 Comment(4)
It's now saying on S3 that the uploaded file is 0B. I'm not sure what could have happened that caused the file to contain no data in the above code. I did end up uploading the io object instead of using the getvalue() method. (I did rename it as well, thank you for that.)Betsybetta
I'd verify that the line print(img.format, img.size) is printing a non-zero value for size. To clarify, boto3 doesn't upload the file-like object, it uploads the content of the file, but it's built in such a way that you need to pass the file-like object to itHades
I'll also point out that I don't see image_url defined anywhere. However, it's far fetched to think that's the cause of the problem, since requests.get would raise an error if image_url didn't contain a valid url, and Image.open would raise an error if the body of the request didn't contain a valid image.Hades
Thank you, it turns out that I had to call .seek(0) on the file-like object to rewind it to the beginning.Betsybetta

© 2022 - 2024 — McMap. All rights reserved.