├── README.md ├── chroma-demo.css ├── chroma-demo.html ├── chroma-demo.js ├── chroma-video.css ├── chroma-video.html └── chroma-video.js /README.md: -------------------------------------------------------------------------------- 1 | HTML5 Chroma Key 2 | ============== 3 | 4 | Green screen effect with HTML5 and JavaScript. 5 | 6 | Modified from Metia Labs, Mark Mower 7 | http://www.metia.com/london/mark-mower/2012/12/building-an-html5-green-screen-(chroma-key)-dynamic-video-player/. 8 | 9 | Use the canvas tag and JavaScript to isolate a subject by removing green pixels from a green screen video. 10 | 11 | chroma-demo files employ a generic website template (Bootstrap) as a background. Any site interaction is currently unavailable due to the overlaid canvas, but the canvas video can be set to a timer, or tied to event handlers. View result here: http://sharon-kasper.com/sharon/chroma/chroma-test.html 12 | 13 | chroma-video files employ a full-sized video as the background, to demo use of two videos. Background images can also be used in place of background videos. 14 | -------------------------------------------------------------------------------- /chroma-demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family:Verdana; 3 | font-size:12px; 4 | } 5 | h1 { 6 | font-size:14px; 7 | font-weight:bold; 8 | } 9 | canvas { 10 | position: fixed; 11 | top: 0; 12 | bottom: 0; 13 | left: 0; 14 | right: 0; 15 | width: 100%; 16 | height: 100%; 17 | z-index: 1050; 18 | } 19 | #source { 20 | display: none; 21 | } 22 | -------------------------------------------------------------------------------- /chroma-demo.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | HTML 5 Chroma Key 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 34 | 35 |
36 | 37 |
38 |
39 |

40 | 41 |

42 |
43 |

Your typical webpage, here

44 |

This is an example to show the potential of an offcanvas layout pattern in Bootstrap. Try some responsive-range viewport sizes to see it in action.

45 |
46 |
47 |
48 |

Heading

49 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

50 |

View details »

51 |
52 |
53 |

Heading

54 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

55 |

View details »

56 |
57 |
58 |

Heading

59 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

60 |

View details »

61 |
62 |
63 |

Heading

64 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

65 |

View details »

66 |
67 |
68 |

Heading

69 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

70 |

View details »

71 |
72 |
73 |

Heading

74 |

Donec id elit non mi porta gravida at eget metus. Fusce dapibus, tellus ac cursus commodo, tortor mauris condimentum nibh, ut fermentum massa justo sit amet risus. Etiam porta sem malesuada magna mollis euismod. Donec sed odio dui.

75 |

View details »

76 |
77 |
78 |
79 | 80 | 97 |
98 | 99 |
100 | 101 | 104 | 105 |
106 | 107 |
108 |
109 | 110 | 111 |

Sorry your browser does not support HTML5

