본문 바로가기

개발하자

빠른 API에서 이미지를 반환하려면 어떻게 해야 합니까?

반응형

빠른 API에서 이미지를 반환하려면 어떻게 해야 합니까?

파이썬 모듈을 사용하여 이미지를 반환하는 방법을 찾을 수 없습니다. 플라스크에서 나는 다음과 같은 것을 할 것이다:

@app.route("/vector_image", methods=["POST"])
def image_endpoint():
    # img = ... # Create the image here
    return Response(img, mimetype="image/png")

이 모듈에서 해당 통화는 무엇입니까?




아직 제대로 문서화되지 않았지만, 스탈렛의 어떤 것이든 사용할 수 있습니다.

경로가 있는 Disk의 파일인 경우 를 사용할 수 있습니다.

에서 생성된 파일과 같은 개체인 경우, Starlette의 다음 안정적인 릴리스(FastAPI에서 내부적으로 사용)에서 이 개체를 반환할 수도 있습니다.




@Sebastian Ramírez에서 온 사람이 올바른 방향으로 나를 가리켰지만, 문제를 해결하려는 사람들을 위해, 나는 그것이 작동하기 위해 몇 줄의 코드가 필요했다. starlette(fastAPI가 아닌)에서 가져오고, CORS 지원을 추가하고, 임시 파일에서 반환해야 했습니다. 더 좋은 방법이 있을지도 모르지만, 나는 직장으로 스트리밍을 할 수 없었다.

from starlette.responses import FileResponse
from starlette.middleware.cors import CORSMiddleware
import tempfile

app = FastAPI()
app.add_middleware(
    CORSMiddleware, allow_origins=["*"], allow_methods=["*"], allow_headers=["*"]
)

@app.post("/vector_image")
def image_endpoint(*, vector):
    # Returns a raw PNG from the document vector (define here)
    img = my_function(vector)

    with tempfile.NamedTemporaryFile(mode="w+b", suffix=".png", delete=False) as FOUT:
        FOUT.write(img)
        return FileResponse(FOUT.name, media_type="image/png")



나도 비슷한 문제가 있었지만 cv2 이미지가 있어. 이것은 다른 사람들에게 유용할 수 있다. 를 사용합니다.

import io
from starlette.responses import StreamingResponse

app = FastAPI()

@app.post("/vector_image")
def image_endpoint(*, vector):
    # Returns a cv2 image array from the document vector
    cv2img = my_function(vector)
    res, im_png = cv2.imencode(".png", cv2img)
    return StreamingResponse(io.BytesIO(im_png.tobytes()), media_type="image/png")



@biophetik의 대답 덕분에, 나를 혼란스럽게 했던 중요한 상기와 함께:

@app.get("/generate")
def generate(data: str):
  img = generate_image(data)
  print('img=%s' % (img.shape,))
  buf = BytesIO()
  imsave(buf, img, format='JPEG', quality=100)
  buf.seek(0) # important here!
  return StreamingResponse(buf, media_type="image/jpeg",
    headers={'Content-Disposition': 'inline; filename="%s.jpg"' %(data,)})



다른 모든 대답은 정확하지만 이제 이미지를 반환하는 것은 매우 쉽습니다.

from fastapi.responses import FileResponse

@app.get("/")
async def main():
    return FileResponse("your_image.jpeg")



당신은 Fast에서 매우 비슷한 것을 할 수 있다.API

from fastapi import FastAPI, Response

app = FastAPI()

@app.post("/vector_image/")
async def image_endpoint():
    # img = ... # Create the image here
    return Response(content=img, media_type="image/png")



이미지의 바이트가 이미 메모리에 있는 경우

사용자 지정 및 을(를) 반환

또한 Fast를 얻으려면 엔드포인트 장식자를 사용해야 합니다.Open에 올바른 미디어 유형을 입력하기 위한 APIAPI 사양입니다.

@app.get(
    "/image",

    # Set what the media type will be in the autogenerated OpenAPI specification.
    # fastapi.tiangolo.com/advanced/additional-responses/#additional-media-types-for-the-main-response
    responses = {
        200: {
            "content": {"image/png": {}}
        }
    }

    # Prevent FastAPI from adding "application/json" as an additional
    # response media type in the autogenerated OpenAPI specification.
    # https://github.com/tiangolo/fastapi/issues/3258
    response_class=Response,
)
def get_image()
    image_bytes: bytes = generate_cat_picture()
    # media_type here sets the media type of the actual response sent to the client.
    return Response(content=image_bytes, media_type="image/png")

