<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<meta content="stuff, to, help, search, engines, not" name="keywords">
<meta content="What this page is about." name="description">
<meta content="Display Webcam Stream" name="title">
<title>Display Webcam Stream - Thanks to https://www.kirupa.com/html5/accessing_your_webcam_in_html5.htm and https://software.intel.com/en-us/html5/hub/blogs/using-the-getusermedia-api-with-the-html5-video-and-canvas-elements and https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas</title>

<style>
#container {
margin: 0px auto;
width: 500px;
height: 375px;
border: 10px #333 solid;
}
#videoElement {
width: 500px;
height: 375px;
background-color: #666;
}
video {
position:absolute;
visibility:hidden;
}
</style>
</head>

<body style='background-color:#f0f0f0;'>
<h1>Display Webcam Stream <span id='sosad'></span><h1>
<h3>Thanks to <a target=_blank title='https://www.kirupa.com/html5/accessing_your_webcam_in_html5.htm' href='https://www.kirupa.com/html5/accessing_your_webcam_in_html5.htm'>www.kirupa.com</a> and <a target=_blank title='https://software.intel.com/en-us/html5/hub/blogs/using-the-getusermedia-api-with-the-html5-video-and-canvas-elements' href='https://software.intel.com/en-us/html5/hub/blogs/using-the-getusermedia-api-with-the-html5-video-and-canvas-elements'>software.intel.com</a> and <a target=_blank href='https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas' title='https://developer.mozilla.org/en-US/docs/Web/API/Canvas_API/Tutorial/Pixel_manipulation_with_canvas'>developer.mozilla.org</a> and <a target=_blank href='http://stackoverflow.com/questions/3129099/how-to-flip-images-horizontally-with-html5' title='http://stackoverflow.com/questions/3129099/how-to-flip-images-horizontally-with-html5'>stackoverflow.com</a> and <a target=_blank href='https://www.html5rocks.com/en/tutorials/getusermedia/intro/' title='https://www.html5rocks.com/en/tutorials/getusermedia/intro/'>html5rocks.com</a> - RJM Programming - April, 2017 <span id='errmsg'></span></h3>
<div id="container">
<video autoplay='true' id='videoElement'></video>
<table><tr><td><canvas id='canvasElement'></canvas></td><td><canvas id='zoom' width=200 height=200></canvas></td></tr></table>
<button id='grey'>Toggle Greyness</button> <button id='invert'>Toggle Colour Inversion</button> Enable image smoothing: <input type='checkbox' id='smoothbtn'></input><br>
Auto Flip New Items: <input onchange='always_horizontally_flip=this.checked;' type='checkbox' id='autoflip'></input> Flop: <input onchange='always_horizontally_flop=this.checked;' type='checkbox' id='autoflop'></input> Rotation (degrees): <input style='width:80px;' type=number onblur='rotis=this.value;' onchange='rotis=this.value;' min='-360' max='360' value='0' step='1'></input> <div id='colour'>Canvas Colour</div><br>
<!--span><button id='email' title='Have ready a Copy of your Webcam via relevant Right Click or Two Finger Gesture'>Email</button> <input title='Have ready a Copy of your Webcam via relevant Right Click or Two Finger Gesture' type='text' id='emailee' value=''></input></span-->
</div>

<br><br><br><br><br><br><script>

var xx=-1, yy=-1, ww=1, hh=1;
var rotis=0, always_horizontally_flip=false, always_horizontally_flop=false;

var isStreaming = false,
v = document.getElementById('videoElement'),
c = document.getElementById('canvasElement'),
grey = document.getElementById('grey');
invert = document.getElementById('invert');
con = c.getContext('2d');
w = 600,
h = 420,
invertit = false,
greyscale = false;

v.addEventListener('canplay', function(e) {
if (!isStreaming) {
// videoWidth isn't always set correctly in all browsers
if (v.videoWidth > 0) h = v.videoHeight / (v.videoWidth / w);
c.setAttribute('width', w);
c.setAttribute('height', h);
// Reverse the canvas image
con.translate(w, 0);
con.scale(-1, 1);
isStreaming = true;
}
}, false);

function dImage(img, x, y, width, height, deg, flip, flop, center) { // thanks to http://stackoverflow.com/questions/3129099/how-to-flip-images-horizontally-with-html5

con.save();

if (typeof width === "undefined") width = img.width;
if (typeof height === "undefined") height = img.height;
if (typeof center === "undefined") center = false;

// Set rotation point to center of image, instead of top/left
if (center) {
x -= width/2;
y -= height/2;
}

// Set the origin to the center of the image
con.translate(x + width/2, y + height/2);

// Rotate the canvas around the origin
var rad = 2 * Math.PI - deg * Math.PI / 180;
con.rotate(rad);

// Flip/flop the canvas
if (flip) {
flipScale = -1;
//document.title='flipping out';
} else {
flipScale = 1;
}
if (flop) {
flopScale = -1;
//document.title='flopping out';
} else {
flopScale = 1;
//document.title='flopping in';
}
con.scale(flipScale, flopScale);

// Draw the image
con.drawImage(img, -width/2, -height/2, width, height);

con.restore();
}

v.addEventListener('play', function() {
// Every 33 milliseconds copy the video image to the canvas
//video.style.visibility = 'hidden';
setInterval(function() {
if (v.paused || v.ended) return;
con.fillRect(0, 0, w, h);
if (always_horizontally_flip || rotis != 0 || always_horizontally_flop) {
dImage(v, 0, 0, w, h, rotis, always_horizontally_flip, always_horizontally_flop);
} else {
con.drawImage(v, 0, 0, w, h);
}
pixelValue();
if (greyscale) goingGrey();
if (invertit) invert();
}, 33);
}, false);

