빠른 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")