diff --git a/files.html b/files.html index 2078f41bdf04e7f9a48c316c2d9425fc8e105594..b9ad79c6fb81b7752a4ebb8e14e94ed4aa1b1b6c 100644 --- a/files.html +++ b/files.html @@ -42,6 +42,7 @@ <a href='./modules/control/slider'>slider</a><br> <i> convert</i><br> <i> rgba</i><br> + <a href='./modules/convert/rgba/jpg'>jpg</a><br> <a href='./modules/convert/rgba/png'>png</a><br> <i> svg</i><br> <a href='./modules/convert/svg/array'>array</a><br> diff --git a/modules/convert/rgba/jpg b/modules/convert/rgba/jpg new file mode 100755 index 0000000000000000000000000000000000000000..ce1c443a223c45910fe84b2ed4a8e7b3435be310 --- /dev/null +++ b/modules/convert/rgba/jpg @@ -0,0 +1,173 @@ +// +// convert rgba jpg +// +// Neil Gershenfeld +// (c) Massachusetts Institute of Technology 2017 +// +// This work may be reproduced, modified, distributed, performed, and +// displayed for any purpose, but must acknowledge the mods +// project. Copyright is retained and must be preserved. The work is +// provided as is; no warranty is provided, and users accept all +// liability. +// +// closure +// +(function(){ +// +// module globals +// +var mod = {} +// +// name +// +var name = 'convert RGBA to JPG' +// +// initialization +// +var init = function() { + mod.name.value = "file.jpg" + mod.compress.value = .75 + } +// +// inputs +// +var inputs = { + image:{type:'RGBA', + event:function(evt){ + var ctx = mod.img.getContext("2d") + ctx.canvas.width = evt.detail.width + ctx.canvas.height = evt.detail.height + ctx.putImageData(evt.detail,0,0) + mod.pxtext.nodeValue = evt.detail.width+' x '+evt.detail.height+' px' + convert_image() + }}, + imageInfo:{type:'object', + event:function(evt){ + mod.name.value = evt.detail.name+'.jpg' + }} + } +// +// outputs +// +var outputs = { + } +// +// interface +// +var interface = function(div){ + mod.div = div + // + // on-screen drawing canvas + // + var canvas = document.createElement('canvas') + canvas.width = mods.ui.canvas + canvas.height = mods.ui.canvas + canvas.style.backgroundColor = 'rgb(255,255,255)' + div.appendChild(canvas) + mod.canvas = canvas + div.appendChild(document.createElement('br')) + // + // off-screen image canvas + // + var canvas = document.createElement('canvas') + mod.img = canvas + // + // view button + // + var btn = document.createElement('button') + btn.style.padding = mods.ui.padding + btn.style.margin = 1 + btn.appendChild(document.createTextNode('view')) + btn.addEventListener('click',function(){ + var win = window.open('') + var btn = document.createElement('button') + btn.appendChild(document.createTextNode('close')) + btn.style.padding = mods.ui.padding + btn.style.margin = 1 + btn.addEventListener('click',function(){ + win.close() + }) + win.document.body.appendChild(btn) + win.document.body.appendChild(document.createElement('br')) + var canvas = document.createElement('canvas') + canvas.width = mod.img.width + canvas.height = mod.img.height + win.document.body.appendChild(canvas) + var ctx = canvas.getContext("2d") + ctx.drawImage(mod.img,0,0) + }) + div.appendChild(btn) + div.appendChild(document.createTextNode(' ')) + // + // info div + // + var info = document.createElement('div') + info.appendChild(document.createTextNode('file name: ')) + var input = document.createElement('input') + input.type = 'text' + input.size = 6 + info.appendChild(input) + mod.name = input + info.appendChild(document.createElement('br')) + info.appendChild(document.createTextNode('compression: ')) + var input = document.createElement('input') + input.type = 'text' + input.size = 6 + info.appendChild(input) + mod.compress = input + info.appendChild(document.createTextNode(' (0-1)')) + info.appendChild(document.createElement('br')) + var text = document.createTextNode('px: ') + info.appendChild(text) + mod.pxtext = text + div.appendChild(info) + } +// +// local functions +// +function convert_image() { + // + // preview + // + var h = mod.img.height + var w = mod.img.width + if (w > h) { + var x0 = 0 + var y0 = mod.canvas.height*.5*(1-h/w) + var wd = mod.canvas.width + var hd = mod.canvas.width*h/w + } + else { + var x0 = mod.canvas.width*.5*(1-w/h) + var y0 = 0 + var wd = mod.canvas.height*w/h + var hd = mod.canvas.height + } + var ctx = mod.canvas.getContext("2d") + ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height) + ctx.drawImage(mod.img,x0,y0,wd,hd) + // + // convert and save + // + mod.img.toBlob(function(blob){ + var url = URL.createObjectURL(blob) + var link = document.createElement('a') + link.download = mod.name.value + link.href = url + document.body.appendChild(link) + link.click() + document.body.removeChild(link) + URL.revokeObjectURL(url) + },'image/jpeg',parseFloat(mod.compress.value)) + } +// +// return values +// +return ({ + name:name, + init:init, + inputs:inputs, + outputs:outputs, + interface:interface + }) +}()) diff --git a/modules/convert/rgba/png b/modules/convert/rgba/png index d5ff0ed2c86314cf93a29bae5afd3aa15de97ac6..acaec9b6cdd5087a64e735858898b50f1a5afd7e 100755 --- a/modules/convert/rgba/png +++ b/modules/convert/rgba/png @@ -25,8 +25,7 @@ var name = 'convert RGBA to PNG' // initialization // var init = function() { - mod.nametext.value = "file.png" - mod.dpitext.value = 100 + mod.name.value = "file.png" } // // inputs @@ -43,9 +42,7 @@ var inputs = { }}, imageInfo:{type:'object', event:function(evt){ - mod.nametext.value = evt.detail.name - mod.dpitext.value = evt.detail.dpi - update_info() + mod.name.value = evt.detail.name+'.png' }} } // @@ -109,35 +106,11 @@ var interface = function(div){ input.type = 'text' input.size = 6 info.appendChild(input) - mod.nametext = input - info.appendChild(document.createElement('br')) - info.appendChild(document.createTextNode('dpi: ')) - var input = document.createElement('input') - input.type = 'text' - input.size = 6 - input.addEventListener('input',function(){ - mod.dpi = parseFloat(mod.dpitext.value) - mod.mmtext.nodeValue = (25.4*mod.img.width/mod.dpi).toFixed(3) - +' x '+(25.4*mod.img.height/mod.dpi).toFixed(3)+' mm' - mod.intext.nodeValue = (mod.img.width/mod.dpi).toFixed(3) - +' x '+(mod.img.height/mod.dpi).toFixed(3)+' in' - outputs.imageInfo.event() - }) - info.appendChild(input) - mod.dpitext = input + mod.name = input info.appendChild(document.createElement('br')) var text = document.createTextNode('px: ') info.appendChild(text) mod.pxtext = text - info.appendChild(document.createElement('br')) - var text = document.createTextNode('mm: ') - info.appendChild(text) - mod.mmtext = text - info.appendChild(document.createElement('br')) - var text = document.createTextNode('in: ') - info.appendChild(text) - mod.intext = text - info.appendChild(document.createElement('br')) div.appendChild(info) } // @@ -170,7 +143,7 @@ function convert_image() { mod.img.toBlob(function(blob){ var url = URL.createObjectURL(blob) var link = document.createElement('a') - link.download = mod.nametext.value + link.download = mod.name.value link.href = url document.body.appendChild(link) link.click() @@ -178,13 +151,7 @@ function convert_image() { URL.revokeObjectURL(url) },'image/png') } -function update_info() { - mod.dpi = parseFloat(mod.dpitext.value) - mod.mmtext.nodeValue = (25.4*mod.img.width/mod.dpi).toFixed(3) - +' x '+(25.4*mod.img.height/mod.dpi).toFixed(3)+' mm' - mod.intext.nodeValue = (mod.img.width/mod.dpi).toFixed(3) - +' x '+(mod.img.height/mod.dpi).toFixed(3)+' in' - } +// // return values // return ({ diff --git a/modules/image/motion detect b/modules/image/motion detect index fb161a60b1ce7ce61f40773e15259ce257ad9f0e..2fe373e4e84bd72957918846a6a94da7793dbc43 100755 --- a/modules/image/motion detect +++ b/modules/image/motion detect @@ -25,7 +25,7 @@ var name = 'motion detect' // initialization // var init = function() { - mod.threshold.value = 0.1 + mod.threshold.value = 0.01 mod.time.value = 15 mod.dpi = 100 timeout() @@ -146,7 +146,6 @@ function timeout() { setTimeout(timeout,parseFloat(mod.time.value)*1000) } function compare_images() { - //mod.change.nodeValue = Date.now() var blob = new Blob(['('+worker.toString()+'())']) var url = window.URL.createObjectURL(blob) var webworker = new Worker(url) @@ -162,7 +161,7 @@ function compare_images() { var hour = ('0'+date.getHours()).slice(-2) var minute = ('0'+date.getMinutes()).slice(-2) var second = ('0'+date.getSeconds()).slice(-2) - var name = year+'-'+month+'-'+day+'-'+hour+'-'+minute+'-'+second+'.png' + var name = year+'-'+month+'-'+day+'-'+hour+'-'+minute+'-'+second obj.name = name obj.dpi = mod.dpi obj.width = mod.img.width @@ -223,6 +222,7 @@ function worker() { self.postMessage({change:change}) }) } +// // return values // return ({ diff --git a/modules/index.html b/modules/index.html index b06b2bb5158b788faf09c2308f48755db4734a91..1dbe4ae1bf9b71e64d441db52b97cfbd10e68638 100644 --- a/modules/index.html +++ b/modules/index.html @@ -25,6 +25,7 @@ <a href="javascript:handler('modules/control/slider')">slider</a><br> <i>convert</i><br> <i> rgba</i><br> + <a href="javascript:handler('modules/convert/rgba/jpg')">jpg</a><br> <a href="javascript:handler('modules/convert/rgba/png')">png</a><br> <i> svg</i><br> <a href="javascript:handler('modules/convert/svg/array')">array</a><br> diff --git a/modules/input/video b/modules/input/video index 1cb52e68fe19cef7f62106d3495b68012c72303c..fb80006a96be73cfcf670290d9fa2d5ca707e03f 100644 --- a/modules/input/video +++ b/modules/input/video @@ -131,10 +131,18 @@ var interface = function(div){ mod.height = input div.appendChild(document.createElement('br')) // + // flip + // + div.appendChild(document.createTextNode('flip image: ')) + var input = document.createElement('input') + input.type = 'checkbox' + div.appendChild(input) + mod.flip = input + div.appendChild(document.createElement('br')) + // // video element // var video = document.createElement('video') - //div.appendChild(video) mod.video = video } // @@ -175,22 +183,67 @@ function capture_video() { var h = parseInt(mod.height.value) var ctx = mod.img.getContext("2d") ctx.drawImage(mod.video,0,0,w,h) - if (w > h) { - var x0 = 0 - var y0 = mod.canvas.height*.5*(1-h/w) - var wd = mod.canvas.width - var hd = mod.canvas.width*h/w - } - else { - var x0 = mod.canvas.width*.5*(1-w/h) - var y0 = 0 - var wd = mod.canvas.height*w/h - var hd = mod.canvas.height - } - var ctx = mod.canvas.getContext("2d") - ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height) - ctx.drawImage(mod.img,x0,y0,wd,hd) - outputs.image.event() + var blob = new Blob(['('+worker.toString()+'())']) + var url = window.URL.createObjectURL(blob) + var webworker = new Worker(url) + webworker.addEventListener('message',function(evt) { + window.URL.revokeObjectURL(url) + var h = mod.img.height + var w = mod.img.width + var buf = new Uint8ClampedArray(evt.data.buffer) + var imgdata = new ImageData(buf,w,h) + var ctx = mod.img.getContext("2d") + ctx.putImageData(imgdata,0,0) + if (w > h) { + var x0 = 0 + var y0 = mod.canvas.height*.5*(1-h/w) + var wd = mod.canvas.width + var hd = mod.canvas.width*h/w + } + else { + var x0 = mod.canvas.width*.5*(1-w/h) + var y0 = 0 + var wd = mod.canvas.height*w/h + var hd = mod.canvas.height + } + var ctx = mod.canvas.getContext("2d") + ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height) + ctx.drawImage(mod.img,x0,y0,wd,hd) + outputs.image.event() + webworker.terminate() + }) + var ctx = mod.img.getContext("2d") + var img = ctx.getImageData(0,0,mod.img.width,mod.img.height) + webworker.postMessage({ + height:mod.img.height,width:mod.img.width, + checked:mod.flip.checked, + buffer:img.data.buffer},[img.data.buffer]) + } +function worker() { + self.addEventListener('message',function(evt) { + var h = evt.data.height + var w = evt.data.width + var checked = evt.data.checked + var buf = new Uint8ClampedArray(evt.data.buffer) + if (checked == true) { + var newbuf = new Uint8ClampedArray(buf.length) + for (var row = 0; row < h; ++row) { + for (var col = 0; col < w; ++col) { + newbuf[(h-1-row)*w*4+col*4+0] = + buf[row*w*4+(w-1-col)*4+0] + newbuf[(h-1-row)*w*4+col*4+1] = + buf[row*w*4+(w-1-col)*4+1] + newbuf[(h-1-row)*w*4+col*4+2] = + buf[row*w*4+(w-1-col)*4+2] + newbuf[(h-1-row)*w*4+col*4+3] = + buf[row*w*4+(w-1-col)*4+3] + } + } + self.postMessage({buffer:newbuf.buffer},[newbuf.buffer]) + } + else + self.postMessage({buffer:buf.buffer},[buf.buffer]) + }) } // // return values diff --git a/programs/image/motion detect b/programs/image/motion detect index 0eadde01cb5123cb73eee59485b3a8410c641f44..8c4bfb3f2ab1167386d619876569c97f2c71e143 100644 --- a/programs/image/motion detect +++ b/programs/image/motion detect @@ -1 +1 @@ -{"modules":{"0.022552610085642244":{"definition":"//\n// motion detect\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2017\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'motion detect'\n//\n// initialization\n//\nvar init = function() {\n mod.threshold.value = 0.1\n mod.time.value = 15\n mod.dpi = 100\n timeout()\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n var ctx = mod.img.getContext(\"2d\")\n var lastctx = mod.lastimg.getContext(\"2d\")\n lastctx.canvas.width = ctx.canvas.width\n lastctx.canvas.height = ctx.canvas.height\n lastctx.drawImage(mod.img,0,0)\n ctx.canvas.width = evt.detail.width\n ctx.canvas.height = evt.detail.height \n ctx.putImageData(evt.detail,0,0)\n compare_images()\n }}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}},\n imageInfo:{type:'object',\n event:function(obj){\n mods.output(mod,'imageInfo',obj)}},\n trigger:{type:'event',\n event:function(){\n mods.output(mod,'trigger',null)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // off-screen last image canvas\n //\n var canvas = document.createElement('canvas')\n mod.lastimg = canvas\n //\n // view button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n canvas.width = mod.img.width\n canvas.height = mod.img.height\n win.document.body.appendChild(canvas)\n var ctx = canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,0,0)\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\n //\n // info div\n //\n var info = document.createElement('div')\n var text = document.createTextNode('relative change: ')\n info.appendChild(text)\n mod.change = text\n info.appendChild(document.createElement('br'))\n info.appendChild(document.createTextNode('threshold: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n info.appendChild(input)\n mod.threshold = input\n info.appendChild(document.createTextNode(' (0-1)'))\n info.appendChild(document.createElement('br'))\n info.appendChild(document.createTextNode('latency: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n info.appendChild(input)\n mod.time = input\n info.appendChild(document.createTextNode(' (s)'))\n div.appendChild(info)\n }\n//\n// local functions\n//\nfunction timeout() {\n outputs.trigger.event()\n setTimeout(timeout,parseFloat(mod.time.value)*1000)\n }\nfunction compare_images() {\n //mod.change.nodeValue = Date.now()\n var blob = new Blob(['('+worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n window.URL.revokeObjectURL(url)\n mod.change.nodeValue = 'relative change: '+evt.data.change.toFixed(3)\n if (evt.data.change > parseFloat(mod.threshold.value)) {\n var obj = {}\n var date = new Date()\n var year = date.getFullYear()\n var month = ('0'+(1+parseInt(date.getMonth()))).slice(-2)\n var day = ('0'+date.getDate()).slice(-2)\n var hour = ('0'+date.getHours()).slice(-2)\n var minute = ('0'+date.getMinutes()).slice(-2)\n var second = ('0'+date.getSeconds()).slice(-2)\n var name = year+'-'+month+'-'+day+'-'+hour+'-'+minute+'-'+second+'.png'\n obj.name = name\n obj.dpi = mod.dpi\n obj.width = mod.img.width\n obj.height = mod.img.height\n outputs.imageInfo.event(obj)\n outputs.image.event()\n }\n var h = mod.img.height\n var w = mod.img.width\n if (w > h) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n })\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var ctx = mod.lastimg.getContext(\"2d\")\n var lastimg = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var t = parseFloat(mod.threshold.value)\n webworker.postMessage({\n height:mod.img.height,width:mod.img.width,threshold:t,\n buffer:img.data.buffer,lastbuffer:lastimg.data.buffer})\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var t = evt.data.threshold\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var lastbuf = new Uint8ClampedArray(evt.data.lastbuffer)\n var change = 0\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n r = buf[(h-1-row)*w*4+col*4+0] \n g = buf[(h-1-row)*w*4+col*4+1] \n b = buf[(h-1-row)*w*4+col*4+2] \n rl = lastbuf[(h-1-row)*w*4+col*4+0] \n gl = lastbuf[(h-1-row)*w*4+col*4+1] \n bl = lastbuf[(h-1-row)*w*4+col*4+2] \n change += (Math.abs(r-rl)/255 \n +Math.abs(g-gl)/255\n +Math.abs(b-bl)/255)/3\n }\n }\n change = change/(w*h)\n self.postMessage({change:change})\n })\n }\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"102","left":"204","inputs":{},"outputs":{}},"0.6300838506360679":{"definition":"//\n// convert rgba png\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2017\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'convert RGBA to PNG'\n//\n// initialization\n//\nvar init = function() {\n mod.nametext.value = \"file.png\"\n mod.dpitext.value = 100\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = evt.detail.width\n ctx.canvas.height = evt.detail.height \n ctx.putImageData(evt.detail,0,0)\n mod.pxtext.nodeValue = evt.detail.width+' x '+evt.detail.height+' px'\n convert_image()\n }},\n imageInfo:{type:'object',\n event:function(evt){\n mod.nametext.value = evt.detail.name\n mod.dpitext.value = evt.detail.dpi\n update_info()\n }}\n }\n//\n// outputs\n//\nvar outputs = {\n }\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // view button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n canvas.width = mod.img.width\n canvas.height = mod.img.height\n win.document.body.appendChild(canvas)\n var ctx = canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,0,0)\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\n //\n // info div\n //\n var info = document.createElement('div')\n info.appendChild(document.createTextNode('file name: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n info.appendChild(input)\n mod.nametext = input\n info.appendChild(document.createElement('br'))\n info.appendChild(document.createTextNode('dpi: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('input',function(){\n mod.dpi = parseFloat(mod.dpitext.value)\n mod.mmtext.nodeValue = (25.4*mod.img.width/mod.dpi).toFixed(3)\n +' x '+(25.4*mod.img.height/mod.dpi).toFixed(3)+' mm'\n mod.intext.nodeValue = (mod.img.width/mod.dpi).toFixed(3)\n +' x '+(mod.img.height/mod.dpi).toFixed(3)+' in'\n outputs.imageInfo.event()\n })\n info.appendChild(input)\n mod.dpitext = input\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('px: ')\n info.appendChild(text)\n mod.pxtext = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('mm: ')\n info.appendChild(text)\n mod.mmtext = text\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('in: ')\n info.appendChild(text)\n mod.intext = text\n info.appendChild(document.createElement('br'))\n div.appendChild(info)\n }\n//\n// local functions\n//\nfunction convert_image() {\n //\n // preview\n //\n var h = mod.img.height\n var w = mod.img.width\n if (w > h) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n //\n // convert and save\n //\n mod.img.toBlob(function(blob){\n var url = URL.createObjectURL(blob)\n var link = document.createElement('a')\n link.download = mod.nametext.value\n link.href = url\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n },'image/png')\n }\nfunction update_info() {\n mod.dpi = parseFloat(mod.dpitext.value)\n mod.mmtext.nodeValue = (25.4*mod.img.width/mod.dpi).toFixed(3)\n +' x '+(25.4*mod.img.height/mod.dpi).toFixed(3)+' mm'\n mod.intext.nodeValue = (mod.img.width/mod.dpi).toFixed(3)\n +' x '+(mod.img.height/mod.dpi).toFixed(3)+' in'\n }\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"103","left":"1034","inputs":{},"outputs":{}},"0.9649518313148912":{"definition":"//\n// video\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2015,6\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'video'\n//\n// initialization\n//\nvar init = function() {\n mod.width.value = 1280\n mod.height.value = 720\n start_video()\n }\n//\n// inputs\n//\nvar inputs = {\n capture:{type:'event',\n event:function(evt){\n capture_video()}}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // capture button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('capture'))\n btn.addEventListener('click',function() {\n capture_video()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\n //\n // view button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n canvas.width = mod.img.width\n canvas.height = mod.img.height\n win.document.body.appendChild(canvas)\n var ctx = canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,0,0)\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // width\n //\n div.appendChild(document.createTextNode('width: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function() {\n update_video()\n })\n div.appendChild(input)\n mod.width = input\n div.appendChild(document.createElement('br'))\n //\n // height\n //\n div.appendChild(document.createTextNode(' height: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function() {\n update_video()\n })\n div.appendChild(input)\n mod.height = input\n div.appendChild(document.createElement('br'))\n //\n // video element\n //\n var video = document.createElement('video')\n //div.appendChild(video)\n mod.video = video\n }\n//\n// local functions\n//\nfunction start_video() {\n var w = parseInt(mod.width.value)\n var h = parseInt(mod.height.value)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = w\n ctx.canvas.height = h\n var constraints = {\n audio:false,\n video:{width:w,height:h}\n }\n navigator.mediaDevices.getUserMedia(constraints)\n .then(function(stream) {\n mod.video.srcObject = stream\n mod.video.onloadedmetadata = function(e) {\n mod.video.play()\n }\n })\n .catch(function(err) {\n console.log(err.name + \": \"+err.message)\n })\n }\nfunction update_video() {\n var w = parseInt(mod.width.value)\n var h = parseInt(mod.height.value)\n mod.video.setAttribute('width',w)\n mod.video.setAttribute('height',h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = w\n ctx.canvas.height = h\n }\nfunction capture_video() {\n var w = parseInt(mod.width.value)\n var h = parseInt(mod.height.value)\n var ctx = mod.img.getContext(\"2d\")\n ctx.drawImage(mod.video,0,0,w,h)\n if (w > h) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n outputs.image.event()\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"262","left":"681","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.022552610085642244\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.6300838506360679\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.022552610085642244\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.6300838506360679\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.022552610085642244\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"trigger\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.9649518313148912\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"capture\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.9649518313148912\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.022552610085642244\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}"]} \ No newline at end of file +{"modules":{"0.8218876344311344":{"definition":"//\n// motion detect\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2017\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'motion detect'\n//\n// initialization\n//\nvar init = function() {\n mod.threshold.value = 0.01\n mod.time.value = 15\n mod.dpi = 100\n timeout()\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n var ctx = mod.img.getContext(\"2d\")\n var lastctx = mod.lastimg.getContext(\"2d\")\n lastctx.canvas.width = ctx.canvas.width\n lastctx.canvas.height = ctx.canvas.height\n lastctx.drawImage(mod.img,0,0)\n ctx.canvas.width = evt.detail.width\n ctx.canvas.height = evt.detail.height \n ctx.putImageData(evt.detail,0,0)\n compare_images()\n }}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}},\n imageInfo:{type:'object',\n event:function(obj){\n mods.output(mod,'imageInfo',obj)}},\n trigger:{type:'event',\n event:function(){\n mods.output(mod,'trigger',null)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // off-screen last image canvas\n //\n var canvas = document.createElement('canvas')\n mod.lastimg = canvas\n //\n // view button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n canvas.width = mod.img.width\n canvas.height = mod.img.height\n win.document.body.appendChild(canvas)\n var ctx = canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,0,0)\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\n //\n // info div\n //\n var info = document.createElement('div')\n var text = document.createTextNode('relative change: ')\n info.appendChild(text)\n mod.change = text\n info.appendChild(document.createElement('br'))\n info.appendChild(document.createTextNode('threshold: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n info.appendChild(input)\n mod.threshold = input\n info.appendChild(document.createTextNode(' (0-1)'))\n info.appendChild(document.createElement('br'))\n info.appendChild(document.createTextNode('latency: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n info.appendChild(input)\n mod.time = input\n info.appendChild(document.createTextNode(' (s)'))\n div.appendChild(info)\n }\n//\n// local functions\n//\nfunction timeout() {\n outputs.trigger.event()\n setTimeout(timeout,parseFloat(mod.time.value)*1000)\n }\nfunction compare_images() {\n var blob = new Blob(['('+worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n window.URL.revokeObjectURL(url)\n mod.change.nodeValue = 'relative change: '+evt.data.change.toFixed(3)\n if (evt.data.change > parseFloat(mod.threshold.value)) {\n var obj = {}\n var date = new Date()\n var year = date.getFullYear()\n var month = ('0'+(1+parseInt(date.getMonth()))).slice(-2)\n var day = ('0'+date.getDate()).slice(-2)\n var hour = ('0'+date.getHours()).slice(-2)\n var minute = ('0'+date.getMinutes()).slice(-2)\n var second = ('0'+date.getSeconds()).slice(-2)\n var name = year+'-'+month+'-'+day+'-'+hour+'-'+minute+'-'+second\n obj.name = name\n obj.dpi = mod.dpi\n obj.width = mod.img.width\n obj.height = mod.img.height\n outputs.imageInfo.event(obj)\n outputs.image.event()\n }\n var h = mod.img.height\n var w = mod.img.width\n if (w > h) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n })\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var ctx = mod.lastimg.getContext(\"2d\")\n var lastimg = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var t = parseFloat(mod.threshold.value)\n webworker.postMessage({\n height:mod.img.height,width:mod.img.width,threshold:t,\n buffer:img.data.buffer,lastbuffer:lastimg.data.buffer})\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var t = evt.data.threshold\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var lastbuf = new Uint8ClampedArray(evt.data.lastbuffer)\n var change = 0\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n r = buf[(h-1-row)*w*4+col*4+0] \n g = buf[(h-1-row)*w*4+col*4+1] \n b = buf[(h-1-row)*w*4+col*4+2] \n rl = lastbuf[(h-1-row)*w*4+col*4+0] \n gl = lastbuf[(h-1-row)*w*4+col*4+1] \n bl = lastbuf[(h-1-row)*w*4+col*4+2] \n change += (Math.abs(r-rl)/255 \n +Math.abs(g-gl)/255\n +Math.abs(b-bl)/255)/3\n }\n }\n change = change/(w*h)\n self.postMessage({change:change})\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"140","left":"233","inputs":{},"outputs":{}},"0.10092185293872713":{"definition":"//\n// convert rgba jpg\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2017\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'convert RGBA to JPG'\n//\n// initialization\n//\nvar init = function() {\n mod.name.value = \"file.jpg\"\n mod.compress.value = .75\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = evt.detail.width\n ctx.canvas.height = evt.detail.height \n ctx.putImageData(evt.detail,0,0)\n mod.pxtext.nodeValue = evt.detail.width+' x '+evt.detail.height+' px'\n convert_image()\n }},\n imageInfo:{type:'object',\n event:function(evt){\n mod.name.value = evt.detail.name+'.jpg'\n }}\n }\n//\n// outputs\n//\nvar outputs = {\n }\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // view button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n canvas.width = mod.img.width\n canvas.height = mod.img.height\n win.document.body.appendChild(canvas)\n var ctx = canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,0,0)\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\n //\n // info div\n //\n var info = document.createElement('div')\n info.appendChild(document.createTextNode('file name: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n info.appendChild(input)\n mod.name = input\n info.appendChild(document.createElement('br'))\n info.appendChild(document.createTextNode('compression: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n info.appendChild(input)\n mod.compress = input\n info.appendChild(document.createTextNode(' (0-1)'))\n info.appendChild(document.createElement('br'))\n var text = document.createTextNode('px: ')\n info.appendChild(text)\n mod.pxtext = text\n div.appendChild(info)\n }\n//\n// local functions\n//\nfunction convert_image() {\n //\n // preview\n //\n var h = mod.img.height\n var w = mod.img.width\n if (w > h) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n //\n // convert and save\n //\n mod.img.toBlob(function(blob){\n var url = URL.createObjectURL(blob)\n var link = document.createElement('a')\n link.download = mod.name.value\n link.href = url\n document.body.appendChild(link)\n link.click()\n document.body.removeChild(link)\n URL.revokeObjectURL(url)\n },'image/jpeg',parseFloat(mod.compress.value))\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"142","left":"1098","inputs":{},"outputs":{}},"0.4997564076516918":{"definition":"//\n// video\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2015,6\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the mods\n// project. Copyright is retained and must be preserved. The work is \n// provided as is; no warranty is provided, and users accept all \n// liability.\n//\n// closure\n//\n(function(){\n//\n// module globals\n//\nvar mod = {}\n//\n// name\n//\nvar name = 'video'\n//\n// initialization\n//\nvar init = function() {\n mod.width.value = 1280 \n mod.height.value = 720\n start_video()\n }\n//\n// inputs\n//\nvar inputs = {\n capture:{type:'event',\n event:function(evt){\n capture_video()}}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n mods.output(mod,'image',img)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // on-screen drawing canvas\n //\n var canvas = document.createElement('canvas')\n canvas.width = mods.ui.canvas\n canvas.height = mods.ui.canvas\n canvas.style.backgroundColor = 'rgb(255,255,255)'\n div.appendChild(canvas)\n mod.canvas = canvas\n div.appendChild(document.createElement('br'))\n //\n // off-screen image canvas\n //\n var canvas = document.createElement('canvas')\n mod.img = canvas\n //\n // capture button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('capture'))\n btn.addEventListener('click',function() {\n capture_video()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\n //\n // view button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('view'))\n btn.addEventListener('click',function(){\n var win = window.open('')\n var btn = document.createElement('button')\n btn.appendChild(document.createTextNode('close'))\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.addEventListener('click',function(){\n win.close()\n })\n win.document.body.appendChild(btn)\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n canvas.width = mod.img.width\n canvas.height = mod.img.height\n win.document.body.appendChild(canvas)\n var ctx = canvas.getContext(\"2d\")\n ctx.drawImage(mod.img,0,0)\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // width\n //\n div.appendChild(document.createTextNode('width: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function() {\n update_video()\n })\n div.appendChild(input)\n mod.width = input\n div.appendChild(document.createElement('br'))\n //\n // height\n //\n div.appendChild(document.createTextNode(' height: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function() {\n update_video()\n })\n div.appendChild(input)\n mod.height = input\n div.appendChild(document.createElement('br'))\n //\n // flip\n //\n div.appendChild(document.createTextNode('flip image: '))\n var input = document.createElement('input')\n input.type = 'checkbox'\n div.appendChild(input)\n mod.flip = input\n div.appendChild(document.createElement('br'))\n //\n // video element\n //\n var video = document.createElement('video')\n mod.video = video\n }\n//\n// local functions\n//\nfunction start_video() {\n var w = parseInt(mod.width.value)\n var h = parseInt(mod.height.value)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = w\n ctx.canvas.height = h\n var constraints = {\n audio:false,\n video:{width:w,height:h}\n }\n navigator.mediaDevices.getUserMedia(constraints)\n .then(function(stream) {\n mod.video.srcObject = stream\n mod.video.onloadedmetadata = function(e) {\n mod.video.play()\n }\n })\n .catch(function(err) {\n console.log(err.name + \": \"+err.message)\n })\n }\nfunction update_video() {\n var w = parseInt(mod.width.value)\n var h = parseInt(mod.height.value)\n mod.video.setAttribute('width',w)\n mod.video.setAttribute('height',h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = w\n ctx.canvas.height = h\n }\nfunction capture_video() {\n var w = parseInt(mod.width.value)\n var h = parseInt(mod.height.value)\n var ctx = mod.img.getContext(\"2d\")\n ctx.drawImage(mod.video,0,0,w,h)\n var blob = new Blob(['('+worker.toString()+'())'])\n var url = window.URL.createObjectURL(blob)\n var webworker = new Worker(url)\n webworker.addEventListener('message',function(evt) {\n window.URL.revokeObjectURL(url)\n var h = mod.img.height\n var w = mod.img.width\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var imgdata = new ImageData(buf,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(imgdata,0,0)\n if (w > h) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-h/w)\n var wd = mod.canvas.width\n var hd = mod.canvas.width*h/w\n }\n else {\n var x0 = mod.canvas.width*.5*(1-w/h)\n var y0 = 0\n var wd = mod.canvas.height*w/h\n var hd = mod.canvas.height\n }\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n ctx.drawImage(mod.img,x0,y0,wd,hd)\n outputs.image.event()\n webworker.terminate()\n })\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n webworker.postMessage({\n height:mod.img.height,width:mod.img.width,\n checked:mod.flip.checked,\n buffer:img.data.buffer},[img.data.buffer])\n }\nfunction worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var checked = evt.data.checked\n var buf = new Uint8ClampedArray(evt.data.buffer)\n if (checked == true) {\n var newbuf = new Uint8ClampedArray(buf.length)\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n newbuf[(h-1-row)*w*4+col*4+0] = \n buf[row*w*4+(w-1-col)*4+0] \n newbuf[(h-1-row)*w*4+col*4+1] = \n buf[row*w*4+(w-1-col)*4+1]\n newbuf[(h-1-row)*w*4+col*4+2] = \n buf[row*w*4+(w-1-col)*4+2]\n newbuf[(h-1-row)*w*4+col*4+3] = \n buf[row*w*4+(w-1-col)*4+3]\n }\n }\n self.postMessage({buffer:newbuf.buffer},[newbuf.buffer])\n }\n else\n self.postMessage({buffer:buf.buffer},[buf.buffer])\n })\n }\n//\n// return values\n//\nreturn ({\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"302","left":"738","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.8218876344311344\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.10092185293872713\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.8218876344311344\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.10092185293872713\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.8218876344311344\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"trigger\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.4997564076516918\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"capture\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.4997564076516918\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.8218876344311344\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}"]} \ No newline at end of file