How can Pillow open uploaded image file from StringIO directly?

8.2k views Asked by At

User upload a image file by the Form, I don't want to save original uploaded image file to disk, and resize image by Pillow opening image from disk.

I want to resize this image file in memory first, then save the resized image file to disk. so I import StringIO as buffer, but it does't work with Pillow.

Here is the code:

Python3.4, Flask==0.10.1, Pillow==3.4.2

forms.py

class Form():
    img = FileField()
    submit = SubmitField()

views.py

from io import StringIO
from PIL import Image
from .forms import Form

@app.route('/upload_img', methods=['GET', 'POST'])
def upload_img():
    form = Form()
    im = Image.open(StringIO(form.img.data.read())

    pass

TypeError: initial_value must be str or None, not bytes

1

There are 1 answers

3
illright On

From Pillow docs:

PIL.Image.open(fp, mode='r')

Opens and identifies the given image file. Parameters:

fp – A filename (string), pathlib.Path object or a file object. The file object must implement read(), seek(), and tell() methods, and be opened in binary mode.

What you're passing to open is a StringIO. It creates a file-like object from an str object that is opened in text mode.
The issue is caused by the argument in StringIO. form.img.data.read() returns a bytes object, passing it into the constructor is forbidden. But in your case, a StringIO won't work.
Instead, use io.BytesIO. It has pretty much the same interface, except that it takes bytes objects and returns a file-like object opened in binary mode, which is what you need.

from io import BytesIO
from PIL import Image
from .forms import Form

@app.route('/upload_img', methods=['GET', 'POST'])
def upload_img():
    form = Form()
    im = Image.open(BytesIO(form.img.data.read())

    pass