如何在 React 上渲染来自 FastAPI 服务器的 Streamable 图像?

Raj*_*hah 1 javascript python image reactjs fastapi

我想使用从 FastAPI 后端返回的 React 来渲染图像StreamingResponse。图像是数组的形式numpy,是cv2对象类型。

@app.post("/predict")
async def root(file: UploadFile = File(...)):
    global model
    global store_coordinates
    global store_faces
    global store_mesh

    content = await file.read()
    nparr = np.fromstring(content, np.uint8)
    bg_img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
    ......................
    for i in range(len(store_coordinates)):
            x, y, w, h = store_coordinates[i]
            bg_img [b:b + d, a:a + c] = store_mesh[i]
    
    res,im_png = cv2.imencode(".png", bg_img)
    return StreamingResponse(io.BytesIO(im_png.tobytes()), media_type="image/png")
Run Code Online (Sandbox Code Playgroud)

在这里,我创建了一个 API 端点,其中使用POST请求接收上传的图像,并StreamableResponse(Image)返回 a。如何在 React 前端渲染这个返回的响应?

反应代码:

import React, { Component } from "react";
import axios from "axios";

class Detect extends Component {
  state = {
    title: "",
    content: "",
    image: null,
  };

  handleChange = (e) => {
    this.setState({
      [e.target.id]: e.target.value,
    });
  };

  handleImageChange = (e) => {
    this.setState({
      image: e.target.files[0],
    });
  };

  
  handleSubmit = (e) => {
    e.preventDefault();
    console.log(this.state);
    let form_data = new FormData();
    form_data.append("image", this.state.image, this.state.image.name);
    let url = "http://127.0.0.1:8000/predict";
    axios
      .post(url, form_data, {
        headers: {
          "content-type": "multipart/form-data",
        },
      })
      .then((res) => {
        console.log(res.data);
      })
      .catch((err) => console.log(err));
  };

  render() {
    return (
      <div className="App">
        <form onSubmit={this.handleSubmit}>
          <p>
            <input
              type="file"
              id="image"
              accept="image/png, image/jpeg"
              onChange={this.handleImageChange}
              required
            />
          </p>
          <input type="submit" />
        </form>
        <div id="image-render">
          <img></img>
        </div>
      </div>
    );
  }
}

export default Detect;
Run Code Online (Sandbox Code Playgroud)

我想在div具有idof的标签中渲染返回的图像image-render

编辑-这是我从后端得到的响应。

在此输入图像描述

Chr*_*ris 5

有两种选择:

  1. 在服务器端将图像数据编码为Base64格式并返回base64编码的字符串,如这个答案这个答案所示,例如:
    base64_string= base64.b64encode(image_bytes).decode('utf-8')
    return base64_string
    
    Run Code Online (Sandbox Code Playgroud) 然后可用于在 HTML 页面中显示图像,如下所示 例如:
    <img src="data:image/png;base64,ADD_BASE64_STRING_HERE>
    
    Run Code Online (Sandbox Code Playgroud)
  2. 或者,像您当前所做的那样,从服务器发送原始字节。但是,最好不要使用 a StreamingResponse(如您提供的示例所示)发送原始字节,因为在您的情况下,整个图像字节已经加载到内存中。因此,您应该使用自定义Response,如本答案本答案中所述,例如:
    return Response(image_bytes, media_type='image/jpeg')
    
    Run Code Online (Sandbox Code Playgroud) 在客户端(使用 JavaScript),将原始字节转换为 Base64 编码的字符串(使用btoa()String.fromCharCode()Uint8Array)或Blob对象(然后调用 URL.createObjectURL()以创建表示该Blob 对象的 URL)。

下面的示例演示了如何使用或库来实现上面选项 2 中解释的两种方法(即让服务器发送原始图像字节,并在客户端将图像字节转换为 Base64 编码的字符串或Blob对象)。Fetch APIAxios

使用获取 API

选项 1 - 将原始图像字节转换为 Blob 对象

fetch('/predict', {
        method: 'POST',
        body: formData,
    })
    .then(response => response.blob())
    .then(blob => {
        var blobURL = URL.createObjectURL(blob);
        var image = document.getElementById("myImage");
        image.onload = function(){
            URL.revokeObjectURL(this.src); // release the blob URL once the image is loaded
        }
        image.src = blobURL;
    })
    .catch(error => {
        console.error(error);
    });
Run Code Online (Sandbox Code Playgroud)

选项 2 - 将原始图像字节转换为 Base64 编码的字符串

fetch('/predict', {
        method: 'POST',
        body: formData,
    })
    .then(response => {
        contentType = response.headers.get('content-type')
        return response.arrayBuffer();
    })
    .then(arrayBuffer => {
        base64string = btoa(String.fromCharCode(...new Uint8Array(arrayBuffer)))
        var image = document.getElementById("myImage");
        image.src = "data:" + contentType + ";base64," + base64string;
    })
    .catch(error => {
        console.error(error);
    });
Run Code Online (Sandbox Code Playgroud)

请记住<img>在您希望显示图像的 HTML 文件中定义一个标签:

<img id="myImage" src="">
Run Code Online (Sandbox Code Playgroud)

使用 Axios

选项 1 - 将原始图像字节转换为 Blob 对象

axios({
        method: 'POST',
        url: '/upload',
        data: formData,
        headers: {
            'Content-Type': 'multipart/form-data'
        },
        responseType: "blob"
    })
    .then(response => {
        var blobURL = URL.createObjectURL(response.data);
        var image = document.getElementById("myImage");
        image.onload = function(){
            URL.revokeObjectURL(this.src); // release the blob URL once the image is loaded
        }
        image.src = blobURL;
    })
    .catch(error => {
        console.error(error);
    });
Run Code Online (Sandbox Code Playgroud)

选项 2 - 将原始图像字节转换为 Base64 编码的字符串

axios({
        method: 'POST',
        url: '/predict',
        data: formData,
        headers: {
            'Content-Type': 'multipart/form-data'
        },
        responseType: "arraybuffer"
    })
    .then(response => {
        base64string = btoa(String.fromCharCode(...new Uint8Array(response.data)))
        contentType = response.headers['content-type']
        return base64string;
    })
    .then(base64string => {
        var image = document.getElementById("myImage");
        image.src = "data:" + contentType + ";base64," + base64string;
    })
    .catch(error => {
        console.error(error);
    });
Run Code Online (Sandbox Code Playgroud)

请记住<img>在您希望显示图像的 HTML 文件中定义一个标签:

<img id="myImage" src="">
Run Code Online (Sandbox Code Playgroud)