From 017762c462dc8771449aa765cf67efcfde0e4c3b Mon Sep 17 00:00:00 2001
From: Neil Gershenfeld <gersh@cba.mit.edu>
Date: Mon, 27 Sep 2021 08:56:42 -0400
Subject: [PATCH] start line scanner

---
 modules/input/video         |  51 ++++++++++-
 modules/processes/scan/line | 164 ++++++++++++++++++++++++++++++++++++
 2 files changed, 213 insertions(+), 2 deletions(-)
 create mode 100644 modules/processes/scan/line

diff --git a/modules/input/video b/modules/input/video
index 1faea25..14fe38c 100644
--- a/modules/input/video
+++ b/modules/input/video
@@ -28,7 +28,7 @@ var init = function() {
    mod.width.value = 640 
    mod.height.value = 480
    mod.flip.checked = false
-   start_video()
+   list_video()
    }
 //
 // inputs
@@ -67,6 +67,25 @@ var interface = function(div){
    var canvas = document.createElement('canvas')
       mod.img = canvas
    //
+   // camera select
+   //
+   var select = document.createElement('select')
+      div.appendChild(select)
+      mod.select = select
+   div.appendChild(document.createElement('br'))
+   //
+   // start button
+   //
+   var btn = document.createElement('button')
+      btn.style.padding = mods.ui.padding
+      btn.style.margin = 1
+      btn.appendChild(document.createTextNode('start'))
+      btn.addEventListener('click',function() {
+         start_video()
+         })
+      div.appendChild(btn)
+   div.appendChild(document.createTextNode(' '))
+   //
    // capture button
    //
    var btn = document.createElement('button')
@@ -149,6 +168,24 @@ var interface = function(div){
 //
 // local functions
 //
+// add cameras to list
+//
+function list_video() {
+   navigator.mediaDevices.enumerateDevices()
+      .then(function(devices) {
+         devices.forEach(function(device) {
+            if (device.kind == 'videoinput') {
+               var el = document.createElement('option')
+                   el.textContent = device.label
+                   el.value = device.deviceId
+                   mod.select.appendChild(el)
+               }
+            })
+         })
+   }
+//
+// start video
+//
 function start_video() {
    var w = parseInt(mod.width.value)
    var h = parseInt(mod.height.value)
@@ -157,19 +194,26 @@ function start_video() {
    ctx.canvas.height = h
    var constraints = {
       audio:false,
-      video:{width:w,height:h}
+      video:{
+         width:w,height:h,
+         deviceId:{exact:mod.select.options[mod.select.selectedIndex].value}
+         }
       }
    navigator.mediaDevices.getUserMedia(constraints)
       .then(function(stream) {
          mod.video.srcObject = stream
          mod.video.onloadedmetadata = function(e) {
             mod.video.play()
+            capture_video()
             }
          })
       .catch(function(err) {
          console.log(err.name+': '+err.message)
          })
    }
+//
+// update video
+//
 function update_video() {
    var w = parseInt(mod.width.value)
    var h = parseInt(mod.height.value)
@@ -179,6 +223,9 @@ function update_video() {
    ctx.canvas.width = w
    ctx.canvas.height = h
    }
+//
+// capture video
+//
 function capture_video() {
    var w = parseInt(mod.width.value)
    var h = parseInt(mod.height.value)
diff --git a/modules/processes/scan/line b/modules/processes/scan/line
new file mode 100644
index 0000000..54f823b
--- /dev/null
+++ b/modules/processes/scan/line
@@ -0,0 +1,164 @@
+//
+// line scan
+//
+// (c) MIT CBA Neil Gershenfeld 9/26/21
+// 
+// This work may be reproduced, modified, distributed, performed, and 
+// displayed for any purpose, but must acknowledge the fab modules 
+// 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 = 'line scan'
+//
+// initialization
+//
+var init = function() {
+   mod.width.value = 10
+   //
+   // open scan window
+   //
+   var win = window.open('')
+   win.document.title = "scan window"
+   win.document.body.appendChild(document.createElement('br'))
+   var canvas = document.createElement('canvas')
+   win.document.body.appendChild(canvas)
+   mod.scan = canvas
+   mod.win = win
+   }
+//
+// inputs
+//
+var inputs = {
+   image:{type:'RGBA',
+      event:function(evt) {
+         scanloop(evt.detail)
+         }
+      }
+   }
+//
+// outputs
+//
+var outputs = {
+   trigger:{type:'event',
+      event:function(){
+         mods.output(mod,'trigger',null)
+         }
+      }
+   }
+//
+// 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.img = canvas
+   div.appendChild(document.createElement('br'))
+   //
+   // line width
+   //
+   div.appendChild(document.createTextNode('scan line width (pixels): '))
+   var input = document.createElement('input')
+      input.type = 'text'
+      input.size = 6
+      input.addEventListener('change',function(){
+         alert('width')
+         })
+      div.appendChild(input)
+      mod.width = input
+   //
+   // start scan button
+   //
+   div.appendChild(document.createElement('br'))
+   div.appendChild(document.createTextNode(' '))
+   var btn = document.createElement('button')
+      btn.style.padding = mods.ui.padding
+      btn.style.margin = 1
+      btn.appendChild(document.createTextNode('start scan'))
+      btn.addEventListener('click',function(){
+         linescan()
+         })
+      div.appendChild(btn)
+   }
+//
+// local functions
+//
+// line scan
+//
+function linescan() {
+   mod.l = parseFloat(mod.width.value)
+   mod.w = mod.win.innerWidth
+   mod.h = mod.win.innerHeight
+   mod.scan.width = mod.w
+   mod.scan.height = mod.h
+   mod.y = 0
+   mod.state = 'start'
+   scanloop(null)
+   }
+//
+// scan loop
+//
+function scanloop(input) {
+   if (mod.state == 'start') {
+      //
+      // take background
+      //
+      var ctx = mod.scan.getContext("2d")
+      ctx.fillStyle = "black"
+      ctx.fillRect(0,0,mod.w,mod.h)
+      mod.state = 'background'
+      outputs.trigger.event()
+      }
+   else if (mod.state == 'background') {
+      //
+      // save background, start scan
+      //
+      mod.state = 'scan'
+      outputs.trigger.event()
+      }
+   else if (mod.state == 'scan') {
+      //
+      // scan
+      //
+      mod.y += mod.l
+      var ctx = mod.scan.getContext("2d")
+      ctx.lineWidth = mod.l
+      ctx.fillStyle = "black"
+      ctx.fillRect(0,0,mod.w,mod.h)
+      ctx.strokeStyle = "white"
+      ctx.beginPath()
+      ctx.moveTo(0,mod.y)
+      ctx.lineTo(mod.w,mod.y)
+      ctx.stroke()
+      if (mod.y < mod.h)
+         outputs.trigger.event()
+      }
+   }
+//
+// return values
+//
+return ({
+   name:name,
+   init:init,
+   inputs:inputs,
+   outputs:outputs,
+   interface:interface
+   })
+}())
-- 
GitLab