grey.addEventListener('click', function() { greyscale = !greyscale; }, false);
invert.addEventListener('click', function() { invertit = !invertit; }, false);

var goingGrey = function() {
var imageData = con.getImageData(0, 0, w, h);
var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
var bright = 0.34 * data[i] + 0.5 * data[i + 1] + 0.16 * data[i + 2];
data[i] = bright;
data[i + 1] = bright;
data[i + 2] = bright;
}
con.putImageData(imageData, 0, 0);
}

var invert = function() {
var imageData = con.getImageData(0, 0, w, h);
var data = imageData.data;
for (var i = 0; i < data.length; i += 4) {
data[i] = 255 - data[i]; // red
data[i + 1] = 255 - data[i + 1]; // green
data[i + 2] = 255 - data[i + 2]; // blue
}
con.putImageData(imageData, 0, 0);
};

var pixelValue = function() {
if (xx >= 0 && yy >= 0) {
//document.title=xx + ' AND ' + yy;
var xpixel = con.getImageData(xx, yy, ww, hh);
var xdata = xpixel.data;
var xrgba = 'rgba(' + xdata[0] + ', ' + xdata[1] +
', ' + xdata[2] + ', ' + (xdata[3] / 255) + ')';
//document.title=xrgba + ' ' + xx + ' AND ' + yy;
colour.style.background = xrgba;
colour.innerHTML = 'Canvas Colour ' + xrgba;
}
}


var colour = document.getElementById('colour');
function pick(event) {
var x = event.layerX;
var y = event.layerY;
xx=x;
yy=y;
//document.title=x + ' and ' + y;
var pixel = con.getImageData(x, y, 1, 1);
var data = pixel.data;
var rgba = 'rgba(' + data[0] + ', ' + data[1] +
', ' + data[2] + ', ' + (data[3] / 255) + ')';
colour.style.background = rgba;
colour.textContent = 'Canvas Colour ' + rgba;
}
//c.addEventListener('mousemove', pick);
var zoomctx = document.getElementById('zoom').getContext('2d');

var smoothbtn = document.getElementById('smoothbtn');
smoothbtn.addEventListener('onchange', function() { toggleSmoothing(); }, false);

var toggleSmoothing = function(event) {
zoomctx.imageSmoothingEnabled = this.checked;
zoomctx.mozImageSmoothingEnabled = this.checked;
zoomctx.webkitImageSmoothingEnabled = this.checked;
zoomctx.msImageSmoothingEnabled = this.checked;
};
smoothbtn.addEventListener('change', toggleSmoothing);

var zoom = function(event) {
var x = event.layerX;
var y = event.layerY;
xx=x;
yy=y;
zoomctx.drawImage(c,
Math.abs(x - 5),
Math.abs(y - 5),
10, 10,
0, 0,
200, 200);
};

c.addEventListener('mousemove', zoom);

var video = document.querySelector("#videoElement");

navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia || navigator.oGetUserMedia;

setTimeout(invertclick,1000);

if (navigator.getUserMedia) {
navigator.getUserMedia({video: true, audio: true}, handleVideo, videoError);
} else {
video.type = "video/mp4";
video.loop = true;
video.autoplay = true;
video.controls = true;
video.src = 'webcamtest.m4v';
video.style.visibility = 'visible';
document.getElementById('errmsg').innerHTML = "So sad, cannot work the 'navigator.getUserMedia({video: true, audio: true}, handleVideo, videoError)' Javascript call we require. But you can see the blog posting's video on a loop (well, it worked in <a onclick=putOnSpeed(); style=text-decoration:underline;cursor:pointer;>Speed</a>) that for best viewing should be <a style=text-decoration:underline;cursor:pointer; onclick=document.getElementById('autoflip').click();>flipped</a>.";
document.getElementById('sosad').innerHTML = " (would have been nice ... but ...)";
setTimeout(andno,4000);
}

function andno() {
video.style.visibility = 'hidden';
}

function invertclick() {
if (!invertit) {
document.getElementById('invert').click();
setTimeout(invertclick, 1500);
} else {
document.getElementById('invert').click();
}
}

function handleVideo(stream) {
video.src = window.URL.createObjectURL(stream);
}

function videoError(e) {
// do something
alert("Sorry, cannot work the 'navigator.getUserMedia({video: true, audio: true}, handleVideo, videoError)' Javascript call we require.");
}

function putOnSpeed() {
document.getElementById('speed').innerHTML = '<iframe src="https://www.rjmprogramming.com.au/HTMLCSS/karaoke_youtube_api.htm?youtubeid=dB77R4Ro59o&youtube_duration=5681.041&email=&email=&emoji=on&c0=on&i0=4271&j0=4655&i1=&j1=&i2=&j2=&i3=&j3=&i4=&j4=&i5=&j5=&i6=&j6=&i7=&j7=&i8=&j8=&i9=&j9=&i10=&j10=&i11=&j11=&i12=&j12=&i13=&j13=&i14=&j14=&i15=&j15=&i16=&j16=&i17=&j17=&i18=&j18=&i19=&j19=&i20=&j20=&i21=&j21=&i22=&j22=&i23=&j23=&i24=&j24=&i25=&j25=&i26=&j26=&i27=&j27=&i28=&j28=&i29=&j29=" style=height:800px;width:100%; id=ispeed></iframe>';
location.href='#speed';
}
</script>
<br><div id=speed></div>
</body>
</html>