2

I am trying to use requests.get() to open/get a file for image processing but my code falls over when I try to do an Image.open() with the file I have just got.

My code is:

conn = S3Connection(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
bucket = conn.get_bucket(settings.AWS_STORAGE_BUCKET_NAME)

for key in bucket.list(prefix='media/userphotos'):
    file_name=key.name
    full_path_filename = 'https://' + settings.AWS_STORAGE_BUCKET_NAME + '.s3.amazonaws.com/' + file_name
    fd_img = requests.get(full_path_filename);
    img = Image.open(fd_img)
    img = resizeimage.resize_width(img, 800)
    new_filename = file_name
    new_filename.replace('userphotos', 'webversion')
    full_path_filename =  'https://' + settings.AWS_STORAGE_BUCKET_NAME + '.s3.amazonaws.com/' + new_filename
    img.save(full_path_filename, img.format)
    fd_img.close()

The traceback is: 

Traceback:

File "/Users/billnoble/Documents/YHistory-Server/yhistoryvenv/lib/python3.4/site-packages/PIL/Image.py" in open
  2275.         fp.seek(0)

During handling of the above exception ('Response' object has no attribute 'seek'), another exception occurred:

File "/Users/billnoble/Documents/YHistory-Server/yhistoryvenv/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response
  149.                     response = self.process_exception_by_middleware(e, request)

File "/Users/billnoble/Documents/YHistory-Server/yhistoryvenv/lib/python3.4/site-packages/django/core/handlers/base.py" in get_response
  147.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)

File "/Users/billnoble/Documents/YHistory-Server/items/views.py" in xformpics
  67.         img = Image.open(fd_img)

File "/Users/billnoble/Documents/YHistory-Server/yhistoryvenv/lib/python3.4/site-packages/PIL/Image.py" in open
  2277.         fp = io.BytesIO(fp.read())

Exception Type: AttributeError at /xformpics
Exception Value: 'Response' object has no attribute 'read'

It all works fine up to the Image.open().

I have spent many hours googling this issue but cannot find a solution.

Bill Noble
  • 6,466
  • 19
  • 74
  • 133
  • I have added traceback – Bill Noble Nov 29 '16 at 21:12
  • It is needed for image processing so I would imagine binary rather than string? – Bill Noble Nov 29 '16 at 21:20
  • The code I have was lifted from an example that used open() rather than requests.get(). With open() (for a local file) the code works. I am trying to get the same result as an open() with a url file rather than a local file. Hence the use of requests.get(). Clearly I need to do something else but I can't figure out what. – Bill Noble Nov 29 '16 at 21:26
  • Yes, I have spent the last 3 hours googling this but without success. Hence posting here. – Bill Noble Nov 29 '16 at 21:29
  • You should mention what you've tried so we don't give you the same answers over and over again... – MooingRawr Nov 29 '16 at 21:31
  • I have tried using open() to open the file but that is all. I have not been able to find a solution on the net. Hence the reason for posting here. – Bill Noble Nov 29 '16 at 21:32
  • http://stackoverflow.com/questions/7391945/how-do-i-read-image-data-from-a-url-in-python – MooingRawr Nov 29 '16 at 21:35

2 Answers2

1

After much googling and experimenting I have found a good solution. The following code also ensures the image is properly rotated.

def xformpics(self):
    conn = S3Connection(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY)
    bucket = conn.get_bucket(settings.AWS_STORAGE_BUCKET_NAME)

    for key in bucket.list(prefix='media/userphotos'):

        # Get the image to be resized from the S3 bucket
        file_name=key.name
        full_path_filename = 'https://' + settings.AWS_STORAGE_BUCKET_NAME + '.s3.amazonaws.com/' + file_name
        fd_img = urlopen(full_path_filename);
        img = Image.open(fd_img)

        # Check EXIF data to see if image needs to be rotated
        img = image_transpose_exif(img)

        # Resize the image to a width of 800 (for viewing on a web page)
        img = resizeimage.resize_width(img, 800)

        # Upload the resized image to the S3 bucket
        new_filename = full_path_filename.replace('userphotos', 'webversion')
        img.save('temp.jpg', img.format)
        with open('temp.jpg', 'rb') as data:
            r = requests.put(new_filename, data, auth=S3Auth(settings.AWS_ACCESS_KEY_ID, settings.AWS_SECRET_ACCESS_KEY))

        fd_img.close()

def image_transpose_exif(im):
    exif_orientation_tag = 0x0112  # contains an integer, 1 through 8
    exif_transpose_sequences = [  # corresponding to the following
        [],
        [Image.FLIP_LEFT_RIGHT],
        [Image.ROTATE_180],
        [Image.FLIP_TOP_BOTTOM],
        [Image.FLIP_LEFT_RIGHT, Image.ROTATE_90],
        [Image.ROTATE_270],
        [Image.FLIP_TOP_BOTTOM, Image.ROTATE_90],
        [Image.ROTATE_90],
    ]

    try:
        seq = exif_transpose_sequences[im._getexif()[exif_orientation_tag] - 1]
    except Exception:
        return im
    else:
        return functools.reduce(lambda im, op: im.transpose(op), seq, im)
Bill Noble
  • 6,466
  • 19
  • 74
  • 133
0

Image.open() requires a file (or file-like) object, which the result of requests.get() is not.

You probably want to slurp the image content into a buffer:

image_data = requests.get(full_path_filename).text

And then use Image.fromstring() or Image.frombuffer() to use the buffer, rather than a file, to create an image.

John Gordon
  • 29,573
  • 7
  • 33
  • 58
  • Yes that seems to be the case. How can I get a file object with something like requests.get(). I would use open() but that only works on local files and my file is on the internet. – Bill Noble Nov 29 '16 at 21:28
  • I tried your suggestion: fd_img = requests.get(full_path_filename).text; img = Image.fromstring(fd_img)) But Image.fromstring() falls over – Bill Noble Nov 29 '16 at 21:50
  • I believe both `fromstring()` and `frombuffer()` require extra arguments. You'd have to read the documentation to find out how to use them correctly. – John Gordon Nov 29 '16 at 22:01