112 |
113 |
114 |
115 | 119 |
120 |
121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /chroma-demo.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function draw() { 4 | if (window.requestAnimationFrame) window.requestAnimationFrame(draw); 5 | // IE implementation 6 | else if (window.msRequestAnimationFrame) window.msRequestAnimationFrame(draw); 7 | // Firefox implementation 8 | else if (window.mozRequestAnimationFrame) window.mozRequestAnimationFrame(draw); 9 | // Chrome implementation 10 | else if (window.webkitRequestAnimationFrame) window.webkitRequestAnimationFrame(draw); 11 | // Other browsers that do not yet support feature 12 | else setTimeout(draw, 16.7); 13 | DrawVideoOnCanvas(); 14 | } 15 | 16 | 17 | 18 | function DrawVideoOnCanvas() { 19 | var object = document.getElementById("videodata") 20 | var width = object.width; 21 | var height = object.height; 22 | var canvas = document.getElementById("videoscreen"); 23 | canvas.setAttribute('width', width); 24 | canvas.setAttribute('height', height); 25 | if (canvas.getContext) { 26 | var context = canvas.getContext('2d'); 27 | context.drawImage(object, 0, 0, width, height); 28 | imgDataNormal = context.getImageData(0, 0, width, height); 29 | var imgData = context.createImageData(width, height); 30 | 31 | for (i = 0; i < imgData.width * imgData.height * 4; i += 4) { 32 | var r = imgDataNormal.data[i + 0]; 33 | var g = imgDataNormal.data[i + 1]; 34 | var b = imgDataNormal.data[i + 2]; 35 | var a = imgDataNormal.data[i + 3]; 36 | // set rgb levels for green and set alphachannel to 0; 37 | selectedR = 110; 38 | selectedG = 154; 39 | selectedB = 90; 40 | if (r <= selectedR && g >= selectedG && b >= selectedB) { 41 | a = 0; 42 | } 43 | if (a != 0) { 44 | imgData.data[i + 0] = r; 45 | imgData.data[i + 1] = g; 46 | imgData.data[i + 2] = b; 47 | imgData.data[i + 3] = a; 48 | } 49 | } 50 | // For image anti-aliasing 51 | for (var y = 0; y < imgData.height; y++) { 52 | for (var x = 0; x < imgData.width; x++) { 53 | var r = imgData.data[((imgData.width * y) + x) * 4]; 54 | var g = imgData.data[((imgData.width * y) + x) * 4 + 1]; 55 | var b = imgData.data[((imgData.width * y) + x) * 4 + 2]; 56 | var a = imgData.data[((imgData.width * y) + x) * 4 + 3]; 57 | if (imgData.data[((imgData.width * y) + x) * 4 + 3] != 0) { 58 | offsetYup = y - 1; 59 | offsetYdown = y + 1; 60 | offsetXleft = x - 1; 61 | offsetxRight = x + 1; 62 | var change = false; 63 | if (offsetYup > 0) { 64 | if (imgData.data[((imgData.width * (y - 1)) + (x)) * 4 + 3] == 0) { 65 | change = true; 66 | } 67 | } 68 | if (offsetYdown < imgData.height) { 69 | if (imgData.data[((imgData.width * (y + 1)) + (x)) * 4 + 3] == 0) { 70 | change = true; 71 | } 72 | } 73 | if (offsetXleft > -1) { 74 | if (imgData.data[((imgData.width * y) + (x - 1)) * 4 + 3] == 0) { 75 | change = true; 76 | } 77 | } 78 | if (offsetxRight < imgData.width) { 79 | if (imgData.data[((imgData.width * y) + (x + 1)) * 4 + 3] == 0) { 80 | change = true; 81 | } 82 | } 83 | } 84 | } 85 | } 86 | context.putImageData(imgData, 0, 0); 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /chroma-video.css: -------------------------------------------------------------------------------- 1 | body { 2 | font-family:Verdana; 3 | font-size:12px; 4 | } 5 | h1 { 6 | font-size:14px; 7 | font-weight:bold; 8 | } 9 | canvas { 10 | position: absolute; 11 | top: 0; 12 | bottom: 0; 13 | left: 0; 14 | right: 0; 15 | width: 100%; 16 | height: 100%; 17 | } 18 | #source { 19 | position: absolute; 20 | bottom: 0; 21 | right: 0; 22 | padding:4px 10px 4px 10px; 23 | } 24 | .clearfix:before, .clearfix:after { 25 | content:'\0020'; 26 | display: block; 27 | overflow: hidden; 28 | visibility: hidden; 29 | width: 0; 30 | height: 0; 31 | } 32 | .clearfix { 33 | zoom: 1; 34 | } 35 | video, canvas { 36 | border: 1px solid #000; 37 | } 38 | -------------------------------------------------------------------------------- /chroma-video.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HTML 5 Chroma Key 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 |
15 |
16 |

Canvas output

17 | 18 |

Sorry your browser does not support HTML5

19 |
20 |
21 |
22 | 26 |
27 | 32 |
33 | 34 | 35 | 36 | -------------------------------------------------------------------------------- /chroma-video.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | function draw() { 4 | if (window.requestAnimationFrame) window.requestAnimationFrame(draw); 5 | // IE implementation 6 | else if (window.msRequestAnimationFrame) window.msRequestAnimationFrame(draw); 7 | // Firefox implementation 8 | else if (window.mozRequestAnimationFrame) window.mozRequestAnimationFrame(draw); 9 | // Chrome implementation 10 | else if (window.webkitRequestAnimationFrame) window.webkitRequestAnimationFrame(draw); 11 | // Other browsers that do not yet support feature 12 | else setTimeout(draw, 16.7); 13 | DrawVideoOnCanvas(); 14 | } 15 | 16 | 17 | 18 | function DrawVideoOnCanvas() { 19 | var object = document.getElementById("videodata") 20 | var backgroundObject = document.getElementById("videoBackgrounddata"); 21 | var width = object.width; 22 | var height = object.height; 23 | var canvas = document.getElementById("videoscreen"); 24 | canvas.setAttribute('width', width); 25 | canvas.setAttribute('height', height); 26 | if (canvas.getContext) { 27 | var context = canvas.getContext('2d'); 28 | context.drawImage(backgroundObject, 0, 0, width, height); 29 | var imgBackgroundData = context.getImageData(0, 0, width, height); 30 | context.drawImage(object, 0, 0, width, height); 31 | imgDataNormal = context.getImageData(0, 0, width, height); 32 | var imgData = context.createImageData(width, height); 33 | 34 | for (i = 0; i < imgData.width * imgData.height * 4; i += 4) { 35 | var r = imgDataNormal.data[i + 0]; 36 | var g = imgDataNormal.data[i + 1]; 37 | var b = imgDataNormal.data[i + 2]; 38 | var a = imgDataNormal.data[i + 3]; 39 | // set rgb levels for green and set alphachannel to 0; 40 | selectedR = 110; 41 | selectedG = 154; 42 | selectedB = 90; 43 | if (r <= selectedR && g >= selectedG && b >= selectedB) { 44 | a = 0; 45 | } 46 | if (a != 0) { 47 | imgData.data[i + 0] = r; 48 | imgData.data[i + 1] = g; 49 | imgData.data[i + 2] = b; 50 | imgData.data[i + 3] = a; 51 | } 52 | } 53 | // For image anti-aliasing 54 | for (var y = 0; y < imgData.height; y++) { 55 | for (var x = 0; x < imgData.width; x++) { 56 | var r = imgData.data[((imgData.width * y) + x) * 4]; 57 | var g = imgData.data[((imgData.width * y) + x) * 4 + 1]; 58 | var b = imgData.data[((imgData.width * y) + x) * 4 + 2]; 59 | var a = imgData.data[((imgData.width * y) + x) * 4 + 3]; 60 | if (imgData.data[((imgData.width * y) + x) * 4 + 3] != 0) { 61 | offsetYup = y - 1; 62 | offsetYdown = y + 1; 63 | offsetXleft = x - 1; 64 | offsetxRight = x + 1; 65 | var change = false; 66 | if (offsetYup > 0) { 67 | if (imgData.data[((imgData.width * (y - 1)) + (x)) * 4 + 3] == 0) { 68 | change = true; 69 | } 70 | } 71 | if (offsetYdown < imgData.height) { 72 | if (imgData.data[((imgData.width * (y + 1)) + (x)) * 4 + 3] == 0) { 73 | change = true; 74 | } 75 | } 76 | if (offsetXleft > -1) { 77 | if (imgData.data[((imgData.width * y) + (x - 1)) * 4 + 3] == 0) { 78 | change = true; 79 | } 80 | } 81 | if (offsetxRight < imgData.width) { 82 | if (imgData.data[((imgData.width * y) + (x + 1)) * 4 + 3] == 0) { 83 | change = true; 84 | } 85 | } 86 | if (change) { 87 | var gray = (imgData.data[((imgData.width * y) + x) * 4 + 0] * .393) + (imgData.data[((imgData.width * y) + x) * 4 + 1] * .769) + (imgData.data[((imgData.width * y) + x) * 4 + 2] * .189); 88 | imgData.data[((imgData.width * y) + x) * 4] = (gray * 0.2) + (imgBackgroundData.data[((imgData.width * y) + x) * 4] * 0.9); 89 | imgData.data[((imgData.width * y) + x) * 4 + 1] = (gray * 0.2) + (imgBackgroundData.data[((imgData.width * y) + x) * 4 + 1] * 0.9); 90 | imgData.data[((imgData.width * y) + x) * 4 + 2] = (gray * 0.2) + (imgBackgroundData.data[((imgData.width * y) + x) * 4 + 2] * 0.9); 91 | imgData.data[((imgData.width * y) + x) * 4 + 3] = 255; 92 | } 93 | } 94 | 95 | } 96 | } 97 | 98 | for (i = 0; i < imgData.width * imgData.height * 4; i += 4) { 99 | var r = imgData.data[i + 0]; 100 | var g = imgData.data[i + 1]; 101 | var b = imgData.data[i + 2]; 102 | var a = imgData.data[i + 3]; 103 | if (a == 0) { 104 | imgData.data[i + 0] = imgBackgroundData.data[i + 0]; 105 | imgData.data[i + 1] = imgBackgroundData.data[i + 1]; 106 | imgData.data[i + 2] = imgBackgroundData.data[i + 2]; 107 | imgData.data[i + 3] = imgBackgroundData.data[i + 3]; 108 | } 109 | } 110 | context.putImageData(imgData, 0, 0); 111 | 112 | } 113 | } 114 | --------------------------------------------------------------------------------