Skip to content

Commit

Permalink
2018 update. Firefox and Safari 11 on iOS compatibility. All PRs in.
Browse files Browse the repository at this point in the history
  • Loading branch information
dandv committed Jan 10, 2018
1 parent e533e5f commit 18e7db2
Show file tree
Hide file tree
Showing 10 changed files with 138 additions and 123 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
docs/bundle.js
30 changes: 15 additions & 15 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,31 +1,31 @@
module.exports = {
'env': {
'browser': true,
'es6': true
env: {
browser: true,
es6: true
},
'parserOptions': {
'sourceType': 'module',
parserOptions: {
sourceType: 'module',
},
'extends': 'google',
'rules': {
extends: 'google',
rules: {
'max-len': [ 'warn',
{ code: 130 } // 130 on GitHub, 80 on npmjs.org for README.md code blocks
],
'arrow-parens': ['error', 'as-needed'],
'space-before-function-paren': [
'error',
{
'anonymous': 'always',
'named': 'never'
anonymous: 'always',
named: 'never'
}
],
'no-negated-condition': 'warn',
'spaced-comment': ['error', 'always', { 'exceptions': ['/'] }]
'spaced-comment': ['error', 'always', { exceptions: ['/'] }]
},
'globals': {
'DOMException': false,
'MediaStream': false,
'Polymer': false,
'URL': false,
globals: {
DOMException: false,
MediaStream: false,
Polymer: false,
URL: false,
}
};
2 changes: 2 additions & 0 deletions .travis.yml
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
language: node_js
node_js:
- '9'
- '8'
- '7'
- '6'
- '5'
Expand Down
4 changes: 3 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,11 +151,13 @@ yarn
yarn run dev
```

## npm (slower)
## npm

```sh
npm install
npm run dev
```

To [make your server accessible outside of `localhost`](https://www.npmjs.com/package/localtunnel), run npm/yarn `run lt`.

Before committing, make sure you pass yarn/npm `run lint` without errors, and run yarn/npm `run docs` to generate the demo.
168 changes: 88 additions & 80 deletions docs/bundle.js
Original file line number Diff line number Diff line change
@@ -1,50 +1,52 @@
/******/ (function(modules) { // webpackBootstrap
/******/ // The module cache
/******/ var installedModules = {};

/******/
/******/ // The require function
/******/ function __webpack_require__(moduleId) {

/******/
/******/ // Check if module is in cache
/******/ if(installedModules[moduleId])
/******/ if(installedModules[moduleId]) {
/******/ return installedModules[moduleId].exports;

/******/ }
/******/ // Create a new module (and put it into the cache)
/******/ var module = installedModules[moduleId] = {
/******/ i: moduleId,
/******/ l: false,
/******/ exports: {}
/******/ };

/******/
/******/ // Execute the module function
/******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__);

/******/
/******/ // Flag the module as loaded
/******/ module.l = true;

/******/
/******/ // Return the exports of the module
/******/ return module.exports;
/******/ }


/******/
/******/
/******/ // expose the modules object (__webpack_modules__)
/******/ __webpack_require__.m = modules;

/******/
/******/ // expose the module cache
/******/ __webpack_require__.c = installedModules;

/******/ // identity function for calling harmory imports with the correct context
/******/
/******/ // identity function for calling harmony imports with the correct context
/******/ __webpack_require__.i = function(value) { return value; };

/******/ // define getter function for harmory exports
/******/
/******/ // define getter function for harmony exports
/******/ __webpack_require__.d = function(exports, name, getter) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ if(!__webpack_require__.o(exports, name)) {
/******/ Object.defineProperty(exports, name, {
/******/ configurable: false,
/******/ enumerable: true,
/******/ get: getter
/******/ });
/******/ }
/******/ };

/******/
/******/ // getDefaultExport function for compatibility with non-harmony modules
/******/ __webpack_require__.n = function(module) {
/******/ var getter = module && module.__esModule ?
Expand All @@ -53,28 +55,28 @@
/******/ __webpack_require__.d(getter, 'a', getter);
/******/ return getter;
/******/ };

/******/
/******/ // Object.prototype.hasOwnProperty.call
/******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };

/******/
/******/ // __webpack_public_path__
/******/ __webpack_require__.p = "";

/******/
/******/ // Load entry module and return exports
/******/ return __webpack_require__(__webpack_require__.s = 1);
/******/ })
/************************************************************************/
/******/ ([
/* 0 */
/***/ function(module, exports, __webpack_require__) {
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
/* harmony export (binding) */ __webpack_require__.d(exports, "a", function() { return ImageCapture; });
/* harmony export (binding) */ __webpack_require__.d(__webpack_exports__, "a", function() { return ImageCapture; });
/**
* MediaStream ImageCapture polyfill
*
* @license
* Copyright 2017 Google Inc.
* Copyright 2018 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down Expand Up @@ -112,9 +114,17 @@ if (typeof ImageCapture === 'undefined') {
// MediaStream constructor not available until Chrome 55 - https://www.chromestatus.com/feature/5912172546752512
this._previewStream = new MediaStream([videoStreamTrack]);
this.videoElement = document.createElement('video');
this.videoElement.src = URL.createObjectURL(this._previewStream);
this.videoElementPlaying = new Promise(resolve => {
this.videoElement.addEventListener('playing', resolve);
});
if (HTMLMediaElement) {
this.videoElement.srcObject = this._previewStream; // Safari 11 doesn't allow use of createObjectURL for MediaStream
} else {
this.videoElement.src = URL.createObjectURL(this._previewStream);
}
this.videoElement.muted = true;
this.videoElement.play(); // required by Firefox
this.videoElement.setAttribute('playsinline', ''); // Required by Safari on iOS 11. See https://webkit.org/blog/6784
this.videoElement.play();

this.canvasElement = document.createElement('canvas');
// TODO Firefox has https://developer.mozilla.org/en-US/docs/Web/API/OffscreenCanvas
Expand All @@ -131,12 +141,14 @@ if (typeof ImageCapture === 'undefined') {

/**
* Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-getphotocapabilities
* @return {Promise<PhotoCapabilities>} Fulfilled promise with [PhotoCapabilities](https://www.w3.org/TR/image-capture/#idl-def-photocapabilities) object on success, rejected promise on failure
* @return {Promise<PhotoCapabilities>} Fulfilled promise with
* [PhotoCapabilities](https://www.w3.org/TR/image-capture/#idl-def-photocapabilities)
* object on success, rejected promise on failure
*/
getPhotoCapabilities() {
return new Promise(function executorGPC(resolve, reject) {
// TODO see https://github.com/w3c/mediacapture-image/issues/97
let MediaSettingsRange = {
const MediaSettingsRange = {
current: 0, min: 0, max: 0,
};
resolve({
Expand Down Expand Up @@ -169,75 +181,71 @@ if (typeof ImageCapture === 'undefined') {
/**
* TODO
* Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-takephoto
* @return {Promise<Blob>} Fulfilled promise with [Blob](https://www.w3.org/TR/FileAPI/#blob) argument on success; rejected promise on failure
* @return {Promise<Blob>} Fulfilled promise with [Blob](https://www.w3.org/TR/FileAPI/#blob)
* argument on success; rejected promise on failure
*/
takePhoto() {
let self = this;
const self = this;
return new Promise(function executorTP(resolve, reject) {
// `If the readyState of the MediaStreamTrack provided in the constructor is not live,
// return a promise rejected with a new DOMException whose name is "InvalidStateError".`
if (self._videoStreamTrack.readyState === 'live') {
// -- however, checking for `live` alone doesn't guarantee the video is ready
if (self.videoElement.videoWidth) {
try {
self.canvasElement.width = self.videoElement.videoWidth;
self.canvasElement.height = self.videoElement.videoHeight;
self.canvas2dContext.drawImage(self.videoElement, 0, 0);
self.canvasElement.toBlob(blob => {
resolve(blob);
});
} catch (error) {
reject(new DOMException('UnknownError'));
}
} else {
if (self._videoStreamTrack.readyState !== 'live') {
return reject(new DOMException('InvalidStateError'));
}
self.videoElementPlaying.then(() => {
try {
self.canvasElement.width = self.videoElement.videoWidth;
self.canvasElement.height = self.videoElement.videoHeight;
self.canvas2dContext.drawImage(self.videoElement, 0, 0);
self.canvasElement.toBlob(resolve);
} catch (error) {
reject(new DOMException('UnknownError'));
}
} else {
reject(new DOMException('InvalidStateError'));
}
});
});
}

/**
* Implements https://www.w3.org/TR/image-capture/#dom-imagecapture-grabframe
* @return {Promise<ImageBitmap>} Fulfilled promise with [ImageBitmap](https://www.w3.org/TR/html51/webappapis.html#webappapis-images) argument on success; rejected promise on failure
* @return {Promise<ImageBitmap>} Fulfilled promise with
* [ImageBitmap](https://www.w3.org/TR/html51/webappapis.html#webappapis-images)
* argument on success; rejected promise on failure
*/
grabFrame() {
let self = this;
const self = this;
return new Promise(function executorGF(resolve, reject) {
if (self._videoStreamTrack.readyState === 'live') {
if (self.videoElement.videoWidth) {
try {
// videoWidth is available after videoElement.onloadedmetadata fires
self.canvasElement.width = self.videoElement.videoWidth;
self.canvasElement.height = self.videoElement.videoHeight;
// The video has an image after videoElement.oncanplay triggers
self.canvas2dContext.drawImage(self.videoElement, 0, 0);
// TODO polyfill https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmapFactories/createImageBitmap for IE
resolve(window.createImageBitmap(self.canvasElement));
} catch (error) {
reject(new DOMException('UnknownError'));
}
} else {
// `If the readyState of the MediaStreamTrack provided in the constructor is not live,
// return a promise rejected with a new DOMException whose name is "InvalidStateError".`
if (self._videoStreamTrack.readyState !== 'live') {
return reject(new DOMException('InvalidStateError'));
}
self.videoElementPlaying.then(() => {
try {
self.canvasElement.width = self.videoElement.videoWidth;
self.canvasElement.height = self.videoElement.videoHeight;
self.canvas2dContext.drawImage(self.videoElement, 0, 0);
// TODO polyfill https://developer.mozilla.org/en-US/docs/Web/API/ImageBitmapFactories/createImageBitmap for IE
resolve(window.createImageBitmap(self.canvasElement));
} catch (error) {
reject(new DOMException('UnknownError'));
}
} else {
reject(new DOMException('InvalidStateError'));
}
});
});
}

};
}

window.ImageCapture = ImageCapture;


/***/ },
/***/ }),
/* 1 */
/***/ function(module, exports, __webpack_require__) {
/***/ (function(module, __webpack_exports__, __webpack_require__) {

"use strict";
Object.defineProperty(__webpack_exports__, "__esModule", { value: true });
/* harmony import */ var __WEBPACK_IMPORTED_MODULE_0__src_imagecapture__ = __webpack_require__(0);
// Copyright 2016 Google Inc.
// Copyright 2017 Google Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
Expand All @@ -255,17 +263,17 @@ if (typeof ImageCapture === 'undefined') {

// Demo for the MediaStream ImageCapture polyfill

'use strict';

let logElement = document.querySelector('#log');

const logElement = document.querySelector('#log');

/**
* Log messages to the #log element and the console
* @param {*[]} messages - list of messages
*/
function log(...messages) {
console.log(...messages);
let p = document.createElement('p');
const p = document.createElement('p');
p.innerText = messages.join(' ');
logElement.appendChild(p);
}
Expand All @@ -276,7 +284,7 @@ function log(...messages) {
*/
function err(...messages) {
console.error(...messages);
let p = document.createElement('p');
const p = document.createElement('p');
p.innerText = messages.join(' ');
p.style = 'color: red';
logElement.appendChild(p);
Expand All @@ -285,9 +293,9 @@ function err(...messages) {


let interval;
let canvas = document.getElementById('frame');
const canvas = document.getElementById('frame');

let photo = document.getElementById('photo');
const photo = document.getElementById('photo');
photo.addEventListener('load', function () {
// After the image loads, discard the image object to release the memory
window.URL.revokeObjectURL(photo.src);
Expand All @@ -310,7 +318,7 @@ function gotMedia(mediaStream) {
videoDevice = mediaStream.getVideoTracks()[0];
log('Using camera', videoDevice.label);

let captureDevice = new __WEBPACK_IMPORTED_MODULE_0__src_imagecapture__["a" /* ImageCapture */](videoDevice, mediaStream);
const captureDevice = new __WEBPACK_IMPORTED_MODULE_0__src_imagecapture__["a" /* ImageCapture */](videoDevice, mediaStream);
interval = setInterval(function () {
captureDevice.grabFrame().then(processFrame).catch(error => {
err((new Date()).toISOString(), 'Error while grabbing frame:', error);
Expand Down Expand Up @@ -358,5 +366,5 @@ function failedToGetMedia(error) {
}


/***/ }
/***/ })
/******/ ]);
2 changes: 1 addition & 1 deletion docs/index.css
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright 2016 Google Inc.
* Copyright 2018 Google Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand Down
Loading

0 comments on commit 18e7db2

Please sign in to comment.