I am trying to build an app to allow user to take picture with their camera. I think in Dash we don’t have the tool so I used client callback with JavaScript codes. The JS codes run well in normal HTML+JS, but not in Dash.
My Dash Codes:
from dash import Dash, html, dcc, Input, Output
app = Dash(name=__name__)
app.layout = html.Div([
html.H1("test of pictures"),
html.Div([
html.Div([
html.Button("start", id="buttonStart"),
html.Video(id="video", style={"width":"500px", "height":"500px", "autoplay":"autoplay", "border":"1px solid red"})
], style={"display":"block"}),
html.Div([
html.Button("take photo", id="buttonPhoto"),
html.Canvas(id="canvas", style={"width":"500px", "height":"500px", "border":"1px solid green"})
], style={"display":"block"}),
html.Div([
html.Button("Stop", id="buttonStop"),
html.Img(id="img", style={"width":"500px", "height":"500px", "autoplay":"autoplay", "border":"1px solid blue"})
], style={"display":"block"}),
], style={"display":"flex"})
])
app.clientside_callback(
'''
function startVideo(){
var srcVideo = document.getElementById("video");
var constraints = {
video:{
width:500,
height:500
},
audio:false,
};
var mediaPromise = navigator.mediaDevices.getUserMedia(constraints);
mediaPromise.then((stream)=>{
srcVideo.srcObject = stream;
srcVideo.play();
}).catch((err)=>{console.log(err);})
}
''',
Output("video", "children"),
Input("buttonStart", "n_clicks"),
prevent_initial_call = True,
)
app.clientside_callback(
'''
function takePhoto(){
var srcVideo = document.getElementById("video");
var tempCanvas = document.getElementById("canvas");
var targImg = document.getElementById("img");
var ctx = tempCanvas.getContext('2d');
ctx.drawImage(srcVideo, 0, 0);
var img =tempCanvas.toDataURL('image/jpeg');
targImg.src = img;
}
''',
Output("canvas", "children"),
Input("buttonPhoto", "n_clicks"),
prevent_initial_call = True,
)
app.clientside_callback(
'''
function stopVideo(){
var srcVideo = document.getElementById("video");
var stream = srcVideo.srcObject;
var tracks = stream.getTracks();
tracks.forEach((track) => {
track.stop();
});
stream = null;
}
''',
Output("img", "children"),
Input("buttonStop", "n_clicks"),
prevent_initial_call = True,
)
if __name__ == "__main__":
app.run_server(debug=True)
The problem is after click button “take photo”, only a small section of video (left-top corner) was taken as the picture displayed, while the same JS codes run well in following HTML file:
<!DOCTYPE html>
<html lang="en">
<head>
<title>photo test</title>
<meta charset="utf-8">
</head>
<body>
<div>
<button onclick="startVideo()">start</button>
<button onclick="takePhoto()">photo</button>
<button onclick="stopVideo()">stop</button>
</div>
<div>
<video id="videoTest" width="200px" height="200px" autoplay="autoplay"></video>
<canvas id="canvasTest" width="200px" height="200px"></canvas>
<img id="imgTest" width="200px" height="200px">
</div>
<script>
function startVideo(){
var srcVideo = document.getElementById("videoTest");
var constraints = {
video:{
width:200,
height:200
},
audio:false,
};
var mediaPromise = navigator.mediaDevices.getUserMedia(constraints);
mediaPromise.then((stream)=>{
srcVideo.srcObject = stream;
srcVideo.play();
}).catch((err)=>{console.log(err);})
}
function stopVideo(){
var srcVideo = document.getElementById("videoTest");
var stream = srcVideo.srcObject;
var tracks = stream.getTracks();
tracks.forEach((track) => {
track.stop();
});
stream = null;
}
function takePhoto(){
var srcVideo = document.getElementById("videoTest");
var tempCanvas = document.getElementById("canvasTest");
var targImg = document.getElementById("imgTest");
var ctx = tempCanvas.getContext('2d');
ctx.drawImage(srcVideo, 0, 0);
var img =tempCanvas.toDataURL('image/jpeg');
targImg.src = img;
}
</script>
</body>
So I got quite confused and don’t know what is the problem in my Dash codes. If someone got any idea about it please kindly help me. Thanks very much.