├── .eslintignore
├── docs
├── CNAME
├── favicon.ico
├── icons
│ ├── favicon-16x16.png
│ ├── favicon-32x32.png
│ ├── mstile-70x70.png
│ ├── apple-touch-icon.png
│ ├── mstile-144x144.png
│ ├── mstile-150x150.png
│ ├── mstile-310x150.png
│ ├── mstile-310x310.png
│ ├── android-chrome-192x192.png
│ ├── android-chrome-512x512.png
│ └── safari-pinned-tab.svg
├── browserconfig.xml
├── manifest.json
├── index.css
├── index.html
├── index.js
└── bundle.js
├── .gitignore
├── .travis.yml
├── .npmignore
├── src
├── favicon.svg
└── imagecapture.js
├── webpack.config.js
├── .eslintrc.js
├── CONTRIBUTING.md
├── package.json
├── README.md
└── LICENSE
/.eslintignore:
--------------------------------------------------------------------------------
1 | docs/bundle.js
2 |
--------------------------------------------------------------------------------
/docs/CNAME:
--------------------------------------------------------------------------------
1 | imagecapture.js.org
2 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | .idea
3 | lib
4 | npm-debug.log
5 |
--------------------------------------------------------------------------------
/docs/favicon.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/favicon.ico
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - '9'
4 | - '8'
5 | - '7'
6 | - '6'
7 | - '5'
8 | - '4'
9 |
--------------------------------------------------------------------------------
/docs/icons/favicon-16x16.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/favicon-16x16.png
--------------------------------------------------------------------------------
/docs/icons/favicon-32x32.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/favicon-32x32.png
--------------------------------------------------------------------------------
/docs/icons/mstile-70x70.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/mstile-70x70.png
--------------------------------------------------------------------------------
/docs/icons/apple-touch-icon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/apple-touch-icon.png
--------------------------------------------------------------------------------
/docs/icons/mstile-144x144.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/mstile-144x144.png
--------------------------------------------------------------------------------
/docs/icons/mstile-150x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/mstile-150x150.png
--------------------------------------------------------------------------------
/docs/icons/mstile-310x150.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/mstile-310x150.png
--------------------------------------------------------------------------------
/docs/icons/mstile-310x310.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/mstile-310x310.png
--------------------------------------------------------------------------------
/docs/icons/android-chrome-192x192.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/android-chrome-192x192.png
--------------------------------------------------------------------------------
/docs/icons/android-chrome-512x512.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/GoogleChromeLabs/imagecapture-polyfill/master/docs/icons/android-chrome-512x512.png
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | bower.json
2 | node_modules
3 | .idea
4 | .eslintrc.js
5 | build
6 | demo
7 | tests
8 | .travis.yml
9 | *.html
10 | **/*.bak
11 | src/favicon.svg
12 | yarn.lock
13 | CONTRIBUTING.md
14 |
--------------------------------------------------------------------------------
/docs/browserconfig.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | #da532c
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/src/favicon.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/webpack.config.js:
--------------------------------------------------------------------------------
1 | const path = require('path');
2 |
3 | module.exports = {
4 | context: path.join(__dirname, 'docs'),
5 | entry: './index.js',
6 |
7 | devServer: {
8 | contentBase: './docs',
9 | inline: true,
10 | },
11 |
12 | output: {
13 | path: path.join(__dirname, 'docs'),
14 | filename: './bundle.js',
15 | },
16 | };
17 |
--------------------------------------------------------------------------------
/docs/manifest.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ImageCapture polyfill demo",
3 | "icons": [
4 | {
5 | "src": "icons/android-chrome-192x192.png",
6 | "sizes": "192x192",
7 | "type": "image/png"
8 | },
9 | {
10 | "src": "icons/android-chrome-512x512.png",
11 | "sizes": "512x512",
12 | "type": "image/png"
13 | }
14 | ],
15 | "theme_color": "#ffffff",
16 | "display": "standalone"
17 | }
18 |
--------------------------------------------------------------------------------
/docs/index.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2018 Google Inc.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 |
17 | #photo {
18 | filter: hue-rotate(180deg);
19 | }
20 |
--------------------------------------------------------------------------------
/.eslintrc.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | env: {
3 | browser: true,
4 | es6: true
5 | },
6 | parserOptions: {
7 | sourceType: 'module',
8 | },
9 | extends: 'google',
10 | rules: {
11 | 'max-len': [ 'warn',
12 | { code: 130 } // 130 on GitHub, 80 on npmjs.org for README.md code blocks
13 | ],
14 | 'arrow-parens': ['error', 'as-needed'],
15 | 'space-before-function-paren': [
16 | 'error',
17 | {
18 | anonymous: 'always',
19 | named: 'never'
20 | }
21 | ],
22 | 'no-negated-condition': 'warn',
23 | 'spaced-comment': ['error', 'always', { exceptions: ['/'] }]
24 | },
25 | globals: {
26 | DOMException: false,
27 | MediaStream: false,
28 | Polymer: false,
29 | URL: false,
30 | }
31 | };
32 |
--------------------------------------------------------------------------------
/docs/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | MediaStream ImageCapture polyfill demo
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | Capturing every 300 milliseconds
19 | grabFrame()
20 |
21 | takePhoto() with post-processing ("Avatar" mix)
22 |
23 | Stop frame grab
24 |
25 |
26 |
27 |
28 |
29 |
30 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | Want to contribute? Great! First, read this page (including the small print at the end).
2 |
3 | ### Before you contribute
4 | Before we can use your code, you must sign the
5 | [Google Individual Contributor License Agreement]
6 | (https://cla.developers.google.com/about/google-individual)
7 | (CLA), which you can do online. The CLA is necessary mainly because you own the
8 | copyright to your changes, even after your contribution becomes part of our
9 | codebase, so we need your permission to use and distribute your code. We also
10 | need to be sure of various other things—for instance that you'll tell us if you
11 | know that your code infringes on other people's patents. You don't have to sign
12 | the CLA until after you've submitted your code for review and a member has
13 | approved it, but you must do it before we can put your code into our codebase.
14 | Before you start working on a larger contribution, you should get in touch with
15 | us first through the issue tracker with your idea so that we can help out and
16 | possibly guide you. Coordinating up front makes it much easier to avoid
17 | frustration later on.
18 |
19 | ### Code reviews
20 | All submissions, including submissions by project members, require review. We
21 | use GitHub pull requests for this purpose.
22 |
23 | ### The small print
24 | Contributions made by corporations are covered by a different agreement than
25 | the one above, the
26 | [Software Grant and Corporate Contributor License Agreement]
27 | (https://cla.developers.google.com/about/google-corporate).
28 |
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "image-capture",
3 | "version": "0.4.0",
4 | "description": "MediaStream ImageCapture polyfill: takePhoto(), grabFrame() and more",
5 | "main": "lib/imagecapture.js",
6 | "module": "src/imagecapture.js",
7 | "jsnext:main": "src/imagecapture.js",
8 | "scripts": {
9 | "lint": "eslint src/*.js docs/index.js",
10 | "prepare": "babel -d lib src/ && uglifyjs lib/imagecapture.js --compress --mangle --comments -o lib/imagecapture.min.js",
11 | "dev": "webpack-dev-server --progress",
12 | "lt": "lt --port 8080 --subdomain imagecapture",
13 | "docs": "webpack"
14 | },
15 | "repository": {
16 | "type": "git",
17 | "url": "git+https://github.com/GoogleChrome/imagecapture-polyfill.git"
18 | },
19 | "keywords": [
20 | "camera",
21 | "webcam",
22 | "photo",
23 | "picture",
24 | "image",
25 | "capture",
26 | "ImageCapture",
27 | "MediaStream",
28 | "getUserMedia"
29 | ],
30 | "author": "Dan Dascalescu (dandv)",
31 | "license": "MIT",
32 | "bugs": {
33 | "url": "https://github.com/GoogleChrome/imagecapture-polyfill/issues"
34 | },
35 | "homepage": "https://github.com/GoogleChrome/imagecapture-polyfill#readme",
36 | "dependencies": {},
37 | "devDependencies": {
38 | "babel-cli": "^6.26.0",
39 | "babel-plugin-transform-es2015-modules-commonjs": "^6.26.0",
40 | "babel-preset-es2015": "^6.24.1",
41 | "eslint": "^3.19.0",
42 | "eslint-config-google": "^0.7.1",
43 | "localtunnel": "^1.8.3",
44 | "uglify-js": "^3.3.5",
45 | "webpack": "^2.7.0",
46 | "webpack-dev-server": "^2.10.1"
47 | },
48 | "babel": {
49 | "presets": [
50 | [
51 | "es2015",
52 | {
53 | "modules": "umd"
54 | }
55 | ]
56 | ]
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/docs/icons/safari-pinned-tab.svg:
--------------------------------------------------------------------------------
1 |
2 |
4 |
7 |
8 | Created by potrace 1.11, written by Peter Selinger 2001-2013
9 |
10 |
12 |
27 |
36 |
37 |
38 |
--------------------------------------------------------------------------------
/docs/index.js:
--------------------------------------------------------------------------------
1 | // Copyright 2018 Google Inc.
2 | //
3 | // Licensed under the Apache License, Version 2.0 (the "License");
4 | // you may not use this file except in compliance with the License.
5 | // You may obtain a copy of the License at
6 | //
7 | // http://www.apache.org/licenses/LICENSE-2.0
8 | //
9 | // Unless required by applicable law or agreed to in writing, software
10 | // distributed under the License is distributed on an "AS IS" BASIS,
11 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | // See the License for the specific language governing permissions and
13 | // limitations under the License.
14 | //
15 | ////////////////////////////////////////////////////////////////////////////////
16 |
17 | // Demo for the MediaStream ImageCapture polyfill
18 |
19 | 'use strict';
20 |
21 | const logElement = document.querySelector('#log');
22 |
23 | /**
24 | * Log messages to the #log element and the console
25 | * @param {*[]} messages - list of messages
26 | */
27 | function log(...messages) {
28 | console.log(...messages);
29 | const p = document.createElement('p');
30 | p.innerText = messages.join(' ');
31 | logElement.appendChild(p);
32 | }
33 |
34 | /**
35 | * Log messages to the #log element and the console as errors
36 | * @param {*} messages - list of messages
37 | */
38 | function err(...messages) {
39 | console.error(...messages);
40 | const p = document.createElement('p');
41 | p.innerText = messages.join(' ');
42 | p.style = 'color: red';
43 | logElement.appendChild(p);
44 | }
45 |
46 | import {ImageCapture} from '../src/imagecapture';
47 |
48 | let interval;
49 | const canvas = document.getElementById('frame');
50 |
51 | const photo = document.getElementById('photo');
52 | photo.addEventListener('load', function () {
53 | // After the image loads, discard the image object to release the memory
54 | window.URL.revokeObjectURL(photo.src);
55 | });
56 |
57 | let videoDevice;
58 | document.getElementById('stop').addEventListener('click', stopFunction);
59 |
60 | // Use navigator.mediaDevices.getUserMedia instead of navigator.getUserMedia, per
61 | // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia and https://webrtc.org/web-apis/interop/
62 | // For cross-platform compatibility, we'll use the WebRTC adapter.js library
63 | navigator.mediaDevices.getUserMedia({video: true}).then(gotMedia).catch(failedToGetMedia);
64 |
65 | /**
66 | * We have a video capture device. Exercise various capturing modes.
67 | * @param {MediaStream} mediaStream
68 | */
69 | function gotMedia(mediaStream) {
70 | // Extract video track.
71 | videoDevice = mediaStream.getVideoTracks()[0];
72 | log('Using camera', videoDevice.label);
73 |
74 | const captureDevice = new ImageCapture(videoDevice, mediaStream);
75 | interval = setInterval(function () {
76 | captureDevice.grabFrame().then(processFrame).catch(error => {
77 | err((new Date()).toISOString(), 'Error while grabbing frame:', error);
78 | });
79 |
80 | captureDevice.takePhoto().then(processPhoto).catch(error => {
81 | err((new Date()).toISOString(), 'Error while taking photo:', error);
82 | });
83 | }, 300);
84 | }
85 |
86 | /**
87 | * Draw the imageBitmap returned by grabFrame() onto a canvas
88 | * @param {ImageBitmap} imageBitmap
89 | */
90 | function processFrame(imageBitmap) {
91 | canvas.width = imageBitmap.width;
92 | canvas.height = imageBitmap.height;
93 | canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
94 | }
95 |
96 | /**
97 | * Set the source of the 'photo' to the blob returned by takePhoto()
98 | * @param {Blob} blob
99 | */
100 | function processPhoto(blob) {
101 | photo.src = window.URL.createObjectURL(blob);
102 | }
103 |
104 | /**
105 | * Stop frame grabbing and video capture
106 | */
107 | function stopFunction() {
108 | if (interval) clearInterval(interval); // stop frame grabbing
109 | if (videoDevice) videoDevice.stop(); // turn off the camera
110 | }
111 |
112 | /**
113 | * Handle errors
114 | * @param {Error} error
115 | */
116 | function failedToGetMedia(error) {
117 | err('getUserMedia failed:', error);
118 | stopFunction();
119 | }
120 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ImageCapture polyfill
2 |
3 | [](https://travis-ci.org/GoogleChromeLabs/imagecapture-polyfill) [](https://david-dm.org/GoogleChromeLabs/imagecapture-polyfill) [](https://david-dm.org/GoogleChromeLabs/imagecapture-polyfill#info=devDependencies)
4 |
5 | ImageCapture is a polyfill for the [MediaStream Image Capture API](https://w3c.github.io/mediacapture-image/).
6 |
7 | ## Status
8 |
9 | As of June 2017, the ImageCapture spec is [relatively stable](https://github.com/w3c/mediacapture-image/issues). Chrome supports the API starting with M59 (earlier versions require setting a flag) and Firefox has partial support behind a flag. See the [ImageCapture browser support](https://github.com/w3c/mediacapture-image/blob/gh-pages/implementation-status.md) page for details.
10 |
11 | ## Prior art
12 |
13 | Prior to this API, in order to take a still picture from the device camera, two approaches have been used:
14 |
15 | 1. Set the source of a `` element to a stream obtained via [`navigator[.mediaDevices].getUserMedia`](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia), then use a 2D canvas context to [`drawImage`](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/drawImage) from that video. The `canvas` can return a URL to be used as the `src` attribute of an ` ` element, via [`.toDataURL('image/')`](https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toDataURL). ([1](http://www.html5rocks.com/en/tutorials/getusermedia/intro/#toc-screenshot), [2](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Taking_still_photos))
16 | 2. Use the [HTML Media Capture API](https://w3c.github.io/html-media-capture/), i.e. ` `
17 |
18 | # Demo
19 |
20 | [The demo](https://dandv.github.io/imagecapture) currently shows grabFrame() and takePhoto().
21 |
22 | # Quick start
23 |
24 | ```shell
25 | yarn add image-capture
26 | ```
27 |
28 | Or, with npm:
29 |
30 | ```shell
31 | npm install --save image-capture
32 | ```
33 |
34 | In your JS code:
35 |
36 | ```js
37 | let videoDevice;
38 | let canvas = document.getElementById('canvas');
39 | let photo = document.getElementById('photo');
40 |
41 | navigator.mediaDevices.getUserMedia({video: true}).then(gotMedia).catch(failedToGetMedia);
42 |
43 | function gotMedia(mediaStream) {
44 | // Extract video track.
45 | videoDevice = mediaStream.getVideoTracks()[0];
46 | // Check if this device supports a picture mode...
47 | let captureDevice = new ImageCapture(videoDevice);
48 | if (captureDevice) {
49 | captureDevice.takePhoto().then(processPhoto).catch(stopCamera);
50 | captureDevice.grabFrame().then(processFrame).catch(stopCamera);
51 | }
52 | }
53 |
54 | function processPhoto(blob) {
55 | photo.src = window.URL.createObjectURL(blob);
56 | }
57 |
58 | function processFrame(imageBitmap) {
59 | canvas.width = imageBitmap.width;
60 | canvas.height = imageBitmap.height;
61 | canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
62 | }
63 |
64 | function stopCamera(error) {
65 | console.error(error);
66 | if (videoDevice) videoDevice.stop(); // turn off the camera
67 | }
68 |
69 | photo.addEventListener('load', function () {
70 | // After the image loads, discard the image object to release the memory
71 | window.URL.revokeObjectURL(this.src);
72 | });
73 | ```
74 |
75 |
76 | # Methods
77 |
78 | Start by constructing a new ImageCapture object:
79 |
80 | ```js
81 | let captureDevice;
82 |
83 | navigator.mediaDevices.getUserMedia({video: true}).then(mediaStream => {
84 | captureDevice = new ImageCapture(mediaStream.getVideoTracks()[0]);
85 | }).catch(...)
86 | ```
87 |
88 | Please consult [the spec](https://w3c.github.io/mediacapture-image/#methods) for full detail on the methods.
89 |
90 | ## constructor(videoStreamTrack)
91 |
92 | Takes a video track and returns an ImageCapture object.
93 |
94 |
95 | ## getPhotoCapabilities
96 |
97 | TBD
98 |
99 | ## setOptions
100 |
101 | TBD
102 |
103 | ## takePhoto
104 |
105 | Capture the video stream into a [Blob](https://www.w3.org/TR/FileAPI/#blob) containing a single still image.
106 |
107 | Returns a Promise that resolves to a Blob on success, or is rejected with `DOMException` on failure.
108 |
109 | ```js
110 | captureDevice.takePhoto().then(blob => {
111 |
112 | }).catch(error => ...);
113 | ```
114 |
115 |
116 | ## grabFrame
117 |
118 | Gather data from the video stream into an [ImageBitmap](https://www.w3.org/TR/html51/webappapis.html#webappapis-images) object. The width and height of the ImageBitmap object are derived from the constraints of the video stream track passed to the constructor.
119 |
120 | Returns a Promise that resolves to an ImageBitmap on success, or is rejected with `DOMException` on failure.
121 |
122 | ```js
123 | captureDevice.grabFrame().then(imageBitmap => {
124 |
125 | }).catch(error => ...);
126 | ```
127 |
128 |
129 | # Compatibility
130 |
131 | The polyfill has been tested to work in current browsers:
132 |
133 | * Chrome 55+
134 | * Firefox 49+
135 | * Chrome 52+ for Android
136 | * Firefox 48+ for Android
137 |
138 | For the widest compatibility, you can additionally load the [WebRTC adapter](https://github.com/webrtc/adapter). That will expand support to:
139 |
140 | * Chrome 53
141 |
142 | For older browsers that don't support navigator.getUserMedia, you can additionally load Addy Osmani's shim with optional fallback to Flash - [getUserMedia.js](https://github.com/addyosmani/getUserMedia.js/). Alternatively, the [getUserMedia](https://github.com/otalk/getUserMedia) wrapper normalizes error handling and gives an error-first API with cross-browser support.
143 |
144 |
145 | # Development
146 |
147 | ## [yarn](https://yarnpkg.com/en/)
148 |
149 | ```sh
150 | yarn
151 | yarn run dev
152 | ```
153 |
154 | ## npm
155 |
156 | ```sh
157 | npm install
158 | npm run dev
159 | ```
160 |
161 | To [make your server accessible outside of `localhost`](https://www.npmjs.com/package/localtunnel), run npm/yarn `run lt`.
162 |
163 | Before committing, make sure you pass yarn/npm `run lint` without errors, and run yarn/npm `run docs` to generate the demo.
164 |
--------------------------------------------------------------------------------
/src/imagecapture.js:
--------------------------------------------------------------------------------
1 | /**
2 | * MediaStream ImageCapture polyfill
3 | *
4 | * @license
5 | * Copyright 2018 Google Inc.
6 | *
7 | * Licensed under the Apache License, Version 2.0 (the "License");
8 | * you may not use this file except in compliance with the License.
9 | * You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | */
19 |
20 | export let ImageCapture = window.ImageCapture;
21 |
22 | if (typeof ImageCapture === 'undefined') {
23 | ImageCapture = class {
24 |
25 | /**
26 | * TODO https://www.w3.org/TR/image-capture/#constructors
27 | *
28 | * @param {MediaStreamTrack} videoStreamTrack - A MediaStreamTrack of the 'video' kind
29 | */
30 | constructor(videoStreamTrack) {
31 | if (videoStreamTrack.kind !== 'video')
32 | throw new DOMException('NotSupportedError');
33 |
34 | this._videoStreamTrack = videoStreamTrack;
35 | if (!('readyState' in this._videoStreamTrack)) {
36 | // Polyfill for Firefox
37 | this._videoStreamTrack.readyState = 'live';
38 | }
39 |
40 | // MediaStream constructor not available until Chrome 55 - https://www.chromestatus.com/feature/5912172546752512
41 | this._previewStream = new MediaStream([videoStreamTrack]);
42 | this.videoElement = document.createElement('video');
43 | this.videoElementPlaying = new Promise(resolve => {
44 | this.videoElement.addEventListener('playing', resolve);
45 | });
46 | if (HTMLMediaElement) {
47 | this.videoElement.srcObject = this._previewStream; // Safari 11 doesn't allow use of createObjectURL for MediaStream
48 | } else {
49 | this.videoElement.src = URL.createObjectURL(this._previewStream);
50 | }
51 | this.videoElement.muted = true;
52 | this.videoElement.setAttribute('playsinline', ''); // Required by Safari on iOS 11. See https://webkit.org/blog/6784
53 | this.videoElement.play();
54 |
55 | this.canvasElement = document.createElement('canvas');
56 | // TODO Firefox has https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
57 | this.canvas2dContext = this.canvasElement.getContext('2d');
58 | }
59 |
60 | /**
61 | * https://w3c.github.io/mediacapture-image/index.html#dom-imagecapture-videostreamtrack
62 | * @return {MediaStreamTrack} The MediaStreamTrack passed into the constructor
63 | */
64 | get videoStreamTrack() {
65 | return this._videoStreamTrack;
66 | }
67 |
68 | /**
69 | * Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-getphotocapabilities
70 | * @return {Promise} Fulfilled promise with
71 | * [PhotoCapabilities](https://www.w3.org/TR/image-capture/#idl-def-photocapabilities)
72 | * object on success, rejected promise on failure
73 | */
74 | getPhotoCapabilities() {
75 | return new Promise(function executorGPC(resolve, reject) {
76 | // TODO see https://github.com/w3c/mediacapture-image/issues/97
77 | const MediaSettingsRange = {
78 | current: 0, min: 0, max: 0,
79 | };
80 | resolve({
81 | exposureCompensation: MediaSettingsRange,
82 | exposureMode: 'none',
83 | fillLightMode: 'none',
84 | focusMode: 'none',
85 | imageHeight: MediaSettingsRange,
86 | imageWidth: MediaSettingsRange,
87 | iso: MediaSettingsRange,
88 | redEyeReduction: false,
89 | whiteBalanceMode: 'none',
90 | zoom: MediaSettingsRange,
91 | });
92 | reject(new DOMException('OperationError'));
93 | });
94 | }
95 |
96 | /**
97 | * Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-setoptions
98 | * @param {Object} photoSettings - Photo settings dictionary, https://www.w3.org/TR/image-capture/#idl-def-photosettings
99 | * @return {Promise} Fulfilled promise on success, rejected promise on failure
100 | */
101 | setOptions(photoSettings = {}) {
102 | return new Promise(function executorSO(resolve, reject) {
103 | // TODO
104 | });
105 | }
106 |
107 | /**
108 | * TODO
109 | * Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-takephoto
110 | * @return {Promise} Fulfilled promise with [Blob](https://www.w3.org/TR/FileAPI/#blob)
111 | * argument on success; rejected promise on failure
112 | */
113 | takePhoto() {
114 | const self = this;
115 | return new Promise(function executorTP(resolve, reject) {
116 | // `If the readyState of the MediaStreamTrack provided in the constructor is not live,
117 | // return a promise rejected with a new DOMException whose name is "InvalidStateError".`
118 | if (self._videoStreamTrack.readyState !== 'live') {
119 | return reject(new DOMException('InvalidStateError'));
120 | }
121 | self.videoElementPlaying.then(() => {
122 | try {
123 | self.canvasElement.width = self.videoElement.videoWidth;
124 | self.canvasElement.height = self.videoElement.videoHeight;
125 | self.canvas2dContext.drawImage(self.videoElement, 0, 0);
126 | self.canvasElement.toBlob(resolve);
127 | } catch (error) {
128 | reject(new DOMException('UnknownError'));
129 | }
130 | });
131 | });
132 | }
133 |
134 | /**
135 | * Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-grabframe
136 | * @return {Promise} Fulfilled promise with
137 | * [ImageBitmap](https://www.w3.org/TR/html51/webappapis.html#webappapis-images)
138 | * argument on success; rejected promise on failure
139 | */
140 | grabFrame() {
141 | const self = this;
142 | return new Promise(function executorGF(resolve, reject) {
143 | // `If the readyState of the MediaStreamTrack provided in the constructor is not live,
144 | // return a promise rejected with a new DOMException whose name is "InvalidStateError".`
145 | if (self._videoStreamTrack.readyState !== 'live') {
146 | return reject(new DOMException('InvalidStateError'));
147 | }
148 | self.videoElementPlaying.then(() => {
149 | try {
150 | self.canvasElement.width = self.videoElement.videoWidth;
151 | self.canvasElement.height = self.videoElement.videoHeight;
152 | self.canvas2dContext.drawImage(self.videoElement, 0, 0);
153 | // TODO polyfill https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmapFactories/createImageBitmap for IE
154 | resolve(window.createImageBitmap(self.canvasElement));
155 | } catch (error) {
156 | reject(new DOMException('UnknownError'));
157 | }
158 | });
159 | });
160 | }
161 | };
162 | }
163 |
164 | window.ImageCapture = ImageCapture;
165 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 |
2 | Apache License
3 | Version 2.0, January 2004
4 | http://www.apache.org/licenses/
5 |
6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
7 |
8 | 1. Definitions.
9 |
10 | "License" shall mean the terms and conditions for use, reproduction,
11 | and distribution as defined by Sections 1 through 9 of this document.
12 |
13 | "Licensor" shall mean the copyright owner or entity authorized by
14 | the copyright owner that is granting the License.
15 |
16 | "Legal Entity" shall mean the union of the acting entity and all
17 | other entities that control, are controlled by, or are under common
18 | control with that entity. For the purposes of this definition,
19 | "control" means (i) the power, direct or indirect, to cause the
20 | direction or management of such entity, whether by contract or
21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
22 | outstanding shares, or (iii) beneficial ownership of such entity.
23 |
24 | "You" (or "Your") shall mean an individual or Legal Entity
25 | exercising permissions granted by this License.
26 |
27 | "Source" form shall mean the preferred form for making modifications,
28 | including but not limited to software source code, documentation
29 | source, and configuration files.
30 |
31 | "Object" form shall mean any form resulting from mechanical
32 | transformation or translation of a Source form, including but
33 | not limited to compiled object code, generated documentation,
34 | and conversions to other media types.
35 |
36 | "Work" shall mean the work of authorship, whether in Source or
37 | Object form, made available under the License, as indicated by a
38 | copyright notice that is included in or attached to the work
39 | (an example is provided in the Appendix below).
40 |
41 | "Derivative Works" shall mean any work, whether in Source or Object
42 | form, that is based on (or derived from) the Work and for which the
43 | editorial revisions, annotations, elaborations, or other modifications
44 | represent, as a whole, an original work of authorship. For the purposes
45 | of this License, Derivative Works shall not include works that remain
46 | separable from, or merely link (or bind by name) to the interfaces of,
47 | the Work and Derivative Works thereof.
48 |
49 | "Contribution" shall mean any work of authorship, including
50 | the original version of the Work and any modifications or additions
51 | to that Work or Derivative Works thereof, that is intentionally
52 | submitted to Licensor for inclusion in the Work by the copyright owner
53 | or by an individual or Legal Entity authorized to submit on behalf of
54 | the copyright owner. For the purposes of this definition, "submitted"
55 | means any form of electronic, verbal, or written communication sent
56 | to the Licensor or its representatives, including but not limited to
57 | communication on electronic mailing lists, source code control systems,
58 | and issue tracking systems that are managed by, or on behalf of, the
59 | Licensor for the purpose of discussing and improving the Work, but
60 | excluding communication that is conspicuously marked or otherwise
61 | designated in writing by the copyright owner as "Not a Contribution."
62 |
63 | "Contributor" shall mean Licensor and any individual or Legal Entity
64 | on behalf of whom a Contribution has been received by Licensor and
65 | subsequently incorporated within the Work.
66 |
67 | 2. Grant of Copyright License. Subject to the terms and conditions of
68 | this License, each Contributor hereby grants to You a perpetual,
69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
70 | copyright license to reproduce, prepare Derivative Works of,
71 | publicly display, publicly perform, sublicense, and distribute the
72 | Work and such Derivative Works in Source or Object form.
73 |
74 | 3. Grant of Patent License. Subject to the terms and conditions of
75 | this License, each Contributor hereby grants to You a perpetual,
76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
77 | (except as stated in this section) patent license to make, have made,
78 | use, offer to sell, sell, import, and otherwise transfer the Work,
79 | where such license applies only to those patent claims licensable
80 | by such Contributor that are necessarily infringed by their
81 | Contribution(s) alone or by combination of their Contribution(s)
82 | with the Work to which such Contribution(s) was submitted. If You
83 | institute patent litigation against any entity (including a
84 | cross-claim or counterclaim in a lawsuit) alleging that the Work
85 | or a Contribution incorporated within the Work constitutes direct
86 | or contributory patent infringement, then any patent licenses
87 | granted to You under this License for that Work shall terminate
88 | as of the date such litigation is filed.
89 |
90 | 4. Redistribution. You may reproduce and distribute copies of the
91 | Work or Derivative Works thereof in any medium, with or without
92 | modifications, and in Source or Object form, provided that You
93 | meet the following conditions:
94 |
95 | (a) You must give any other recipients of the Work or
96 | Derivative Works a copy of this License; and
97 |
98 | (b) You must cause any modified files to carry prominent notices
99 | stating that You changed the files; and
100 |
101 | (c) You must retain, in the Source form of any Derivative Works
102 | that You distribute, all copyright, patent, trademark, and
103 | attribution notices from the Source form of the Work,
104 | excluding those notices that do not pertain to any part of
105 | the Derivative Works; and
106 |
107 | (d) If the Work includes a "NOTICE" text file as part of its
108 | distribution, then any Derivative Works that You distribute must
109 | include a readable copy of the attribution notices contained
110 | within such NOTICE file, excluding those notices that do not
111 | pertain to any part of the Derivative Works, in at least one
112 | of the following places: within a NOTICE text file distributed
113 | as part of the Derivative Works; within the Source form or
114 | documentation, if provided along with the Derivative Works; or,
115 | within a display generated by the Derivative Works, if and
116 | wherever such third-party notices normally appear. The contents
117 | of the NOTICE file are for informational purposes only and
118 | do not modify the License. You may add Your own attribution
119 | notices within Derivative Works that You distribute, alongside
120 | or as an addendum to the NOTICE text from the Work, provided
121 | that such additional attribution notices cannot be construed
122 | as modifying the License.
123 |
124 | You may add Your own copyright statement to Your modifications and
125 | may provide additional or different license terms and conditions
126 | for use, reproduction, or distribution of Your modifications, or
127 | for any such Derivative Works as a whole, provided Your use,
128 | reproduction, and distribution of the Work otherwise complies with
129 | the conditions stated in this License.
130 |
131 | 5. Submission of Contributions. Unless You explicitly state otherwise,
132 | any Contribution intentionally submitted for inclusion in the Work
133 | by You to the Licensor shall be under the terms and conditions of
134 | this License, without any additional terms or conditions.
135 | Notwithstanding the above, nothing herein shall supersede or modify
136 | the terms of any separate license agreement you may have executed
137 | with Licensor regarding such Contributions.
138 |
139 | 6. Trademarks. This License does not grant permission to use the trade
140 | names, trademarks, service marks, or product names of the Licensor,
141 | except as required for reasonable and customary use in describing the
142 | origin of the Work and reproducing the content of the NOTICE file.
143 |
144 | 7. Disclaimer of Warranty. Unless required by applicable law or
145 | agreed to in writing, Licensor provides the Work (and each
146 | Contributor provides its Contributions) on an "AS IS" BASIS,
147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
148 | implied, including, without limitation, any warranties or conditions
149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
150 | PARTICULAR PURPOSE. You are solely responsible for determining the
151 | appropriateness of using or redistributing the Work and assume any
152 | risks associated with Your exercise of permissions under this License.
153 |
154 | 8. Limitation of Liability. In no event and under no legal theory,
155 | whether in tort (including negligence), contract, or otherwise,
156 | unless required by applicable law (such as deliberate and grossly
157 | negligent acts) or agreed to in writing, shall any Contributor be
158 | liable to You for damages, including any direct, indirect, special,
159 | incidental, or consequential damages of any character arising as a
160 | result of this License or out of the use or inability to use the
161 | Work (including but not limited to damages for loss of goodwill,
162 | work stoppage, computer failure or malfunction, or any and all
163 | other commercial damages or losses), even if such Contributor
164 | has been advised of the possibility of such damages.
165 |
166 | 9. Accepting Warranty or Additional Liability. While redistributing
167 | the Work or Derivative Works thereof, You may choose to offer,
168 | and charge a fee for, acceptance of support, warranty, indemnity,
169 | or other liability obligations and/or rights consistent with this
170 | License. However, in accepting such obligations, You may act only
171 | on Your own behalf and on Your sole responsibility, not on behalf
172 | of any other Contributor, and only if You agree to indemnify,
173 | defend, and hold each Contributor harmless for any liability
174 | incurred by, or claims asserted against, such Contributor by reason
175 | of your accepting any such warranty or additional liability.
176 |
177 | END OF TERMS AND CONDITIONS
178 |
179 | APPENDIX: How to apply the Apache License to your work.
180 |
181 | To apply the Apache License to your work, attach the following
182 | boilerplate notice, with the fields enclosed by brackets "[]"
183 | replaced with your own identifying information. (Don't include
184 | the brackets!) The text should be enclosed in the appropriate
185 | comment syntax for the file format. We also recommend that a
186 | file or class name and description of purpose be included on the
187 | same "printed page" as the copyright notice for easier
188 | identification within third-party archives.
189 |
190 | Copyright [yyyy] [name of copyright owner]
191 |
192 | Licensed under the Apache License, Version 2.0 (the "License");
193 | you may not use this file except in compliance with the License.
194 | You may obtain a copy of the License at
195 |
196 | http://www.apache.org/licenses/LICENSE-2.0
197 |
198 | Unless required by applicable law or agreed to in writing, software
199 | distributed under the License is distributed on an "AS IS" BASIS,
200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
201 | See the License for the specific language governing permissions and
202 | limitations under the License.
203 |
--------------------------------------------------------------------------------
/docs/bundle.js:
--------------------------------------------------------------------------------
1 | /******/ (function(modules) { // webpackBootstrap
2 | /******/ // The module cache
3 | /******/ var installedModules = {};
4 | /******/
5 | /******/ // The require function
6 | /******/ function __webpack_require__(moduleId) {
7 | /******/
8 | /******/ // Check if module is in cache
9 | /******/ if(installedModules[moduleId]) {
10 | /******/ return installedModules[moduleId].exports;
11 | /******/ }
12 | /******/ // Create a new module (and put it into the cache)
13 | /******/ var module = installedModules[moduleId] = {
14 | /******/ i: moduleId,
15 | /******/ l: false,
16 | /******/ exports: {}
17 | /******/ };
18 | /******/
19 | /******/ // Execute the module function
20 | /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);
21 | /******/
22 | /******/ // Flag the module as loaded
23 | /******/ module.l = true;
24 | /******/
25 | /******/ // Return the exports of the module
26 | /******/ return module.exports;
27 | /******/ }
28 | /******/
29 | /******/
30 | /******/ // expose the modules object (__webpack_modules__)
31 | /******/ __webpack_require__.m = modules;
32 | /******/
33 | /******/ // expose the module cache
34 | /******/ __webpack_require__.c = installedModules;
35 | /******/
36 | /******/ // identity function for calling harmony imports with the correct context
37 | /******/ __webpack_require__.i = function(value) { return value; };
38 | /******/
39 | /******/ // define getter function for harmony exports
40 | /******/ __webpack_require__.d = function(exports, name, getter) {
41 | /******/ if(!__webpack_require__.o(exports, name)) {
42 | /******/ Object.defineProperty(exports, name, {
43 | /******/ configurable: false,
44 | /******/ enumerable: true,
45 | /******/ get: getter
46 | /******/ });
47 | /******/ }
48 | /******/ };
49 | /******/
50 | /******/ // getDefaultExport function for compatibility with non-harmony modules
51 | /******/ __webpack_require__.n = function(module) {
52 | /******/ var getter = module && module.__esModule ?
53 | /******/ function getDefault() { return module['default']; } :
54 | /******/ function getModuleExports() { return module; };
55 | /******/ __webpack_require__.d(getter, 'a', getter);
56 | /******/ return getter;
57 | /******/ };
58 | /******/
59 | /******/ // Object.prototype.hasOwnProperty.call
60 | /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };
61 | /******/
62 | /******/ // __webpack_public_path__
63 | /******/ __webpack_require__.p = "";
64 | /******/
65 | /******/ // Load entry module and return exports
66 | /******/ return __webpack_require__(__webpack_require__.s = 1);
67 | /******/ })
68 | /************************************************************************/
69 | /******/ ([
70 | /* 0 */
71 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
72 |
73 | "use strict";
74 | /* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ImageCapture; });
75 | /**
76 | * MediaStream ImageCapture polyfill
77 | *
78 | * @license
79 | * Copyright 2018 Google Inc.
80 | *
81 | * Licensed under the Apache License, Version 2.0 (the "License");
82 | * you may not use this file except in compliance with the License.
83 | * You may obtain a copy of the License at
84 | *
85 | * http://www.apache.org/licenses/LICENSE-2.0
86 | *
87 | * Unless required by applicable law or agreed to in writing, software
88 | * distributed under the License is distributed on an "AS IS" BASIS,
89 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
90 | * See the License for the specific language governing permissions and
91 | * limitations under the License.
92 | */
93 |
94 | let ImageCapture = window.ImageCapture;
95 |
96 | if (typeof ImageCapture === 'undefined') {
97 | ImageCapture = class {
98 |
99 | /**
100 | * TODO https://www.w3.org/TR/image-capture/#constructors
101 | *
102 | * @param {MediaStreamTrack} videoStreamTrack - A MediaStreamTrack of the 'video' kind
103 | */
104 | constructor(videoStreamTrack) {
105 | if (videoStreamTrack.kind !== 'video')
106 | throw new DOMException('NotSupportedError');
107 |
108 | this._videoStreamTrack = videoStreamTrack;
109 | if (!('readyState' in this._videoStreamTrack)) {
110 | // Polyfill for Firefox
111 | this._videoStreamTrack.readyState = 'live';
112 | }
113 |
114 | // MediaStream constructor not available until Chrome 55 - https://www.chromestatus.com/feature/5912172546752512
115 | this._previewStream = new MediaStream([videoStreamTrack]);
116 | this.videoElement = document.createElement('video');
117 | this.videoElementPlaying = new Promise(resolve => {
118 | this.videoElement.addEventListener('playing', resolve);
119 | });
120 | if (HTMLMediaElement) {
121 | this.videoElement.srcObject = this._previewStream; // Safari 11 doesn't allow use of createObjectURL for MediaStream
122 | } else {
123 | this.videoElement.src = URL.createObjectURL(this._previewStream);
124 | }
125 | this.videoElement.muted = true;
126 | this.videoElement.setAttribute('playsinline', ''); // Required by Safari on iOS 11. See https://webkit.org/blog/6784
127 | this.videoElement.play();
128 |
129 | this.canvasElement = document.createElement('canvas');
130 | // TODO Firefox has https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
131 | this.canvas2dContext = this.canvasElement.getContext('2d');
132 | }
133 |
134 | /**
135 | * https://w3c.github.io/mediacapture-image/index.html#dom-imagecapture-videostreamtrack
136 | * @return {MediaStreamTrack} The MediaStreamTrack passed into the constructor
137 | */
138 | get videoStreamTrack() {
139 | return this._videoStreamTrack;
140 | }
141 |
142 | /**
143 | * Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-getphotocapabilities
144 | * @return {Promise} Fulfilled promise with
145 | * [PhotoCapabilities](https://www.w3.org/TR/image-capture/#idl-def-photocapabilities)
146 | * object on success, rejected promise on failure
147 | */
148 | getPhotoCapabilities() {
149 | return new Promise(function executorGPC(resolve, reject) {
150 | // TODO see https://github.com/w3c/mediacapture-image/issues/97
151 | const MediaSettingsRange = {
152 | current: 0, min: 0, max: 0,
153 | };
154 | resolve({
155 | exposureCompensation: MediaSettingsRange,
156 | exposureMode: 'none',
157 | fillLightMode: 'none',
158 | focusMode: 'none',
159 | imageHeight: MediaSettingsRange,
160 | imageWidth: MediaSettingsRange,
161 | iso: MediaSettingsRange,
162 | redEyeReduction: false,
163 | whiteBalanceMode: 'none',
164 | zoom: MediaSettingsRange,
165 | });
166 | reject(new DOMException('OperationError'));
167 | });
168 | }
169 |
170 | /**
171 | * Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-setoptions
172 | * @param {Object} photoSettings - Photo settings dictionary, https://www.w3.org/TR/image-capture/#idl-def-photosettings
173 | * @return {Promise} Fulfilled promise on success, rejected promise on failure
174 | */
175 | setOptions(photoSettings = {}) {
176 | return new Promise(function executorSO(resolve, reject) {
177 | // TODO
178 | });
179 | }
180 |
181 | /**
182 | * TODO
183 | * Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-takephoto
184 | * @return {Promise} Fulfilled promise with [Blob](https://www.w3.org/TR/FileAPI/#blob)
185 | * argument on success; rejected promise on failure
186 | */
187 | takePhoto() {
188 | const self = this;
189 | return new Promise(function executorTP(resolve, reject) {
190 | // `If the readyState of the MediaStreamTrack provided in the constructor is not live,
191 | // return a promise rejected with a new DOMException whose name is "InvalidStateError".`
192 | if (self._videoStreamTrack.readyState !== 'live') {
193 | return reject(new DOMException('InvalidStateError'));
194 | }
195 | self.videoElementPlaying.then(() => {
196 | try {
197 | self.canvasElement.width = self.videoElement.videoWidth;
198 | self.canvasElement.height = self.videoElement.videoHeight;
199 | self.canvas2dContext.drawImage(self.videoElement, 0, 0);
200 | self.canvasElement.toBlob(resolve);
201 | } catch (error) {
202 | reject(new DOMException('UnknownError'));
203 | }
204 | });
205 | });
206 | }
207 |
208 | /**
209 | * Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-grabframe
210 | * @return {Promise} Fulfilled promise with
211 | * [ImageBitmap](https://www.w3.org/TR/html51/webappapis.html#webappapis-images)
212 | * argument on success; rejected promise on failure
213 | */
214 | grabFrame() {
215 | const self = this;
216 | return new Promise(function executorGF(resolve, reject) {
217 | // `If the readyState of the MediaStreamTrack provided in the constructor is not live,
218 | // return a promise rejected with a new DOMException whose name is "InvalidStateError".`
219 | if (self._videoStreamTrack.readyState !== 'live') {
220 | return reject(new DOMException('InvalidStateError'));
221 | }
222 | self.videoElementPlaying.then(() => {
223 | try {
224 | self.canvasElement.width = self.videoElement.videoWidth;
225 | self.canvasElement.height = self.videoElement.videoHeight;
226 | self.canvas2dContext.drawImage(self.videoElement, 0, 0);
227 | // TODO polyfill https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmapFactories/createImageBitmap for IE
228 | resolve(window.createImageBitmap(self.canvasElement));
229 | } catch (error) {
230 | reject(new DOMException('UnknownError'));
231 | }
232 | });
233 | });
234 | }
235 | };
236 | }
237 |
238 | window.ImageCapture = ImageCapture;
239 |
240 |
241 | /***/ }),
242 | /* 1 */
243 | /***/ (function(module, __webpack_exports__, __webpack_require__) {
244 |
245 | "use strict";
246 | Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
247 | /* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_imagecapture__ = __webpack_require__(0);
248 | // Copyright 2017 Google Inc.
249 | //
250 | // Licensed under the Apache License, Version 2.0 (the "License");
251 | // you may not use this file except in compliance with the License.
252 | // You may obtain a copy of the License at
253 | //
254 | // http://www.apache.org/licenses/LICENSE-2.0
255 | //
256 | // Unless required by applicable law or agreed to in writing, software
257 | // distributed under the License is distributed on an "AS IS" BASIS,
258 | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
259 | // See the License for the specific language governing permissions and
260 | // limitations under the License.
261 | //
262 | ////////////////////////////////////////////////////////////////////////////////
263 |
264 | // Demo for the MediaStream ImageCapture polyfill
265 |
266 |
267 |
268 | const logElement = document.querySelector('#log');
269 |
270 | /**
271 | * Log messages to the #log element and the console
272 | * @param {*[]} messages - list of messages
273 | */
274 | function log(...messages) {
275 | console.log(...messages);
276 | const p = document.createElement('p');
277 | p.innerText = messages.join(' ');
278 | logElement.appendChild(p);
279 | }
280 |
281 | /**
282 | * Log messages to the #log element and the console as errors
283 | * @param {*} messages - list of messages
284 | */
285 | function err(...messages) {
286 | console.error(...messages);
287 | const p = document.createElement('p');
288 | p.innerText = messages.join(' ');
289 | p.style = 'color: red';
290 | logElement.appendChild(p);
291 | }
292 |
293 |
294 |
295 | let interval;
296 | const canvas = document.getElementById('frame');
297 |
298 | const photo = document.getElementById('photo');
299 | photo.addEventListener('load', function () {
300 | // After the image loads, discard the image object to release the memory
301 | window.URL.revokeObjectURL(photo.src);
302 | });
303 |
304 | let videoDevice;
305 | document.getElementById('stop').addEventListener('click', stopFunction);
306 |
307 | // Use navigator.mediaDevices.getUserMedia instead of navigator.getUserMedia, per
308 | // https://developer.mozilla.org/en-US/docs/Web/API/Navigator/getUserMedia and https://webrtc.org/web-apis/interop/
309 | // For cross-platform compatibility, we'll use the WebRTC adapter.js library
310 | navigator.mediaDevices.getUserMedia({video: true}).then(gotMedia).catch(failedToGetMedia);
311 |
312 | /**
313 | * We have a video capture device. Exercise various capturing modes.
314 | * @param {MediaStream} mediaStream
315 | */
316 | function gotMedia(mediaStream) {
317 | // Extract video track.
318 | videoDevice = mediaStream.getVideoTracks()[0];
319 | log('Using camera', videoDevice.label);
320 |
321 | const captureDevice = new __WEBPACK_IMPORTED_MODULE_0__src_imagecapture__["a" /* ImageCapture */](videoDevice, mediaStream);
322 | interval = setInterval(function () {
323 | captureDevice.grabFrame().then(processFrame).catch(error => {
324 | err((new Date()).toISOString(), 'Error while grabbing frame:', error);
325 | });
326 |
327 | captureDevice.takePhoto().then(processPhoto).catch(error => {
328 | err((new Date()).toISOString(), 'Error while taking photo:', error);
329 | });
330 | }, 300);
331 | }
332 |
333 | /**
334 | * Draw the imageBitmap returned by grabFrame() onto a canvas
335 | * @param {ImageBitmap} imageBitmap
336 | */
337 | function processFrame(imageBitmap) {
338 | canvas.width = imageBitmap.width;
339 | canvas.height = imageBitmap.height;
340 | canvas.getContext('2d').drawImage(imageBitmap, 0, 0);
341 | }
342 |
343 | /**
344 | * Set the source of the 'photo' to the blob returned by takePhoto()
345 | * @param {Blob} blob
346 | */
347 | function processPhoto(blob) {
348 | photo.src = window.URL.createObjectURL(blob);
349 | }
350 |
351 | /**
352 | * Stop frame grabbing and video capture
353 | */
354 | function stopFunction() {
355 | if (interval) clearInterval(interval); // stop frame grabbing
356 | if (videoDevice) videoDevice.stop(); // turn off the camera
357 | }
358 |
359 | /**
360 | * Handle errors
361 | * @param {Error} error
362 | */
363 | function failedToGetMedia(error) {
364 | err('getUserMedia failed:', error);
365 | stopFunction();
366 | }
367 |
368 |
369 | /***/ })
370 | /******/ ]);
--------------------------------------------------------------------------------