├── overlay └── 1.png ├── data ├── shutter.png └── camera-shutter.mp3 ├── photos ├── Selfie-2020-8-4-11-54-12.png └── Selfie-2020-8-4-12-4-37.png ├── README.md ├── js ├── canvas-toBlob.js ├── Camera_overlay.js ├── Filters.js └── FileSaver.js └── index.html /overlay/1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkhorse07232020/Selfie-with-overlay/HEAD/overlay/1.png -------------------------------------------------------------------------------- /data/shutter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkhorse07232020/Selfie-with-overlay/HEAD/data/shutter.png -------------------------------------------------------------------------------- /data/camera-shutter.mp3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkhorse07232020/Selfie-with-overlay/HEAD/data/camera-shutter.mp3 -------------------------------------------------------------------------------- /photos/Selfie-2020-8-4-11-54-12.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkhorse07232020/Selfie-with-overlay/HEAD/photos/Selfie-2020-8-4-11-54-12.png -------------------------------------------------------------------------------- /photos/Selfie-2020-8-4-12-4-37.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/darkhorse07232020/Selfie-with-overlay/HEAD/photos/Selfie-2020-8-4-12-4-37.png -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Selfie-with-overlay 2 | This project is selfie camera app with overlay. 3 | You can change the overlay Image that you want. 4 | # About this project 5 | ![No-effect](/photos/Selfie-2020-8-4-11-54-12.png) 6 | ![Grey-effect](/photos/Selfie-2020-8-4-12-4-37.png) 7 | -------------------------------------------------------------------------------- /js/canvas-toBlob.js: -------------------------------------------------------------------------------- 1 | /* canvas-toBlob.js 2 | * A canvas.toBlob() implementation. 3 | * 2016-05-26 4 | * 5 | * By Eli Grey, http://eligrey.com and Devin Samarin, https://github.com/eboyjr 6 | * License: MIT 7 | * See https://github.com/eligrey/canvas-toBlob.js/blob/master/LICENSE.md 8 | */ 9 | 10 | /*global self */ 11 | /*jslint bitwise: true, regexp: true, confusion: true, es5: true, vars: true, white: true, 12 | plusplus: true */ 13 | 14 | /*! @source http://purl.eligrey.com/github/canvas-toBlob.js/blob/master/canvas-toBlob.js */ 15 | 16 | (function(view) { 17 | "use strict"; 18 | var 19 | Uint8Array = view.Uint8Array 20 | , HTMLCanvasElement = view.HTMLCanvasElement 21 | , canvas_proto = HTMLCanvasElement && HTMLCanvasElement.prototype 22 | , is_base64_regex = /\s*;\s*base64\s*(?:;|$)/i 23 | , to_data_url = "toDataURL" 24 | , base64_ranks 25 | , decode_base64 = function(base64) { 26 | var 27 | len = base64.length 28 | , buffer = new Uint8Array(len / 4 * 3 | 0) 29 | , i = 0 30 | , outptr = 0 31 | , last = [0, 0] 32 | , state = 0 33 | , save = 0 34 | , rank 35 | , code 36 | , undef 37 | ; 38 | while (len--) { 39 | code = base64.charCodeAt(i++); 40 | rank = base64_ranks[code-43]; 41 | if (rank !== 255 && rank !== undef) { 42 | last[1] = last[0]; 43 | last[0] = code; 44 | save = (save << 6) | rank; 45 | state++; 46 | if (state === 4) { 47 | buffer[outptr++] = save >>> 16; 48 | if (last[1] !== 61 /* padding character */) { 49 | buffer[outptr++] = save >>> 8; 50 | } 51 | if (last[0] !== 61 /* padding character */) { 52 | buffer[outptr++] = save; 53 | } 54 | state = 0; 55 | } 56 | } 57 | } 58 | // 2/3 chance there's going to be some null bytes at the end, but that 59 | // doesn't really matter with most image formats. 60 | // If it somehow matters for you, truncate the buffer up outptr. 61 | return buffer; 62 | } 63 | ; 64 | if (Uint8Array) { 65 | base64_ranks = new Uint8Array([ 66 | 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1 67 | , -1, -1, 0, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 68 | , 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 69 | , -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 70 | , 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51 71 | ]); 72 | } 73 | if (HTMLCanvasElement && (!canvas_proto.toBlob || !canvas_proto.toBlobHD)) { 74 | if (!canvas_proto.toBlob) 75 | canvas_proto.toBlob = function(callback, type /*, ...args*/) { 76 | if (!type) { 77 | type = "image/png"; 78 | } if (this.mozGetAsFile) { 79 | callback(this.mozGetAsFile("canvas", type)); 80 | return; 81 | } if (this.msToBlob && /^\s*image\/png\s*(?:$|;)/i.test(type)) { 82 | callback(this.msToBlob()); 83 | return; 84 | } 85 | 86 | var 87 | args = Array.prototype.slice.call(arguments, 1) 88 | , dataURI = this[to_data_url].apply(this, args) 89 | , header_end = dataURI.indexOf(",") 90 | , data = dataURI.substring(header_end + 1) 91 | , is_base64 = is_base64_regex.test(dataURI.substring(0, header_end)) 92 | , blob 93 | ; 94 | if (Blob.fake) { 95 | // no reason to decode a data: URI that's just going to become a data URI again 96 | blob = new Blob 97 | if (is_base64) { 98 | blob.encoding = "base64"; 99 | } else { 100 | blob.encoding = "URI"; 101 | } 102 | blob.data = data; 103 | blob.size = data.length; 104 | } else if (Uint8Array) { 105 | if (is_base64) { 106 | blob = new Blob([decode_base64(data)], {type: type}); 107 | } else { 108 | blob = new Blob([decodeURIComponent(data)], {type: type}); 109 | } 110 | } 111 | callback(blob); 112 | }; 113 | 114 | if (!canvas_proto.toBlobHD && canvas_proto.toDataURLHD) { 115 | canvas_proto.toBlobHD = function() { 116 | to_data_url = "toDataURLHD"; 117 | var blob = this.toBlob(); 118 | to_data_url = "toDataURL"; 119 | return blob; 120 | } 121 | } else { 122 | canvas_proto.toBlobHD = canvas_proto.toBlob; 123 | } 124 | } 125 | }(typeof self !== "undefined" && self || typeof window !== "undefined" && window || this.content || this)); 126 | -------------------------------------------------------------------------------- /js/Camera_overlay.js: -------------------------------------------------------------------------------- 1 | function showPage() { 2 | document.getElementById("loader").style.display = "none"; 3 | document.getElementById("canvasOutput").style.display = "block"; 4 | document.getElementById("shutter_icon").style.display = "block"; 5 | document.getElementById("button_UI").style.display = "block"; 6 | document.getElementById("filter_btn").style.display = "block"; 7 | } 8 | 9 | function findGetParameter(parameterName) { 10 | let result = null, 11 | tmp = []; 12 | location.search 13 | .substr(1) 14 | .split("&") 15 | .forEach(function (item) { 16 | tmp = item.split("="); 17 | if (tmp[0] === parameterName) result = decodeURIComponent(tmp[1]); 18 | }); 19 | if (result === undefined) { 20 | result = ""; 21 | } 22 | return result; 23 | } 24 | 25 | let use_back_camera; 26 | 27 | let filters = [null, Filters.grayscale, Filters.brightness, Filters.convolute, Filters.threshold, Filters.convolute, Filters.sobel]; 28 | let filter_arg=90; 29 | let filter_arguments = [null,null, filter_arg, [1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9,1/9], filter_arg, [0,-1,0,-1,5,-1,0,-1,0], null]; 30 | let filter_in_use = 0; 31 | 32 | function filter_button() { 33 | filter_in_use = (filter_in_use + 1)%filters.length; 34 | } 35 | 36 | window.addEventListener('orientationchange', function () { 37 | document.location.reload() 38 | }); 39 | 40 | 41 | $('input[id=camid]').change(function () { 42 | if ($(this).is(':checked')) { 43 | window.location.href = document.location.origin + document.location.pathname + "?camid=back"; 44 | 45 | } else { 46 | window.location.href = document.location.origin + document.location.pathname + "?camid=front"; 47 | } 48 | }); 49 | 50 | 51 | if (findGetParameter("camid") === "front") { 52 | use_back_camera = false; 53 | document.getElementById("camid").checked = false; 54 | } 55 | else { 56 | use_back_camera = true; 57 | } 58 | const click_animation = document.getElementById("click_animation"); 59 | const audio = document.getElementById("shutter"); 60 | const canvas = document.getElementById('canvasOutput'); 61 | const context = canvas.getContext('2d'); 62 | const video = document.createElement('video'); 63 | let overlay_ready = 0; 64 | let video_ready = 0; 65 | let height = 240; 66 | let width = 320; 67 | let aspectRatio = 1; 68 | 69 | const overlay = new Image(); 70 | overlay.onload = function () { 71 | overlay_ready++; 72 | }; 73 | overlay.src = "overlay/1.png"; 74 | 75 | 76 | let readyToPlay = false; 77 | const eventNames = [ 78 | 'touchstart', 'touchend', 'touchmove', 'touchcancel', 79 | 'click', 'mousedown', 'mouseup', 'mousemove', 80 | 'keydown', 'keyup', 'keypress', 'scroll' 81 | ]; 82 | let play = function () { 83 | if (readyToPlay) { 84 | video.play(); 85 | if (!video.paused) { 86 | eventNames.forEach(function (eventName) { 87 | window.removeEventListener(eventName, play, true); 88 | }); 89 | } 90 | } 91 | }; 92 | 93 | eventNames.forEach(function (eventName) { 94 | window.addEventListener(eventName, play, true); 95 | }); 96 | 97 | const initProgress = function () { 98 | if (this.videoWidth !== 0) { 99 | aspectRatio = this.videoHeight / this.videoWidth; 100 | width = window.innerWidth; 101 | height = Math.round(width * aspectRatio); 102 | this.width = width; 103 | this.height = height; 104 | canvas.width = width; 105 | canvas.height = height; 106 | } 107 | }; 108 | let success = function (stream) { 109 | video.addEventListener('loadedmetadata', initProgress, false); 110 | video.srcObject = stream; 111 | readyToPlay = true; 112 | video.setAttribute("playsinline", ""); // Latest iOS hack to force playing without user input and to prevent fullscreen 113 | play(); // Try playing without user input, should work on non-Android Chrome 114 | video_ready++; 115 | }; 116 | 117 | navigator.getUserMedia = navigator.getUserMedia || navigator.webkitGetUserMedia || navigator.mozGetUserMedia || navigator.msGetUserMedia; 118 | navigator.mediaDevices.getUserMedia({ 119 | audio: false, 120 | video: {facingMode: use_back_camera ? "environment" : "user"} 121 | }).then(success, function (err) { 122 | console.error("An error occurred! " + err); 123 | }); 124 | 125 | function updateFrame() { 126 | if (video_ready && overlay_ready) { 127 | showPage(); 128 | context.drawImage(video, 0, 0, width, height); 129 | if (filter_in_use) { 130 | let idata = Filters.filterImage(filters[filter_in_use], canvas, filter_arguments[filter_in_use]); 131 | context.putImageData(idata, 0, 0); 132 | } 133 | const ov_width = window.innerWidth; 134 | const ov_height = ov_width * 1162 / 2048; 135 | context.drawImage(overlay, 0, height - ov_height, ov_width, ov_height); 136 | } 137 | requestAnimationFrame(updateFrame); 138 | } 139 | 140 | requestAnimationFrame(updateFrame); 141 | 142 | document.getElementById("shutter_icon").onclick = function () { 143 | click_animation.classList.add("lds-hourglass"); 144 | click_animation.style.display = "block"; 145 | audio.play(); 146 | setTimeout(function () { 147 | click_animation.classList.remove("lds-hourglass"); 148 | click_animation.style.display = "block"; 149 | }, 1200); 150 | let date = new Date(); 151 | let filename = "Selfie-" + 152 | date.getFullYear() + "-" + 153 | date.getMonth() + "-" + 154 | date.getDay() + "-" + 155 | date.getHours() + "-" + 156 | date.getMinutes() + "-" + 157 | date.getSeconds() + ".png"; 158 | canvas.toBlob(function (blob) { 159 | saveAs(blob, filename); 160 | }); 161 | }; 162 | 163 | window.onresize = function () { 164 | if (!video_ready || !overlay_ready) return; 165 | width = window.innerWidth; 166 | height = Math.round(width * aspectRatio); 167 | video.width = width; 168 | video.height = height; 169 | canvas.width = width; 170 | canvas.height = height; 171 | }; -------------------------------------------------------------------------------- /js/Filters.js: -------------------------------------------------------------------------------- 1 | Filters = {}; 2 | Filters.global_canvas = null; 3 | if (!window.Float32Array) 4 | Float32Array = Array; 5 | 6 | Filters.filterImage = function(filter, canvas, var_args) { 7 | const context = canvas.getContext('2d'); 8 | const args = [context.getImageData(0,0,canvas.width,canvas.height)]; 9 | for (let i=2; i= threshold) ? 255 : 0; 46 | d[i] = d[i+1] = d[i+2] = v 47 | } 48 | return pixels; 49 | }; 50 | 51 | Filters.tmpCanvas = document.createElement('canvas'); 52 | Filters.tmpCtx = Filters.tmpCanvas.getContext('2d'); 53 | 54 | Filters.createImageData = function(w,h) { 55 | return this.tmpCtx.createImageData(w,h); 56 | }; 57 | 58 | Filters.convolute = function(pixels, weights, opaque) { 59 | const side = Math.round(Math.sqrt(weights.length)); 60 | const halfSide = Math.floor(side / 2); 61 | const src = pixels.data; 62 | const sw = pixels.width; 63 | const sh = pixels.height; 64 | // pad output by the convolution matrix 65 | const w = sw; 66 | const h = sh; 67 | const output = Filters.createImageData(w, h); 68 | const dst = output.data; 69 | // go through the destination image pixels 70 | const alphaFac = opaque ? 1 : 0; 71 | for (let y=0; y= 0 && scy < sh && scx >= 0 && scx < sw) { 84 | const srcOff = (scy * sw + scx) * 4; 85 | const wt = weights[cy * side + cx]; 86 | r += src[srcOff] * wt; 87 | g += src[srcOff+1] * wt; 88 | b += src[srcOff+2] * wt; 89 | a += src[srcOff+3] * wt; 90 | } 91 | } 92 | } 93 | dst[dstOff] = r; 94 | dst[dstOff+1] = g; 95 | dst[dstOff+2] = b; 96 | dst[dstOff+3] = a + alphaFac*(255-a); 97 | } 98 | } 99 | return output; 100 | }; 101 | 102 | 103 | Filters.convoluteFloat32 = function(pixels, weights, opaque) { 104 | const side = Math.round(Math.sqrt(weights.length)); 105 | const halfSide = Math.floor(side / 2); 106 | 107 | const src = pixels.data; 108 | const sw = pixels.width; 109 | const sh = pixels.height; 110 | 111 | const w = sw; 112 | const h = sh; 113 | const output = { 114 | width: w, height: h, data: new Float32Array(w * h * 4) 115 | }; 116 | const dst = output.data; 117 | 118 | const alphaFac = opaque ? 1 : 0; 119 | 120 | for (let y=0; y 2 | 4 | 5 | Photo Frame App 6 | 7 | 182 | 183 | 184 |
185 | 186 | 187 | 188 | 189 | 196 | 197 | 198 | 199 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | --------------------------------------------------------------------------------