diff --git a/files.html b/files.html index 10778e2b9c492058df1b8c255e38029ae33074a7..4acc62db3a053887c940b0861aada2f516d5c732 100644 --- a/files.html +++ b/files.html @@ -178,6 +178,8 @@ <a href='./modules/processes/mill/raster/2.5D'>2.5D</a><br> <a href='./modules/processes/mill/raster/2D'>2D</a><br> <a href='./modules/processes/mill/raster/3D'>3D</a><br> +<i> scan</i><br> + <a href='./modules/processes/scan/line'>line</a><br> <i> read</i><br> <a href='./modules/read/png'>png</a><br> <a href='./modules/read/stl'>stl</a><br> diff --git a/modules/index.js b/modules/index.js index 4ed6839a9c6bd64e57dc1dd2b0b3fbea0e78e9a8..6f1910f122eab31bc106bbd8c473667eb66fab18 100644 --- a/modules/index.js +++ b/modules/index.js @@ -148,6 +148,8 @@ module_label(' raster') module_menu(' 2.5D','modules/processes/mill/raster/2.5D') module_menu(' 2D','modules/processes/mill/raster/2D') module_menu(' 3D','modules/processes/mill/raster/3D') +module_label(' scan') +module_menu(' line','modules/processes/scan/line') module_label('read') module_menu(' png','modules/read/png') module_menu(' stl','modules/read/stl') diff --git a/programs/processes/scan/line b/programs/processes/scan/line new file mode 100644 index 0000000000000000000000000000000000000000..b10a676d708e729fb86eb674df9b0514b92fc809 --- /dev/null +++ b/programs/processes/scan/line @@ -0,0 +1 @@ +{"modules":{"0.44700721850201686":{"definition":"//\n// line scan\n//\n// (c) MIT CBA Neil Gershenfeld 9/26/21\n// \n// This work may be reproduced, modified, distributed, performed, and \n// displayed for any purpose, but must acknowledge the fab modules \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 = 'line scan'\n//\n// initialization\n//\nvar init = function() {\n mod.width.value = 10\n //\n // open scan window\n //\n var win = window.open('')\n win.document.title = \"scan window\"\n win.document.body.appendChild(document.createElement('br'))\n var canvas = document.createElement('canvas')\n win.document.body.appendChild(canvas)\n mod.scan = canvas\n mod.win = win\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt) {\n scanloop(evt.detail)\n }\n }\n }\n//\n// outputs\n//\nvar outputs = {\n trigger:{type:'event',\n event:function(){\n mods.output(mod,'trigger',null)\n }\n }\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.img = canvas\n div.appendChild(document.createElement('br'))\n //\n // line width\n //\n div.appendChild(document.createTextNode('scan line width (pixels): '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 6\n input.addEventListener('change',function(){\n alert('width')\n })\n div.appendChild(input)\n mod.width = input\n //\n // start scan button\n //\n div.appendChild(document.createElement('br'))\n div.appendChild(document.createTextNode(' '))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n btn.appendChild(document.createTextNode('start scan'))\n btn.addEventListener('click',function(){\n linescan()\n })\n div.appendChild(btn)\n }\n//\n// local functions\n//\n// line scan\n//\nfunction linescan() {\n mod.l = parseFloat(mod.width.value)\n mod.w = mod.win.innerWidth\n mod.h = mod.win.innerHeight\n mod.scan.width = mod.w\n mod.scan.height = mod.h\n mod.y = 0\n mod.state = 'start'\n scanloop(null)\n }\n//\n// scan loop\n//\nfunction scanloop(input) {\n if (mod.state == 'start') {\n //\n // take background\n //\n var ctx = mod.scan.getContext(\"2d\")\n ctx.fillStyle = \"black\"\n ctx.fillRect(0,0,mod.w,mod.h)\n mod.state = 'background'\n outputs.trigger.event()\n }\n else if (mod.state == 'background') {\n //\n // save background, start scan\n //\n mod.state = 'scan'\n outputs.trigger.event()\n }\n else if (mod.state == 'scan') {\n //\n // scan\n //\n mod.y += mod.l\n var ctx = mod.scan.getContext(\"2d\")\n ctx.lineWidth = mod.l\n ctx.fillStyle = \"black\"\n ctx.fillRect(0,0,mod.w,mod.h)\n ctx.strokeStyle = \"white\"\n ctx.beginPath()\n ctx.moveTo(0,mod.y)\n ctx.lineTo(mod.w,mod.y)\n ctx.stroke()\n if (mod.y < mod.h)\n outputs.trigger.event()\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":"162","left":"274","filename":"modules/processes/scan/line","inputs":{},"outputs":{}},"0.058167411259774315":{"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 = '640'\n mod.height.value = '480'\n mod.flip.checked = false\n list_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 // camera select\n //\n var select = document.createElement('select')\n div.appendChild(select)\n mod.select = select\n div.appendChild(document.createElement('br'))\n //\n // start 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('start'))\n btn.addEventListener('click',function() {\n start_video()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' '))\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//\n// add cameras to list\n//\nfunction list_video() {\n navigator.mediaDevices.enumerateDevices()\n .then(function(devices) {\n devices.forEach(function(device) {\n if (device.kind == 'videoinput') {\n var el = document.createElement('option')\n el.textContent = device.label\n el.value = device.deviceId\n mod.select.appendChild(el)\n }\n })\n })\n }\n//\n// start video\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:{\n width:w,height:h,\n deviceId:{exact:mod.select.options[mod.select.selectedIndex].value}\n }\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 capture_video()\n }\n })\n .catch(function(err) {\n console.log(err.name+': '+err.message)\n })\n }\n//\n// update video\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 }\n//\n// capture video\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 mod:mod,\n name:name,\n init:init,\n inputs:inputs,\n outputs:outputs,\n interface:interface\n })\n}())\n","top":"248","left":"773","filename":"modules/input/video","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.44700721850201686\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"trigger\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.058167411259774315\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"capture\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.058167411259774315\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.44700721850201686\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}"]} \ No newline at end of file