pythonpython-imaging-libraryflask-wtformsflask-uploads

Missing bytes after making copy of PIL image from Flask-Uploads data


I have a Flask app where I'm trying to perform some PIL/Pillow operations on a file that is received from Flask-WTF -> Flask-Uploads, but when I save the file I'm missing bytes and the image isn't valid.

It seems even making a copy of the image with no additional PIL operations results in corrupting the original upload:

@sights_blueprint.route('/add', methods=['GET', 'POST'])
def add_image():
form = AddImageForm()
if request.method == 'POST':
    if form.validate_on_submit():

        # uploaded file
        f = form.sights_image.data
        filename = secure_filename(f.filename)

        # PIL open + copy
        img = Image.open(f).copy()

        # save original file
        f.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))

Results in:

original_file: 4622336 bytes
saved_file:     886784 bytes

If I remove img = Image.open(f).copy() the uploaded file is saved correctly.

If I only open the image with PIL:

    # PIL open (no copy)
    img = Image.open(f)

The file will also save correctly.

But if I perform any operation, copy or otherwise, the resulting saved file is missing bytes and an invalid image.

How can I achieve this desired workflow?


Solution

  • When operating against the file opened with PIL Image.open(f), the file pointer is advanced but not reset before writing the file. I would think that in the case of copy() the file pointer would reach the end of the file and no bytes would be written, but it doesn't seem so based on my previous partial writes. In any case, the solution is to rewind the file pointer to the start of the file before saving. In my use case it was also not necessary to open a copy.

    img = Image.open(f)
    # do some stuff to img
    f.seek(0)
    f.save(os.path.join(app.config['UPLOAD_FOLDER'], filename))