I would like to render an image on React returned from FastAPI backend using StreamingResponse
. The image is in the form of a numpy
array, which is of cv2
type of object.
@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")
Here, I have created an API endpoint in which the uploaded image is received using POST
request, and a StreamableResponse(Image)
is returned.
How can I render this returned response on React frontend?
React Code:
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;
I would like to render the returned image in the div
tag which has the id
of image-render
.
Edit - This is the response I get from my backend.
I would like to render an image on React returned from FastAPI backend using StreamingResponse
. The image is in the form of a numpy
array, which is of cv2
type of object.
@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")
Here, I have created an API endpoint in which the uploaded image is received using POST
request, and a StreamableResponse(Image)
is returned.
How can I render this returned response on React frontend?
React Code:
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;
I would like to render the returned image in the div
tag which has the id
of image-render
.
Edit - This is the response I get from my backend.
Share Improve this question edited Sep 30, 2022 at 4:49 Chris 35.6k10 gold badges104 silver badges251 bronze badges asked Mar 1, 2022 at 18:35 Raj ShahRaj Shah 251 silver badge6 bronze badges 1-
2
You can set the src of the img tag to
data:image/png;base64,<base 64 encoded img data>
- either return base64 data directly from your API or convert it in Javascript by handling the response from the server. – MatsLindh Commented Mar 1, 2022 at 21:45
1 Answer
Reset to default 5There are two options:
- encode the image data into Base64 format on server side and
return the base64-encoded string, as shown in this answer and this
answer,
for example:
which can then be used to display the image in an HTML page as shown here, for instance:base64_string= base64.b64encode(image_bytes).decode('utf-8') return base64_string
<img src="data:image/png;base64,ADD_BASE64_STRING_HERE>
- or, send the raw bytes from the server, as you currently do. However, it
might be best not to use a
StreamingResponse
(as shown in the example you provided) for sending the raw bytes, as, in your case, the entire image bytes are already loaded into memory. Thus, you should rather use a customResponse
, as explained in this answer and this answer, for example:
On client side (using JavaScript), convert the raw bytes into either a base64-encoded string (usingreturn Response(image_bytes, media_type='image/jpeg')
btoa()
,String.fromCharCode()
andUint8Array
), or aBlob
object (and then call URL.createObjectURL() to create a URL representing theBlob
object).
The examples below demonstrate how to implement the two methods explained in Option 2 above (i.e., having the server sending raw image bytes and, on client side, converting the image bytes to either a base64-encoded string or Blob
object), using either Fetch API
or Axios
library.
Using Fetch API
Option 1 - Convert raw image bytes into Blob object
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);
});
Option 2 - Convert raw image bytes into base64-encoded string
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);
});
Remember to define an <img>
tag in your HTML file, where you wish to display the image:
<img id="myImage" src="">
Using Axios
Option 1 - Convert raw image bytes into Blob object
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);
});
Option 2 - Convert raw image bytes into base64-encoded string
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);
});
Remember to define an <img>
tag in your HTML file, where you wish to display the image:
<img id="myImage" src="">