How to return a numpy array as an image using FastAPI?

Question:

I load an image with img = imageio.imread('hello.jpg').
I want to return this numpy array as an image. I know I can do return FileResponse('hello.jpg'), however, in the future, I will have the pictures as numpy arrays.

How can I return the numpy array img from FastAPI server in a way that it is equivalent to return FileResponse('hello.jpg')?

Asked By: Skyy2010

||

Answers:

You can use StreamingResponse (https://fastapi.tiangolo.com/advanced/custom-response/#using-streamingresponse-with-file-like-objects) to do it e.g., but before you will need to convert your numpy array to the io.BytesIO or io.StringIO

Answered By: dukkee

You shouldn’t be using StreamingResponse, as suggested by some other answer. If the entire image bytes are loaded into memory from the beginning (e.g., into an in-memory bytes buffer), using StreamingResponse makes little sense. Please have a look at this answer for more details. You should instead use Response and pass the image bytes, after converting the numpy array into a BytesIO buffered stream, as described in the documentation of the Imageio library that you are using—if you instead wish to use PIL or Pillow library (the successor of PIL, which added Python 3.x support), see this answer. You can also define the media_type, as well as set the Content-Disposition header, as described here and here, so that the image is viewed in the browser (if you would like to have the image downloaded rather than viewed in the browser, then use attachment insetad of inline, as described in the linked answers above). Example below:

import io
import imageio
from imageio import v3 as iio
from fastapi import Response

@app.get("/image", response_class=Response)
def get_image():
    im = imageio.imread("test.jpeg") # 'im' could be an in-memory image (numpy array) instead
    with io.BytesIO() as buf:
        iio.imwrite(buf, im, plugin="pillow", format="JPEG")
        im_bytes = buf.getvalue()
        
    headers = {'Content-Disposition': 'inline; filename="test.jpeg"'}
    return Response(im_bytes, headers=headers, media_type='image/jpeg')
Answered By: Chris