From be22b9c46bd7cbc32130d0cd4de77edfb659ff9d Mon Sep 17 00:00:00 2001 From: "Chris E. Kelley" Date: Wed, 16 Jun 2021 13:44:09 -0500 Subject: [PATCH 1/4] implemented camera switcher for photo capture --- demo/tangy-photo-capture.html | 2 +- input/tangy-photo-capture.js | 63 +++++++++++++++++++++++++++++++++-- 2 files changed, 61 insertions(+), 4 deletions(-) diff --git a/demo/tangy-photo-capture.html b/demo/tangy-photo-capture.html index 4a3bff12..45c41d57 100644 --- a/demo/tangy-photo-capture.html +++ b/demo/tangy-photo-capture.html @@ -71,7 +71,7 @@

tangy-photo-capture demo

diff --git a/input/tangy-photo-capture.js b/input/tangy-photo-capture.js index 166a8823..101e78dc 100644 --- a/input/tangy-photo-capture.js +++ b/input/tangy-photo-capture.js @@ -16,6 +16,7 @@ import ImageBlobReduce from 'image-blob-reduce' * @demo demo/index.html */ export class TangyPhotoCapture extends PolymerElement { + static get template () { return html` @@ -46,6 +47,7 @@ export class TangyPhotoCapture extends PolymerElement {
+
@@ -53,6 +55,7 @@ export class TangyPhotoCapture extends PolymerElement {
[[t.capture]] [[t.accept]] + [[t.switch]] [[t.clear]]
@@ -81,6 +84,11 @@ export class TangyPhotoCapture extends PolymerElement { value: 256, reflectToAttribute: true }, + label: { + type: String, + observer: 'reflect', + value: '' + }, hintText: { type: String, observer: 'onHintTextChange', @@ -152,7 +160,12 @@ export class TangyPhotoCapture extends PolymerElement { type: Boolean, value: false, reflectToAttribute: true - } + }, + front: { + type: Boolean, + value: true, + reflectToAttribute: true + }, } } @@ -161,6 +174,11 @@ export class TangyPhotoCapture extends PolymerElement { this.shadowRoot.querySelector('#qnum-number').innerHTML = this.hasAttribute('question-number') ? `` : '' + let supportedConstraints = navigator.mediaDevices.getSupportedConstraints(); + let devices = navigator.mediaDevices.enumerateDevices().then(function(devices) { + var arrayLength = devices.length; + }) + this.constraints = {video: { facingMode: { exact: "environment" } }} } ready() { @@ -170,13 +188,27 @@ export class TangyPhotoCapture extends PolymerElement { accept: t('accept'), clear: t('clear') } + this.shadowRoot.querySelector('#label').innerHTML = this.label // Start streaming video - navigator.mediaDevices.getUserMedia({video: { facingMode: { exact: "environment" } }}) + const constraints = this.getConstraints() + navigator.mediaDevices.getUserMedia(constraints) .then(mediaStream => { this.shadowRoot.querySelector('video').srcObject = mediaStream; const track = mediaStream.getVideoTracks()[0]; this.imageCapture = new ImageCapture(track); - }) + }).catch(error => { + if (error.constraint && error.constraint === 'facingMode') { + navigator.mediaDevices.getUserMedia({video: true}) + .then(mediaStream => { + this.shadowRoot.querySelector('video').srcObject = mediaStream; + const track = mediaStream.getVideoTracks()[0]; + this.imageCapture = new ImageCapture(track); + }); + } else { + console.log("error: " + error) + } + } + ) if (this.value) { this.shadowRoot.querySelector('video').style.display = 'none' @@ -264,6 +296,31 @@ export class TangyPhotoCapture extends PolymerElement { this.shadowRoot.querySelector('#accept-button').setAttribute('disabled', '') } + + + getConstraints() { + if (this.front) { + return {video: { facingMode: { exact: "user" } }} + } else { + return {video: { facingMode: { exact: "environment" } }} + } + } + + toggleCamera() { + if (this.front) { + this.front = false + } else { + this.front = true + } + const constraints = this.getConstraints() + navigator.mediaDevices.getUserMedia(constraints) + .then(mediaStream => { + this.shadowRoot.querySelector('video').srcObject = mediaStream; + const track = mediaStream.getVideoTracks()[0]; + this.imageCapture = new ImageCapture(track); + }) + } + onDiscrepancyChange(value) { this.shadowRoot.querySelector('#discrepancy-text').innerHTML = this.hasDiscrepancy ? `
${ this.hasAttribute('discrepancy-text') ? this.getAttribute('discrepancy-text') : ''}
` From 9f0b146db50952a5cb3fb291a75c675bb6100d80 Mon Sep 17 00:00:00 2001 From: "Chris E. Kelley" Date: Wed, 16 Jun 2021 18:35:57 -0500 Subject: [PATCH 2/4] convert img blob to base64 data url in browser --- demo/tangy-photo-capture.html | 2 +- input/tangy-photo-capture.js | 16 +++++++++------- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/demo/tangy-photo-capture.html b/demo/tangy-photo-capture.html index 45c41d57..6811aa30 100644 --- a/demo/tangy-photo-capture.html +++ b/demo/tangy-photo-capture.html @@ -71,7 +71,7 @@

tangy-photo-capture demo

diff --git a/input/tangy-photo-capture.js b/input/tangy-photo-capture.js index 101e78dc..63a2c8c1 100644 --- a/input/tangy-photo-capture.js +++ b/input/tangy-photo-capture.js @@ -163,7 +163,7 @@ export class TangyPhotoCapture extends PolymerElement { }, front: { type: Boolean, - value: true, + value: false, reflectToAttribute: true }, } @@ -285,12 +285,14 @@ export class TangyPhotoCapture extends PolymerElement { async acceptPhoto() { // Convert blob to base64 string - // https://stackoverflow.com/questions/18650168/convert-blob-to-base64/61226119#61226119 - const reader = new FileReader(); - reader.readAsDataURL(this.blob); - this.value = await new Promise(resolve => { - reader.onloadend = () => resolve(reader.result); - }); + const arrayBuffer = await this.blob.arrayBuffer() + // convert arrayBuffer to a string + const abString = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)) + // base64 encode the string + const b64 = window.btoa(unescape(encodeURIComponent(abString))); + // turn it into a data:image + const nudata = 'data:image/jpeg;base64,' + b64 + this.data = nudata this.shadowRoot.querySelector('#capture-button').setAttribute('disabled', '') this.shadowRoot.querySelector('#accept-button').setAttribute('disabled', '') From 3472d063f6153d65938712df6f2e8cd6686652f6 Mon Sep 17 00:00:00 2001 From: "Chris E. Kelley" Date: Wed, 16 Jun 2021 19:56:50 -0500 Subject: [PATCH 3/4] new base64String function --- input/tangy-photo-capture.js | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/input/tangy-photo-capture.js b/input/tangy-photo-capture.js index 63a2c8c1..f29197a4 100644 --- a/input/tangy-photo-capture.js +++ b/input/tangy-photo-capture.js @@ -287,12 +287,13 @@ export class TangyPhotoCapture extends PolymerElement { // Convert blob to base64 string const arrayBuffer = await this.blob.arrayBuffer() // convert arrayBuffer to a string - const abString = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)) + // const abString = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)) // base64 encode the string - const b64 = window.btoa(unescape(encodeURIComponent(abString))); + // const b64 = window.btoa(unescape(encodeURIComponent(abString))); + const base64String = window.btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))); // turn it into a data:image - const nudata = 'data:image/jpeg;base64,' + b64 - this.data = nudata + const nudata = 'data:image/jpeg;base64,' + base64String + this.value = nudata this.shadowRoot.querySelector('#capture-button').setAttribute('disabled', '') this.shadowRoot.querySelector('#accept-button').setAttribute('disabled', '') From 6817ecd9dadd197bd21beca1d998ab65763f6ee5 Mon Sep 17 00:00:00 2001 From: "Chris E. Kelley" Date: Wed, 16 Jun 2021 19:57:24 -0500 Subject: [PATCH 4/4] code cleanup --- input/tangy-photo-capture.js | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/input/tangy-photo-capture.js b/input/tangy-photo-capture.js index f29197a4..cbb4c5f0 100644 --- a/input/tangy-photo-capture.js +++ b/input/tangy-photo-capture.js @@ -286,10 +286,7 @@ export class TangyPhotoCapture extends PolymerElement { async acceptPhoto() { // Convert blob to base64 string const arrayBuffer = await this.blob.arrayBuffer() - // convert arrayBuffer to a string - // const abString = String.fromCharCode.apply(null, new Uint8Array(arrayBuffer)) - // base64 encode the string - // const b64 = window.btoa(unescape(encodeURIComponent(abString))); + // convert arrayBuffer to a base64String const base64String = window.btoa(String.fromCharCode(...new Uint8Array(arrayBuffer))); // turn it into a data:image const nudata = 'data:image/jpeg;base64,' + base64String