From a4874bc13d50a48d7b11901229dc9d38d8db5e08 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Tue, 30 Jan 2018 23:12:27 -0500 Subject: [PATCH 1/5] Add `mirror: true` opt that flips webcam picture to act like mirror MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Should we add a UI button to flip/mirror the image? Camera might be looking the other way, it could be a front facing camera. - Decide on what to do with dimensions, if we scale the image to fill the Dashboard UI window, we’ll have to crop some parts, depending on the size if the screen. What about mobile? --- src/plugins/Webcam/CameraScreen.js | 3 +-- src/plugins/Webcam/index.js | 20 +++++++++++++++++--- src/scss/_webcam.scss | 13 +++++-------- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/plugins/Webcam/CameraScreen.js b/src/plugins/Webcam/CameraScreen.js index 08dfb38866..cc51f6a301 100644 --- a/src/plugins/Webcam/CameraScreen.js +++ b/src/plugins/Webcam/CameraScreen.js @@ -27,14 +27,13 @@ class CameraScreen extends Component { return (
-
{ this.btnContainer = el }}> {shouldShowSnapshotButton ? SnapshotButton(this.props) : null} {' '} {shouldShowRecordButton ? RecordButton(this.props) : null}
-
) } diff --git a/src/plugins/Webcam/index.js b/src/plugins/Webcam/index.js index 2642234434..6e2d61f77f 100644 --- a/src/plugins/Webcam/index.js +++ b/src/plugins/Webcam/index.js @@ -56,6 +56,7 @@ module.exports = class Webcam extends Plugin { onBeforeSnapshot: () => Promise.resolve(), countdown: false, locale: defaultLocale, + mirror: true, modes: [ 'video-audio', 'video-only', @@ -251,10 +252,22 @@ module.exports = class Webcam extends Plugin { const name = `webcam-${Date.now()}.jpg` const mimeType = 'image/jpeg' + const width = video.videoWidth + const height = video.videoHeight + + const scaleH = this.opts.mirror ? -1 : 1 // Set horizontal scale to -1 if flip horizontal + const scaleV = 1 + const posX = this.opts.mirror ? width * -1 : 0 // Set x position to -100% if flip horizontal + const posY = 0 + const canvas = document.createElement('canvas') - canvas.width = video.videoWidth - canvas.height = video.videoHeight - canvas.getContext('2d').drawImage(video, 0, 0) + canvas.width = width + canvas.height = height + const ctx = canvas.getContext('2d') + ctx.save() // Save the current state + ctx.scale(scaleH, scaleV) // Set scale to flip the image + ctx.drawImage(video, posX, posY, width, height) // draw the image + ctx.restore() // Restore the last saved state return canvasToBlob(canvas, mimeType).then((blob) => { return { @@ -313,6 +326,7 @@ module.exports = class Webcam extends Plugin { modes: this.opts.modes, supportsRecording: supportsMediaRecorder(), recording: webcamState.isRecording, + mirror: this.opts.mirror, src: this.streamSrc })) } diff --git a/src/scss/_webcam.scss b/src/scss/_webcam.scss index d0c4f99975..ddc47ee5bd 100644 --- a/src/scss/_webcam.scss +++ b/src/scss/_webcam.scss @@ -1,8 +1,3 @@ -// @import '_variables.scss'; -// @import '_utils.scss'; -// @import '_animation.scss'; -// @import '_common.scss'; - .uppy-Webcam-container { width: 100%; height: 100%; @@ -19,13 +14,15 @@ } .uppy-Webcam-video { + width: 100%; + height: 100%; max-width: 100%; max-height: 100%; } -// .uppy-Webcam-canvas { -// display: none; -// } + .uppy-Webcam-video--mirrored { + transform: scaleX(-1); + } .uppy-Webcam-buttonContainer { position: absolute; From 992a9ac8352dcc3c20e19182fc4699038c85c408 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Fri, 2 Feb 2018 16:06:29 -0500 Subject: [PATCH 2/5] Fill the whole Uppy screen with webcam preview image --- src/scss/_webcam.scss | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/src/scss/_webcam.scss b/src/scss/_webcam.scss index ddc47ee5bd..ef457e4959 100644 --- a/src/scss/_webcam.scss +++ b/src/scss/_webcam.scss @@ -7,12 +7,17 @@ } .uppy-Webcam-videoContainer { + width: 100%; height: 100%; - display: flex; - justify-content: center; - align-items: center; + // display: flex; + // justify-content: center; + // align-items: center; } + .uppy-Dashboard--wide .uppy-Webcam-videoContainer { + height: initial; + } + .uppy-Webcam-video { width: 100%; height: 100%; From 8c087d1b2dac953ff4a4b2b8c3ece764310fd15a Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Wed, 7 Feb 2018 00:14:09 -0500 Subject: [PATCH 3/5] Fix webcam in Safari on Mac and iOS, add facingMode: user using stream directly on srcObject video attribute, instead of createObjectURL --- src/plugins/Webcam/CameraScreen.js | 2 +- src/plugins/Webcam/index.js | 9 ++++----- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/src/plugins/Webcam/CameraScreen.js b/src/plugins/Webcam/CameraScreen.js index cc51f6a301..8f5409cd77 100644 --- a/src/plugins/Webcam/CameraScreen.js +++ b/src/plugins/Webcam/CameraScreen.js @@ -27,7 +27,7 @@ class CameraScreen extends Component { return (
-
{ this.btnContainer = el }}> {shouldShowSnapshotButton ? SnapshotButton(this.props) : null} diff --git a/src/plugins/Webcam/index.js b/src/plugins/Webcam/index.js index 6e2d61f77f..02667cbebd 100644 --- a/src/plugins/Webcam/index.js +++ b/src/plugins/Webcam/index.js @@ -57,6 +57,7 @@ module.exports = class Webcam extends Plugin { countdown: false, locale: defaultLocale, mirror: true, + facingMode: 'user', modes: [ 'video-audio', 'video-only', @@ -109,7 +110,7 @@ module.exports = class Webcam extends Plugin { return { audio: acceptsAudio, - video: acceptsVideo + video: acceptsVideo ? { facingMode: this.opts.facingMode } : false } } @@ -126,8 +127,7 @@ module.exports = class Webcam extends Plugin { return this.mediaDevices.getUserMedia(constraints) .then((stream) => { this.stream = stream - console.log(stream) - this.streamSrc = URL.createObjectURL(this.stream) + // this.streamSrc = URL.createObjectURL(this.stream) this.setPluginState({ cameraReady: true }) @@ -192,7 +192,6 @@ module.exports = class Webcam extends Plugin { }) this.webcamActive = false this.stream = null - this.streamSrc = null } getVideoElement () { @@ -327,7 +326,7 @@ module.exports = class Webcam extends Plugin { supportsRecording: supportsMediaRecorder(), recording: webcamState.isRecording, mirror: this.opts.mirror, - src: this.streamSrc + src: this.stream })) } From f1bc38c321b4866b8b29cec6bf52acb870303bed Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Wed, 7 Feb 2018 00:14:59 -0500 Subject: [PATCH 4/5] =?UTF-8?q?Don=E2=80=99t=20flip=20the=20resulting=20im?= =?UTF-8?q?age=20when=20mirroring,=20just=20the=20preview?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/plugins/Webcam/index.js | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/plugins/Webcam/index.js b/src/plugins/Webcam/index.js index 02667cbebd..393b0e1d9d 100644 --- a/src/plugins/Webcam/index.js +++ b/src/plugins/Webcam/index.js @@ -254,19 +254,20 @@ module.exports = class Webcam extends Plugin { const width = video.videoWidth const height = video.videoHeight - const scaleH = this.opts.mirror ? -1 : 1 // Set horizontal scale to -1 if flip horizontal - const scaleV = 1 - const posX = this.opts.mirror ? width * -1 : 0 // Set x position to -100% if flip horizontal - const posY = 0 + // const scaleH = this.opts.mirror ? -1 : 1 // Set horizontal scale to -1 if flip horizontal + // const scaleV = 1 + // const posX = this.opts.mirror ? width * -1 : 0 // Set x position to -100% if flip horizontal + // const posY = 0 const canvas = document.createElement('canvas') canvas.width = width canvas.height = height const ctx = canvas.getContext('2d') - ctx.save() // Save the current state - ctx.scale(scaleH, scaleV) // Set scale to flip the image - ctx.drawImage(video, posX, posY, width, height) // draw the image - ctx.restore() // Restore the last saved state + ctx.drawImage(video, 0, 0) + // ctx.save() // Save the current state + // ctx.scale(scaleH, scaleV) // Set scale to flip the image + // ctx.drawImage(video, posX, posY, width, height) // draw the image + // ctx.restore() // Restore the last saved state return canvasToBlob(canvas, mimeType).then((blob) => { return { From 3a30f53247e31116d7d36bb9e5f9cfb14e97db72 Mon Sep 17 00:00:00 2001 From: Artur Paikin Date: Thu, 8 Feb 2018 23:29:12 -0500 Subject: [PATCH 5/5] Add new options to docs --- src/plugins/Webcam/index.js | 6 +++--- website/src/docs/webcam.md | 19 ++++++++++++++++++- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/plugins/Webcam/index.js b/src/plugins/Webcam/index.js index 393b0e1d9d..e60e9eb43c 100644 --- a/src/plugins/Webcam/index.js +++ b/src/plugins/Webcam/index.js @@ -56,14 +56,14 @@ module.exports = class Webcam extends Plugin { onBeforeSnapshot: () => Promise.resolve(), countdown: false, locale: defaultLocale, - mirror: true, - facingMode: 'user', modes: [ 'video-audio', 'video-only', 'audio-only', 'picture' - ] + ], + mirror: true, + facingMode: 'user' } // merge default options with the ones set by user diff --git a/website/src/docs/webcam.md b/website/src/docs/webcam.md index 42d7e7b9b4..c06585de82 100644 --- a/website/src/docs/webcam.md +++ b/website/src/docs/webcam.md @@ -5,8 +5,9 @@ title: "Webcam" permalink: docs/webcam/ --- +The Webcam plugin lets you take photos and record videos with a built-in camera on desktop and mobile devices. -[Try it live](/examples/dashboard/) - The Informer is included in the Dashboard by default. +[Try live!](/examples/dashboard/) ## Options @@ -20,6 +21,8 @@ uppy.use(Webcam, { 'audio-only', 'picture' ], + mirror: true, + facingMode: 'user', locale: { strings: { smile: 'Smile!' @@ -52,6 +55,20 @@ The types of recording modes to allow. By default, all modes are allowed, and the Webcam plugin will show controls for recording video as well as taking pictures. +### `mirror: true` + +Whether to mirror preview image from the camera. This option is useful when taking a selfie with a front camera: when you wave your right hand, you will see your hand on the right on the preview screen, like in the mirror. But when you actually take a picture, it will not be mirrored. This is how smartphone selfie cameras behave. + +### `facingMode: 'user'` + +Devices sometimes have multiple cameras, front and back, for example. There’s a browser API to set which camera will be used, [facingMode](https://developer.mozilla.org/en-US/docs/Web/API/MediaTrackConstraints/facingMode): + +- `user`: The video source is facing toward the user; this includes, for example, the front-facing camera on a smartphone. +- `environment`: The video source is facing away from the user, thereby viewing their environment. This is the back camera on a smartphone. +- `left`: The video source is facing toward the user but to their left, such as a camera aimed toward the user but over their left shoulder. +- `right`: The video source is facing toward the user but to their right, such as a camera aimed toward the user but over their right shoulder. + + ### `locale: {}` There is only one localizable string: `strings.smile`. It's shown before a picture is taken, when the `countdown` option is set to true.