How to save an uploaded image to FastAPI using Python Imaging Library (PIL)?

PIL.Image.open() takes as fp argumnet the following:

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

Using a BytesIO stream, you would need to have something like the below (as shown in client side of this answer):

Image.open(io.BytesIO(file.file.read()))

However, you don’t really have to use an in-memory bytes buffer, as you can get the the actual file object using the .file attribute of UploadFile. As per the documentation:

file: A SpooledTemporaryFile (a file-like object).
This is the actual Python file that you can pass directly to other
functions or libraries that expect a “file-like” object.

Example – Saving image to disk:

# ...
from fastapi import HTTPException
from PIL import Image

@app.post("/upload")
def upload(file: UploadFile = File()):
    try:        
        im = Image.open(file.file)
        if im.mode in ("RGBA", "P"): 
            im = im.convert("RGB")
        im.save('out.jpg', 'JPEG', quality=50) 
    except Exception:
        raise HTTPException(status_code=500, detail="Something went wrong")
    finally:
        file.file.close()
        im.close()

Example – Saving image to an in-memory bytes buffer (see this answer):

# ...
from fastapi import HTTPException
from PIL import Image

@app.post("/upload")
def upload(file: UploadFile = File()):
    try:        
        im = Image.open(file.file)
        if im.mode in ("RGBA", "P"): 
            im = im.convert("RGB")
        buf = io.BytesIO()
        im.save(buf, 'JPEG', quality=50)
        # to get the entire bytes of the buffer use:
        contents = buf.getvalue()
        # or, to read from `buf` (which is a file-like object), call this first:
        buf.seek(0)  # to rewind the cursor to the start of the buffer
    except Exception:
        raise HTTPException(status_code=500, detail="Something went wrong")
    finally:
        file.file.close()
        buf.close()
        im.close()

For more details and code examples on how to upload files/images using FastAPI, please have a look at this answer and this answer. Also, please have a look at this answer for more information on defining your endpoint with def or async def.

Leave a Comment