I'm trying to get image from phone camera to canvas to save it later.
My problem is when i use iPhone 13 Pro then the image on canvas is brighter than it should be.
This happens only when i draw image on iPhone 13 Pro, other ios and android phones do not have this problem.
This is how i pass video stream to canvas
let video = document.createElement('video');
let canvas = document.getElementById('canvas');
let ctx = container.getContext('2d');
navigator.mediaDevices.getUserMedia({
audio: false,
video: {
width: 1920,
height: 1020,
facingMode: 'environment'
}}).then(stream => {
window.stream = stream;
video.srcObject = stream;
const track = stream.getVideoTracks()[0];
video.setAttribute('playsinline', 'true');
video.play();
requestAnimationFrame(() => {
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
});
})
The image in <video> element stays at normal brightness (iPhone 13 pro)
Image from iphone 13 pro
Image from android phone
It was problem with width: 1920, height: 1020, params in getUserMedia. I deleted it and it works fine now.
Related
Is there a way to specify/modify video resolution/canvas size in html5/Javascript?
Tried to set video.videoHeight and video.videoWidth, but these seem to be not modifiable.
This sets up the video camera window:
$("#videoControl").show();
video = document.createElement("video");
canvasElement = $("#qrCanvas")[0];
canvas = canvasElement.getContext("2d");
window.navigator.mediaDevices.getUserMedia({ video: { facingMode: "environment" } }).then(function (stream) {
video.srcObject = stream;
video.setAttribute("playsinline", true); // required to tell iOS safari we don't want fullscreenvideo.play();
requestAnimationFrame(tick);
}
I added:
video.setAttribute("width",'320');
video.setAttribute("height",'240');
Got: "640 x 480" via:
window.alert(venter code hereideo.videoWidth + " x " + video.videoHeight);
grep did not find in the programs 640 x 480 nor are there other references to object video.
I have Webcam class, that uses for capturing data from webcam. This class streames data to video tag and also draw it on canvas., Also I have QRScanner class, that uses for parsing QR code from imageData of canvas.
class Webcam {
constructor(videoTag, canvasTag) {
// using for real-time video capture
this.videoTag = videoTag;
// qr scanner parses imageData from this element
this.canvasTag = canvasTag;
// waiting for qr code here
this.captureArea = {
x: 100,
y: 60,
width: 120,
height: 120
}
// getting access to webcam
navigator.mediaDevices
.getUserMedia({
video: true
})
.then(stream => this.videoTag.srcObject = stream)
.catch(console.log);
}
capture() {
setInterval(() => {
let ctx = this.canvasTag.getContext('2d');
ctx.drawImage(this.videoTag, 0, 0, 320, 240);
// drawing capture area
ctx.strokeStyle = 'red';
// this arguments also should be passed into qr scanner
ctx.strokeRect(
this.captureArea.x,
this.captureArea.y,
this.captureArea.width,
this.captureArea.height
);
}, 100);
}
}
class QRScanner {
constructor(canvas, router, captureArea) {
this.canvas = canvas;
this.router = router;
this.captureArea = captureArea;
this.qrCode = null;
}
scan() {
setInterval(() => {
let imageData = this.canvas
.getContext('2d')
.getImageData(
this.captureArea.x,
this.captureArea.y,
this.captureArea.width,
this.captureArea.height
).data;
// parsing qr code from canvas
this.qrCode = jsQR(imageData, this.captureArea.width, this.captureArea.height);
if (this.qrCode) {
router.redirect(Router.pages.result, this.qrCode);
let resultPage = document.querySelector('#result .qr-code-data');
resultPage.innerHTML = this.qrCode.data;
}
}, 100);
}
}
<div id="scan">
<video id="video" width="320" height="240" autoplay title="Real-time video stream from webcam"></video>
<canvas id="preview" width="320" height="240" title="Capture area for QR code"></canvas>
</div>
This works as expected, but when I removes canvas element from page and trying to use temporary canvas (using document.createElement('canvas') without appending to the page) - this solution do not work. Does it possible to using temporary canvas for getting video imageData without appending this canvas to the page?
P.S. I'm using https://github.com/cozmo/jsQR
Canvas elements have a default width height when they aren't explicitly set. Since you never set those for you created canvas it is going to default to 300 x 150, at least for Chrome might be different for other browsers implementations.
var canvas = document.createElement("canvas");
console.log(canvas.width,canvas.height)
And since this default size is different than the size that you are trying to draw the image/video to there is going to be some cropping going on and therefore effecting your QR library from properly reading the image.
Just set the width and height to what you need
var canvas = document.createElement('canvas')
canvas.width = 320;
canvas.height = 240;
Using the following code:
function captureScreen(size) {
navigator.webkitGetUserMedia({
audio: false,
video: {
mandatory: {
chromeMediaSource: 'desktop',
minWidth: size.width,
maxWidth: size.width,
minHeight: size.height,
maxHeight: size.height,
minFrameRate: 1,
maxFrameRate: 1
}
}
}, gotStream, getUserMediaError);
function gotStream(stream) {
var video = document.createElement('video');
video.addEventListener('loadedmetadata',function(){
var canvas = document.createElement('canvas');
canvas.width = this.videoWidth;
canvas.height = this.videoHeight;
var context = canvas.getContext("2d");
context.drawImage(this, 0, 0);
},false);
video.src = URL.createObjectURL(stream);
}
function getUserMediaError(e) {
console.log('getUserMediaError: ' + JSON.stringify(e, null, '---'));
}
}
Gives me the following result:
Notice how the right side of the image is slightly wrapped to the left side? For some reason, this happens on my laptop (1366x768), a friend's laptop (1366x768), but not my desktop (3840x1080 dual screen). the size parameter passed to the function is always the correct and actual size of the entire desktop area. Even when I hardcode the min and max width / height, I get the same result. Is there any way to fix this? Am I doing something wrong?
I'm building an Electron app which needs to take a screenshot of the user's desktop. There's also nothing else on the web page, and I am using a reset CSS.
Context
I'm trying to capture a snapshot through the client's video camera and save it as an image. I have a JSFiddle demo.
Problem
I'm not succeeding in getting the whole video area from the Video element to the Canvas with Context2D's drawImage. Althought the Video is 400 by 300
<video width="400" height="300" ...
and the canvas is the same 400 by 300
<canvas width="400" height="300" ...
and when I draw I specify for both source and target 400 by 300...
ctx.drawImage(video, 0, 0, 400, 300, 0, 0, 400, 300);
This is a sample of what is happening on my client.
The red framed element is the video and the green one is the canvas.
I suspect this is because the video stream is not 400 by 300 (not even 4:3 aspect ratio), but I couldn't find yet a solution for this or at least some indication in the HTML specs that this behavior is because of the video stream.
Does anyone have some more experience in this area and can point me in the right direction?
Sorry for the bad quality of the code in the fiddle.
When you set the HTMLElement's widthand height attributes, you're only setting its display size, not the size of the frame inside it.
Canvas2dContext.drawImage(video, x, y) will take the frame size, (which can be set by the mandatory of getUserMedia btw).
So you need either to set your canvas' width and height to the video.videoWidthand video.videoHeight properties to get the full quality image grabbed by the webcam, ot to call ctx.drawImage(video, 0,0, 400, 300) to rescale it on the canvas as it is scaled by CSS, or setting directly the mandatory during the getUserMedia call (latests specs are navigator.mediaDevices.getUserMedia(video: { width: 300, height:300 });) but unfortunately, for this latest, you can't be sure the browser will honor it, except by checking the video.videoHeight/Width ;-)
var ctx = rendering.getContext('2d');
btn.onclick = function() {
switch (select.value) {
case 'css rescale':
rendering.width = 400;
rendering.height = 300;
ctx.drawImage(video, 0, 0, 400, 300);
break;
case 'full quality':
rendering.width = video.videoWidth;
rendering.height = video.videoHeight;
ctx.drawImage(video, 0, 0);
break;
}
}
var initVideo = function(stream) {
video.src = URL.createObjectURL(stream);
video.play();
};
navigator.mediaDevices.getUserMedia({
video: true
})
.then(function(s) {
initVideo(s)
})
.catch(function(err) {
if (err.message.indexOf('secure origins') > -1) {
document.body.innerHTML = '<h3><a target="_blank" href="https://jsfiddle.net/x64ta5r3/">jsfiddle link for chrome and its https policy...</a></h3>(right click -> open Link...';
}
});
<button id="btn">take a snapshot</button>
<select id="select">
<option value="css rescale">css rescale</option>
<option value="full quality">full quality</option>
</select>
<video width="400" height="300" id="video"></video>
<canvas id="rendering"></canvas>
jsfiddle link for chrome and its https policy...
I am trying to take a snapshot from someone's webcam through javascript. The code works except the resultant image is stretched way too much to me readable.
I've messed around with the: ctx.drawImage(video, 0, 0);line
I've tried ctx.drawImage(video, 0, 0,1280,720); with no difference
I've tried ctx.drawImage(video, 0, 0,100,100); with major difference. It made the whole image appear but way too small for the eye.
Code:
<html>
<head>
<video autoplay></video>
<img src="" width=1280, height=720>
<canvas style="display:none;"></canvas>
<script>
var errorCallback = function(e) {
console.log('Reeeejected!', e);
video.src = 'failure.mp4'; // fallback.
};
navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia;
var video = document.querySelector('video');
var canvas = document.querySelector('canvas');
var ctx = canvas.getContext('2d');
var localMediaStream = null;
var hdConstraints = {
video: {
mandatory: {
minWidth: 1280,
minHeight: 720
}
}
};
function snapshot() {
if (localMediaStream) {
ctx.drawImage(video, 0, 0);
// "image/webp" works in Chrome.
// Other browsers will fall back to image/png.
document.querySelector('img').src = canvas.toDataURL('image/webp');
}
}
function success(stream) {
video.src = window.URL.createObjectURL(stream);
localMediaStream = stream;
}
video.addEventListener('click', snapshot, false);
navigator.getUserMedia(hdConstraints, success,errorCallback);
</script>
</head>
</html>
Result:
Video:
Image Output:
So in conjunction with #Loktar's comment, I determined that the secret was to set the canvas size in the html like so:
<canvas style="display:none;" width=1280 height=720></canvas>
This allows for a full screen (aspect correct) capture.
Hope this helps someone else!