Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Uploading PIL image object to Amazon s3 python

I want to get an image from the web and upload it to Amazon s3. While doing so, I would like to check the image dimensions. I have the following code in Python 3:

from PIL import Image
import requests

# Get response
response = requests.get(url, stream= True)

# Open image
im = Image.open(response.raw)

# Get size
size = im.size

# Upload image to s3
S3.Client.upload_fileobj(
    im, # This is what i am trying to upload
    AWS_BUCKET_NAME,
    key,
    ExtraArgs={
        'ACL': 'public-read'
    }
)

The problem is that the PIL image object does not support read. I get the following error when i try to upload the PIL Image object im.

ValueError: Fileobj must implement read

It works when I just try to upload the 'response.raw', but I need to get the image dimensions. How can I change the PIL image object to a file-like-object? Is there an easier way to get the dimensions while still being able to upload the image to s3?

So the question is; how do I upload an image to s3 after getting the dimensions of an image?

like image 299
john Avatar asked Sep 13 '17 18:09

john


People also ask

How do I import an image into Python using PIL?

To load the image, we simply import the image module from the pillow and call the Image. open(), passing the image filename. Instead of calling the Pillow module, we will call the PIL module as to make it backward compatible with an older module called Python Imaging Library (PIL).

How do I upload images to Amazon s3?

jpg . Sign in to the AWS Management Console and open the Amazon S3 console at https://console.aws.amazon.com/s3/ . In the Buckets list, choose the name of the bucket that you want to upload your folders or files to. Choose Upload.


2 Answers

You need to use a file-like object but you should not call getValue() contrary to the accepted answer. Using the following snippet, you can then upload the image to S3 using in_mem_file when calling upload_fileobj:

from PIL import Image
import io

# Open image
pil_image = Image.open(response.raw)

# Save the image to an in-memory file
in_mem_file = io.BytesIO()
pil_image.save(in_mem_file, format=pil_image.format)
in_mem_file.seek(0)

# Upload image to s3
client_s3.upload_fileobj(
    in_mem_file, # This is what i am trying to upload
    AWS_BUCKET_NAME,
    key,
    ExtraArgs={
        'ACL': 'public-read'
    }
)

The .seek(0) part is needed to rewind the file-like object if you see that the uploaded file is 0kB.

like image 91
nbeuchat Avatar answered Sep 18 '22 06:09

nbeuchat


Instead of calling read() to get the file contents back, you 'save' the file to either a real file object or an file like object in memory. Then call getValue() on it.

Here is an example function you could pass file content into, print out the height and width, then return the file data back in a format that an AWS clients put_object function will accept as the Body parameter.

from PIL import Image
import io

def modify_image(image, format):
    pil_image = Image.open(image)

    # Prints out (1280, 960) 
    print(pil_image.size)

    in_mem_file = io.BytesIO()

    # format here would be something like "JPEG". See below link for more info.
    pil_image.save(in_mem_file, format=format)
    return in_mem_file.getvalue()

There are also separate width and height attributes here: http://pillow.readthedocs.io/en/3.4.x/reference/Image.html#attributes

See more about the file formats here http://pillow.readthedocs.io/en/3.4.x/handbook/image-file-formats.html

Note: Example uses Python 3.6.1

like image 22
sails44 Avatar answered Sep 20 '22 06:09

sails44