62

I'm making a simple API in Flask that accepts an image encoded in base64, then decodes it for further processing using Pillow.

I've looked at some examples (1, 2, 3), and I think I get the gist of the process, but I keep getting an error where Pillow can't read the string I gave it.

Here's what I've got so far:

import cStringIO
from PIL import Image
import base64

data = request.form
image_string = cStringIO.StringIO(base64.b64decode(data['img']))
image = Image.open(image_string)

which gives the error:

IOError: cannot identify image file <cStringIO.StringIO object at 0x10f84c7a0>
5
  • Can you paste in an example of what you're getting in data['img']? Log that out, or print it out. Sep 27, 2014 at 3:57
  • Here's an example: jsfiddle.net/gn0x0wvc. I put it in an img tag to make sure the image data wasn't corrupted. Sep 27, 2014 at 4:21
  • What does the data look like after b64decode()? Is there any other encoding going on, e.g. urlencoding? Is it really an image supported by PIL?
    – mhawke
    Sep 27, 2014 at 5:09
  • Just that fiddle doesn't tell us anything about how you are posting that string to your Flask server. What does print repr(data['img']) produce on your console for example?
    – Martijn Pieters
    Sep 27, 2014 at 12:37
  • @mhawke Here's a screenshot of the output of b64 decode: imgur.com/7ZJNuPf I was trying to follow the example here. @Martijn Pieters here's what print repr(data['img']) looks like: imgur.com/xmrvNmI Sep 27, 2014 at 14:42

3 Answers 3

132

You should try something like:

from PIL import Image
from io import BytesIO
import base64

data['img'] = '''R0lGODlhDwAPAKECAAAAzMzM/////wAAACwAAAAADwAPAAACIISPeQHsrZ5ModrLl
N48CXF8m2iQ3YmmKqVlRtW4MLwWACH+H09wdGltaXplZCBieSBVbGVhZCBTbWFydFNhdmVyIQAAOw==''' 

im = Image.open(BytesIO(base64.b64decode(data['img'])))

Your data['img'] string should not include the HTML tags or the parameters data:image/jpeg;base64 that are in the example JSFiddle.

I've changed the image string for an example I took from Google, just for readability purposes.

0
32

There is a metadata prefix of data:image/jpeg;base64, being included in the img field. Normally this metadata is used in a CSS or HTML data URI when embedding image data into the document or stylesheet. It is there to provide the MIME type and encoding of the embedded data to the rendering browser.

You can strip off the prefix before the base64 decode and this should result in valid image data that PIL can load (see below), but you really need to question how the metadata is being submitted to your server as normally it should not.

import re
import cStringIO
from PIL import Image

image_data = re.sub('^data:image/.+;base64,', '', data['img']).decode('base64')
image = Image.open(cStringIO.StringIO(image_data))
2
  • @LazaroGamio : the main point though is that the prefix should not be present in the data posted to your server. How is it being posted?
    – mhawke
    Sep 28, 2014 at 14:32
  • I'm taking a user - uploaded image and sending it to the API via the jquery post method. I suppose I could strip the prefix off client side instead of removing it on the server. Sep 28, 2014 at 15:46
13

Sorry for necromancy, but none of the answers worked completely for me. Here is code working on Python 3.6 and Flask 0.13.

Server:

from flask import Flask, jsonify, request
from io import BytesIO
from web import app
import base64
import re
import json
from PIL import Image

@app.route('/process_image', methods=['post'])
def process_image():
    image_data = re.sub('^data:image/.+;base64,', '', request.form['data'])
    im = Image.open(BytesIO(base64.b64decode(image_data)))
    return json.dumps({'result': 'success'}), 200, {'ContentType': 'application/json'}

Client JS:

// file comes from file input
var reader = new FileReader();
reader.onloadend = function () {
    var fileName = file.name;
    $.post('/process_image', { data: reader.result, name: fileName });
};
reader.readAsDataURL(file);

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.