을 참조하십시오.

이미지가 파일 시스템에만 있는 경우

a를 반환합니다.

을 참조하십시오.


에 주의하세요

다른 답변에서는 .가 더 정확하게 사용하기 어렵기 때문에 또는 을 사용할 수 없는 것이 확실한 경우가 아니면 권장하지 않습니다.

특히 이런 코드는 의미가 없다. 유용한 방법으로 이미지를 "스트리밍"하지 않습니다.

@app.get("/image")
def get_image()
    image_bytes: bytes = generate_cat_picture()
    # ❌ Don't do this.
    image_stream = io.BytesIO(image_bytes)
    return StreamingResponse(content=image_stream, media_type="image/png")

먼저, 에서 제공하는 청크를 반복하여 스트림을 생성하지만, 이진 이미지에 대해 의미가 없는 ,일 경우.

그리고 청크 분할이 의미가 있다고 해도, 청크는 처음부터 전체 개체를 사용할 수 있었기 때문에 의미가 없습니다. 우리는 처음부터 모든 것을 그냥 a로 넘겨버린 것이 나을 수도 있다. 우리는 FastAPI로부터 데이터를 보류함으로써 아무것도 얻지 못한다.

둘째, 에 해당합니다. (ASGI 서버에 따라 다를 수 있지만 적어도 에 해당됩니다.) 그리고 이것은 청크 전송 인코딩에 대한 좋은 사용 사례가 아니다.

청크 전송 인코딩은 출력의 크기를 미리 알 수 없고 클라이언트로 전송하기 전에 모든 출력을 수집할 때까지 기다리지 않을 때 유용합니다. 이는 느린 데이터베이스 쿼리의 결과를 제공하는 것과 같은 것에 적용될 수 있지만 일반적으로 이미지를 제공하는 것에는 적용되지 않습니다.

불필요한 청크 전송 인코딩은 해로울 수 있습니다. 예를 들어, 클라이언트가 파일을 다운로드할 때 진행률 표시줄을 표시할 수 없습니다. 참조:




디스크에 파일이 있는 경우 a를 사용할 수 있습니다.

import os

from fastapi import FastAPI 
from fastapi.responses import FileResponse

app = FastAPI()

path = "/path/to/files"

@app.get("/")
def index():
    return {"Hello": "World"}

@app.get("/vector_image", responses={200: {"description": "A picture of a vector image.", "content" : {"image/jpeg" : {"example" : "No example available. Just imagine a picture of a vector image."}}}})
def image_endpoint():
    file_path = os.path.join(path, "files/vector_image.jpg")
    if os.path.exists(file_path):
        return FileResponse(file_path, media_type="image/jpeg", filename="vector_image_for_you.jpg")
    return {"error" : "File not found!"}



내 이미지가 PIL로 구축되었기 때문에 위의 요구 사항이 충족되지 않았습니다. 내 fastapi 끝점은 이미지 파일 이름을 가져와서 PIL 이미지로 읽고 다음과 같이 HTML에서 사용할 수 있는 메모리에 썸네일 jpeg를 생성합니다.

<img src="http://localhost:8000/images/thumbnail/bigimage.jpg">

import io
from PIL import Image
from fastapi.responses import StreamingResponse
@app.get('/images/thumbnail/{filename}',
  response_description="Returns a thumbnail image from a larger image",
  response_class="StreamingResponse",
  responses= {200: {"description": "an image", "content": {"image/jpeg": {}}}})
def thumbnail_image (filename: str):
  # read the high-res image file
  image = Image.open(filename)
  # create a thumbnail image
  image.thumbnail((100, 100))
  imgio = io.BytesIO()
  image.save(imgio, 'JPEG')
  imgio.seek(0)
  return StreamingResponse(content=imgio, media_type="image/jpeg")



상위 답변을 따를 때 바이트를 반환하려고 하는 경우당신의 IO 객체는 다음과 같습니다.

    buffer = BytesIO(my_data)

    # Return file
    return Response(content=buffer, media_type="image/jpg")

다음과 같은 오류가 발생할 수 있습니다(설명 참조).

AttributeError: '_io.BytesIO' object has no attribute 'encode'

이는 형식을 명시적으로 확인하는 함수에 의해 발생합니다. 값을 인코딩하려고 시도했다가 실패하기 때문에 실패합니다.

해결책은 바이트에서 바이트 값을 가져오는 것입니다.IO 개체 사용

    buffer = BytesIO(my_data)

    # Return file
    return Response(content=buffer.getvalue(), media_type="image/jpg")

반응형