getUserMedia not capturing the screen correctly - javascript

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.

Related

Brightness of image on canvas Iphone 13 pro

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.

Is there a way to specify streaming video resolution/canvas size in html5/Javascript?

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.

How to use canvas for parsing imageData from video without appending canvas to the page?

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;

How to resolve iOS 11 Safari getUserMedia "Invalid constraint" issue

I'm attempting to run the following code in Safari in iOS 11. It should prompt the user to give access to their devices camera and then display it in my <video autoplay id="video"></video> element. However, when running in iOS 11, it results in an OverconstrainedError to be thrown:
{message: "Invalid constraint", constraint: ""}
The code runs fine in Android and successfully opens the camera.
I've attempted multiple valid configurations with no luck.
I know iOS 11 just came out so it may be a bug, but any thoughts? Has anyone else run into this?
Code:
var video = document.getElementById('video');
if(navigator.mediaDevices && navigator.mediaDevices.getUserMedia) {
navigator.mediaDevices.getUserMedia({video: true})
.then(function(stream) {
video.src = window.URL.createObjectURL(stream);
video.play();
})
.catch(function(err) {
console.log(err);
});
}
Edit 1
I've run navigator.mediaDevices.getSupportedConstraints() and it returns the following:
{
aspectRatio: true,
deviceid: true,
echoCancellation: false,
facingMode: true,
frameRate: true,
groupId: true,
height: true,
sampleRate: false,
sampleSize: false,
volume: true,
width: true
}
I've tried configurations omitting the video property, but had no luck.
The invalid constraint error in safari is because the browser expects that you pass a correct width, one of:
320
640
1280
the height is auto calculate in an aspect ratio of 4:3 for 320 or 640, and 16:9 for 1280, then if you pass a width of 320, you video stream is set in:
320x240
if you set a width of 640, you video stream is set in:
640x480
And if you set a width of 1280, then you video stream is set in:
1280x720
In any other case you got a error "InvalidConstrain" for width value.
Also you can use a min, max, exact or ideal constrains for width, please check the MDN documentation
Here an example in this codepen
var config = { video: { width: 320/*320-640-1280*/ } };
var start = () => navigator.mediaDevices.getUserMedia(config)
.then(stream => v.srcObject = stream)
.then(() => new Promise(resolve => v.onloadedmetadata = resolve))
.then(() => log("Success: " + v.videoWidth + "x" + v.videoHeight))
.catch(log);
var log = msg => div.innerHTML += "<p>" + msg + "</p>";
PD: In chrome you can set a width of height and the video stream is set in these sizes, Firefox do a fitness distance, and Safari expect a exact match.
Remember that the iOS Simulator that comes with Xcode does not support webcam or microphone, which is why you may get the OverconstrainedError (as per https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia docs, that means no device fits the passed options, even if you're not putting specifics)
It appears to have been a bug that was corrected, because I just tried it again and the error message no longer appears.
Note that while the error message went away, I did have to make one more change for it to work, which was adding video.srcObject = stream; in the then callback.

Drawing canvas with an image picked with Cordova Camera Plugin

I'm getting an image from device and drawing a canvas with filters using Pixi JS. It works all well using computer to get an image. But when I'm on IOS, it throws errors such as cross origin issue, or that I'm trying to use an unknown format.
This is the code I'm using to draw the image (that works on web/desktop but not cordova built ios app)
_renderImage() {
let wWidth;
if (window.outerWidth > 414) {
wWidth = 414;
} else {
wWidth = window.outerWidth;
}
const img = new Image();
img.src = this.state.avatarSource;
let lower;
if (img.width > img.height) {
lower = img.height;
} else {
lower = img.width;
}
const canvas = this.refs.canvasimg;
if (canvas.hasChildNodes()) {
canvas.removeChild(canvas.childNodes[0]);
}
const renderer = PIXI.autoDetectRenderer(wWidth, wWidth * 1.25, {transparent: true});
const stage = new PIXI.Container();
canvas.appendChild(renderer.view);
// create a PIXI sprite from an image path
const canvasImg = PIXI.Sprite.fromImage(this.state.avatarSource);
canvasImg.anchor.x = 0;
canvasImg.anchor.y = 0;
canvasImg.width = wWidth;
canvasImg.height = wWidth * 1.25;
const filter = this._getImageFilter();
stage.filters = [filter];
stage.addChild(canvasImg);
render();
function render(){
requestAnimationFrame(render);
renderer.render(stage);
}
}
And this is the code I use to pick the image using cordova camera plugin:
_getPhoto(isPhotosLib) {
const captureSuccess = (imageData) => {
this.m.setState({
// avatarSource: `data:image/jpeg;base64,${imageData}`
avatarSource: imageData
})
};
const captureError = (error) => {
navigator.notification.alert('Error code: ' + error.code, null, 'Capture Error');
};
let options = {
quality: 100,
targetWidth: 640,
targetHeight: 640,
saveToPhotoAlbum: false,
destinationType: Camera.DestinationType.FILE_URI,
popoverOptions: new CameraPopoverOptions(640, 640, 100, 100, Camera.PopoverArrowDirection.ARROW_ANY)
}
isPhotosLib ? options.sourceType = Camera.PictureSourceType.PHOTOLIBRARY : null;
navigator.camera.getPicture(captureSuccess, captureError, options);
}
The error I get is this:
Failed to load resource: Origin null is not allowed by Access-Control-Allow-Origin.
And on XCode:
[Generic] Creating an image format with an unknown type is an error
And when I changed to NATIVE_URI, it logs this error:
Failed to load resource: unsupported URL
assets-library://asset/asset.JPG?id=2DDAD0CF-2F82-40A0-B84B-398C996AC749&ext=JPG
So what could be the reason that it doesn't work on ios?
Check out this post regarding the Cordova Whitelist Plugin, it has solved most of my issues.
I don't know whether or not you are using any WKWebView plugins, but the cordova-wkwebview-engine plugin supports some iOS specific Application Transport Security settings as well https://github.com/apache/cordova-plugin-wkwebview-engine.
Another workaround would be to use an HTML input tag to initiate the camera capture:
<input type="file" capture="camera" accept="image/*" />
And just listen to the "change" event.
on the option section, set as DATA_URL :
destinationType: Camera.DestinationType.DATA_URL
this will get image as base64 format, to display the image, add
<img src="data:image/jpeg;base64,'+ imageData +'">
then the canvas draw from this img tag

Categories