1

I am using Flask to open an image from a URL.

file = cStringIO.StringIO(urllib.urlopen(URL).read())
img = Image.open(file)

I then want to take the image and save it to my site. When I do this, I get

Traceback (most recent call last):
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1836, in __call__
    return self.wsgi_app(environ, start_response)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1820, in wsgi_app
    response = self.make_response(self.handle_exception(e))
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1403, in handle_exception
    reraise(exc_type, exc_value, tb)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1817, in wsgi_app
    response = self.full_dispatch_request()
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1477, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1381, in handle_user_exception
    reraise(exc_type, exc_value, tb)
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1475, in full_dispatch_request
    rv = self.dispatch_request()
  File "/Library/Python/2.7/site-packages/flask/app.py", line 1461, in dispatch_request
    return self.view_functions[rule.endpoint](**req.view_args)
  File "/Users/User/Desktop/Flask/fl.py", line 37, in index
    img.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
  File "/Library/Python/2.7/site-packages/PIL/Image.py", line 1648, in save
    raise KeyError(ext)  # unknown extension
KeyError: ''

Here is the code to save:

filename = secure_filename(img.filename)
img.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))
print url_for('uploaded_file', filename=filename)

@app.route('/uploads/<filename>')
def uploaded_file(filename):
    return send_from_directory(app.config['UPLOAD_FOLDER'], filename)

Why is this happening? How can I fix this?

Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
user3822146
  • 114
  • 3
  • 10

1 Answers1

3

When saving in image from an object without a filename, like a StringIO object, you need to tell PIL what type of image it is:

img.save(os.path.join(app.config['UPLOAD_FOLDER'], filename), format='PNG')

Here I stated that the format is a PNG, but you'll need to introspect the Content-Type header from the response and see what type is from that. Map the content type to the appropriate PIL format, based on the header.

You'll also need to come up with a better filename; img.filename is an empty string as you never gave img.open() a filename. Use the last component of URL instead for example; presumably that'll have a filename:

formats = {
    'image/jpeg': 'JPEG',
    'image/png': 'PNG',
    'image/gif': 'GIF'
}

response = urllib.urlopen(URL)
image_type = response.info().get('Content-Type')
try:
    format = formats[image_type]
except KeyError:
    raise ValueError('Not a supported image format')

file = cStringIO.StringIO(response.read())
img = Image.open(file)

# ...

filename = secure_filename(URL.rpartition('/')[-1])
img.save(os.path.join(app.config['UPLOAD_FOLDER'], filename), format=format)
Martijn Pieters
  • 1,048,767
  • 296
  • 4,058
  • 3,343
  • Awesome. But now I get an error `OError: [Errno 21] Is a directory: "uploads/"`. What does this mean? – user3822146 Jul 27 '14 at 01:46
  • @user3822146: `img.filename` is *empty*, as you never provided a filename. So the `os.path.join(app.config['UPLOAD_FOLDER'], filename)` result ends up being the directory name. I'll update. – Martijn Pieters Jul 27 '14 at 01:48