Skip to content
GitLab
Explore
Sign in
Primary navigation
Search or go to…
Project
M
mods
Manage
Activity
Members
Labels
Plan
Issues
Issue boards
Milestones
Wiki
Code
Merge requests
Repository
Branches
Commits
Tags
Repository graph
Compare revisions
Snippets
Build
Pipelines
Jobs
Pipeline schedules
Artifacts
Deploy
Releases
Model registry
Operate
Environments
Monitor
Incidents
Analyze
Value stream analytics
Contributor analytics
CI/CD analytics
Repository analytics
Model experiments
Help
Help
Support
GitLab documentation
Compare GitLab plans
GitLab community forum
Contribute to GitLab
Provide feedback
Keyboard shortcuts
?
Snippets
Groups
Projects
Show more breadcrumbs
pub
mods
Commits
937b2c96
Commit
937b2c96
authored
Dec 22, 2017
by
Neil Gershenfeld
Browse files
Options
Downloads
Patches
Plain Diff
wip
parent
02662f23
Branches
Branches containing commit
No related tags found
No related merge requests found
Changes
1
Show whitespace changes
Inline
Side-by-side
Showing
1 changed file
programs/image/palette mask raster
+1
-1
1 addition, 1 deletion
programs/image/palette mask raster
with
1 addition
and
1 deletion
programs/image/palette mask raster
+
1
−
1
View file @
937b2c96
{"modules":{"0.5648025145147616":{"definition":"//\n// read png\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 = 'read png'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\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(){\n var obj = {}\n obj.name = mod.name.nodeValue\n obj.dpi = parseFloat(mod.dpitext.value)\n obj.width = mod.img.width\n obj.height = mod.img.height\n mods.output(mod,'imageInfo',obj)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // file input control\n //\n var file = document.createElement('input')\n file.setAttribute('type','file')\n file.setAttribute('id',div.id+'file_input')\n file.style.position = 'absolute'\n file.style.left = 0\n file.style.top = 0\n file.style.width = 0\n file.style.height = 0\n file.style.opacity = 0\n file.addEventListener('change',function() {\n png_read_handler()\n })\n div.appendChild(file)\n mod.file = file\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 // file select 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('select png file'))\n btn.addEventListener('click',function(){\n var file = document.getElementById(div.id+'file_input')\n file.value = null\n file.click()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\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 // invert 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('invert'))\n btn.addEventListener('click',function(){\n invert_image()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // info div\n //\n var info = document.createElement('div')\n info.setAttribute('id',div.id+'info')\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 var text = document.createTextNode('')\n info.appendChild(text)\n mod.name = text\n div.appendChild(info)\n }\n//\n// local functions\n//\n// read handler\n//\nfunction png_read_handler(event) {\n var file_reader = new FileReader()\n file_reader.onload = png_binary_handler\n input_file = mod.file.files[0]\n file_name = input_file.name\n mod.name.nodeValue = file_name\n file_reader.readAsArrayBuffer(input_file)\n }\n//\n// binary load handler\n//\nfunction png_binary_handler(event) {\n //\n // get DPI\n //\n // 8 header\n // 4 len, 4 type, data, 4 crc\n // pHYs 4 ppx, 4 ppy, 1 unit: 0 ?, 1 meter\n // IEND\n //\n var units = ppx = ppy = 0\n var buf = event.target.result\n var view = new DataView(buf)\n var ptr = 8\n if (!((view.getUint8(1) == 80) && (view.getUint8(2) == 78) && (view.getUint8(3) == 71))) {\n set_prompt(\"error: PNG header not found\")\n return\n }\n while (1) {\n var length = view.getUint32(ptr)\n ptr += 4\n var type = String.fromCharCode(\n view.getUint8(ptr),view.getUint8(ptr+1),\n view.getUint8(ptr+2),view.getUint8(ptr+3))\n ptr += 4\n if (type == \"pHYs\") {\n ppx = view.getUint32(ptr)\n ppy = view.getUint32(ptr + 4)\n units = view.getUint8(ptr + 8)\n }\n if (type == \"IEND\")\n break\n ptr += length + 4\n }\n if (units == 0) {\n set_prompt(\"no PNG units not found, assuming 72 DPI\")\n ppx = 72*1000/25.4\n }\n dpi = ppx*25.4/1000\n //\n // read as URL for display\n //\n var file_reader = new FileReader()\n file_reader.onload = png_URL_handler\n file_reader.readAsDataURL(input_file)\n }\n//\n// URL load handler\n//\nfunction png_URL_handler(event) {\n var img = new Image()\n img.setAttribute(\"src\",event.target.result)\n img.onload = function() {\n if (img.width > img.height) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-img.height/img.width)\n var w = mod.canvas.width\n var h = mod.canvas.width*img.height/img.width\n }\n else {\n var x0 = mod.canvas.width*.5*(1-img.width/img.height)\n var y0 = 0\n var w = mod.canvas.height*img.width/img.height\n var h = 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(img,x0,y0,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = img.width\n ctx.canvas.height = img.height \n ctx.drawImage(img,0,0)\n mod.dpitext.value = dpi.toFixed(3)\n mod.pxtext.nodeValue = img.width+' x '+img.height+' px'\n mod.mmtext.nodeValue = (25.4*img.width/dpi).toFixed(3)\n +' x '+(25.4*img.height/dpi).toFixed(3)+' mm'\n mod.intext.nodeValue = (img.width/dpi).toFixed(3)\n +' x '+(img.height/dpi).toFixed(3)+' in'\n outputs.image.event()\n outputs.imageInfo.event()\n }\n }\n//\n// invert image\n//\nfunction invert_image() {\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.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var h = mod.img.height\n var w = mod.img.width\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,w,h)\n webworker.postMessage({\n height:img.height,width:img.width,buffer:img.data.buffer},\n [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 buf = new Uint8ClampedArray(evt.data.buffer)\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n buf[(h-1-row)*w*4+col*4+0] \n = 255-buf[(h-1-row)*w*4+col*4+0] \n buf[(h-1-row)*w*4+col*4+1] \n = 255-buf[(h-1-row)*w*4+col*4+1] \n buf[(h-1-row)*w*4+col*4+2] \n = 255-buf[(h-1-row)*w*4+col*4+2] \n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\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":"102","left":"204","inputs":{},"outputs":{}},"0.3959513260329336":{"definition":"//\n// save file\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\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 = 'save file'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n file:{type:'object',\n event:function(evt){\n mod.name = evt.detail.name\n mod.contents = evt.detail.contents\n save_file()\n }}}\n//\n// outputs\n//\nvar outputs = {}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // info\n //\n var text = document.createTextNode('name:')\n div.appendChild(text)\n mod.nametext = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('size:')\n div.appendChild(text)\n mod.sizetext = text\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\nfunction save_file() {\n var a = document.createElement('a')\n a.setAttribute('href','data:text/plain;charset=utf-8,'+ \n encodeURIComponent(mod.contents))\n a.setAttribute('download',mod.name)\n a.style.display = 'none'\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n mod.nametext.nodeValue = 'name: '+mod.name\n mods.fit(mod.div)\n mod.sizetext.nodeValue = 'size: '+mod.contents.length\n mods.fit(mod.div)\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":"97","left":"1630","inputs":{},"outputs":{}},"0.3603827322636355":{"definition":"//\n// image palette\n// todo: linear time palette search\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 = 'image palette'\n//\n// initialization\n//\nvar init = function() {\n mod.palette.value = '[[255,255,255],\\n[0,0,0],\\n[255,0,0],\\n[0,255,0],\\n[0,0,255]]'\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n var ctx = mod.convert.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n show_palette()\n }\n },\n palette:{type:'text',\n event:function(evt){\n mod.palette.value = evt.detail\n show_palette()\n }\n }\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 palette:{type:'text',\n event:function(){\n mods.output(mod,'palette',mod.palette.value)\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 // off-screen conversion canvas\n //\n var canvas = document.createElement('canvas')\n mod.convert = canvas\n //\n // view\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 // image \n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('original')\n span.appendChild(text)\n span.style.fontWeight = 'normal'\n btn.appendChild(span)\n mod.originalspan = span\n btn.addEventListener('click',function(){\n mod.originalspan.style.fontWeight = 'bold'\n mod.palettespan.style.fontWeight = 'normal'\n show_original()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' image '))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('palette')\n span.appendChild(text)\n span.style.fontWeight = 'bold'\n btn.appendChild(span)\n mod.palettespan = span\n btn.addEventListener('click',function(){\n mod.originalspan.style.fontWeight = 'normal'\n mod.palettespan.style.fontWeight = 'bold'\n show_palette()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // palette\n //\n div.appendChild(document.createTextNode('palette'))\n div.appendChild(document.createElement('br'))\n var text = document.createElement('textarea')\n text.setAttribute('rows',mods.ui.rows)\n text.setAttribute('cols',mods.ui.cols)\n div.appendChild(text)\n mod.palette = text\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n// show_original\n//\nfunction show_original() {\n var h = mod.img.height\n var w = mod.img.width\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,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 }\n//\n// show palette\n//\nfunction show_palette() {\n var blob = new Blob(['('+palette_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 webworker.terminate()\n outputs.palette.event()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,0,0)\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var palette = JSON.parse(mod.palette.value)\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,palette:palette,\n buffer:img.data.buffer},\n [img.data.buffer])\n }\n//\n// palette worker\n// todo: sort palette\n//\nfunction palette_worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var palette = evt.data.palette\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var r,g,b,a,rc,gc,bc\n var cmin,dmin,d\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 a = buf[(h-1-row)*w*4+col*4+3] \n dmin = Number.MAX_VALUE\n for (color = 0; color < palette.length; ++color) {\n rc = palette[color][0]\n gc = palette[color][1]\n bc = palette[color][2]\n d = Math.sqrt(\n (rc-r)*(rc-r)+\n (gc-g)*(gc-g)+\n (bc-b)*(bc-b))\n if (d < dmin) {\n dmin = d\n cmin = color\n }\n }\n buf[(h-1-row)*w*4+col*4+0] = palette[cmin][0]\n buf[(h-1-row)*w*4+col*4+1] = palette[cmin][1]\n buf[(h-1-row)*w*4+col*4+2] = palette[cmin][2]\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\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":"235","left":"614","inputs":{},"outputs":{}},"0.2403743422209378":{"definition":"//\n// read text\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 = 'read text'\n//\n// initialization\n//\nvar init = function() {\n mod.text.value = \"load palette\"\n }\n//\n// inputs\n//\nvar inputs = {\n text:{type:'',\n event:function(evt) {\n mod.text.value = evt.detail\n }}}\n//\n// outputs\n//\nvar outputs = {\n text:{type:'',\n event:function(){\n mods.output(mod,'text',mod.text.value)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // file input control\n //\n var file = document.createElement('input')\n file.setAttribute('type','file')\n file.setAttribute('id',div.id+'file_input')\n file.style.position = 'absolute'\n file.style.left = 0\n file.style.top = 0\n file.style.width = 0\n file.style.height = 0\n file.style.opacity = 0\n file.addEventListener('change',function() {\n text_read_handler()\n })\n div.appendChild(file)\n mod.file = file\n //\n // text\n //\n var text = document.createElement('textarea')\n text.setAttribute('rows',mods.ui.rows)\n text.setAttribute('cols',mods.ui.cols)\n text.addEventListener('input',function() {\n outputs.text.event()\n })\n div.appendChild(text)\n mod.text = text\n div.appendChild(document.createElement('br'))\n //\n // file select 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('select text file'))\n btn.addEventListener('click',function(){\n var file = document.getElementById(div.id+'file_input')\n file.value = null\n file.click()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n// read handler\n//\nfunction text_read_handler(event) {\n //\n // read as text\n //\n var file_reader = new FileReader()\n file_reader.onload = text_load_handler\n var input_file = mod.file.files[0]\n file_reader.readAsText(input_file)\n }\n//\n// load handler\n//\nfunction text_load_handler(event) {\n mod.text.value = event.target.result\n outputs.text.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":"681","left":"212","inputs":{},"outputs":{}},"0.10571271239124669":{"definition":"//\n// image color separation\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 = 'color separation'\n//\n// initialization\n//\nvar init = function() {\n mod.input = null\n mod.color.value = '[255,0,0]'\n mod.fill.checked = true\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n var ctx = mod.convert.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n show_separation()\n }\n },\n color:{type:'RGB',\n event:function(evt){\n mod.color.value = JSON.stringify(evt.detail)\n }\n }\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//\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 conversion canvas\n //\n var canvas = document.createElement('canvas')\n mod.convert = canvas\n //\n // view\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 // image \n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('original')\n span.appendChild(text)\n span.style.fontWeight = 'normal'\n btn.appendChild(span)\n mod.originalspan = span\n btn.addEventListener('click',function(){\n mod.originalspan.style.fontWeight = 'bold'\n mod.palettespan.style.fontWeight = 'normal'\n show_original()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' image '))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('separation')\n span.appendChild(text)\n span.style.fontWeight = 'bold'\n btn.appendChild(span)\n mod.palettespan = span\n btn.addEventListener('click',function(){\n mod.originalspan.style.fontWeight = 'normal'\n mod.palettespan.style.fontWeight = 'bold'\n show_separation()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // color\n //\n div.appendChild(document.createTextNode('color: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 10\n div.appendChild(input)\n mod.color = input\n div.appendChild(document.createElement('br'))\n //\n // edges\n //\n div.appendChild(document.createTextNode('fill edges: '))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'fill'\n div.appendChild(input)\n mod.fill = input\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n// show_original\n//\nfunction show_original() {\n var h = mod.img.height\n var w = mod.img.width\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,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 }\n//\n// show separation\n//\nfunction show_separation() {\n var blob = new Blob(['('+separation_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 webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,0,0)\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var color = JSON.parse(mod.color.value)\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,color:color,\n fill:mod.fill.checked,buffer:img.data.buffer},\n [img.data.buffer])\n }\n//\n// separation worker\n//\nfunction separation_worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var color = evt.data.color\n var fill = evt.data.fill\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var r,g,b,a,rc,gc,bc\n var cmin,dmin,d\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 a = buf[(h-1-row)*w*4+col*4+3] \n rc = color[0]\n gc = color[1]\n bc = color[2]\n if ((rc == r) && (gc == g) && (bc == b)) {\n buf[(h-1-row)*w*4+col*4+0] = 255\n buf[(h-1-row)*w*4+col*4+1] = 255\n buf[(h-1-row)*w*4+col*4+2] = 255\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n }\n if (fill == true) {\n for (var row = 0; row < h; ++row) {\n col = 0\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n col = w-1\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n for (var col = 0; col < w; ++col) {\n row = 0\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n row = h-1\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\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":"349","left":"1131","inputs":{},"outputs":{}},"0.5509389792243394":{"definition":"//\n// raster mask\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 = 'raster mask'\n//\n// initialization\n//\nvar init = function() {\n mod.fill.checked = true\n }\n//\n// inputs\n//\nvar inputs = {\n imageInfo:{type:'object',\n event:function(evt){\n mod.imageInfo = evt.detail\n }},\n image:{type:'RGBA',\n event:function(evt){\n mod.image = evt.detail\n mod.labelspan.style.fontWeight = 'bold' \n var ctx = mod.convert.getContext(\"2d\")\n ctx.canvas.width = mod.image.width\n ctx.canvas.height = mod.image.height \n }},\n palette:{type:'text',\n event:function(evt){\n mod.palette = JSON.parse(evt.detail)\n }},\n mask:{type:'RGBA',\n event:function(evt){\n var ctx = mod.convert.getContext(\"2d\")\n ctx.putImageData(evt.detail,0,0)\n make_mask()\n }}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n mods.output(mod,'image',mod.image)\n }},\n color:{type:'RGB',\n event:function(evt){\n mods.output(mod,'color',evt)\n }},\n SVG:{type:'file',\n event:function(evt){\n mods.output(mod,'SVG',evt)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // off-screen conversion canvas\n //\n var canvas = document.createElement('canvas')\n mod.convert = canvas\n //\n // button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('calculate masks')\n mod.label = text\n span.appendChild(text)\n mod.labelspan = span\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n mod.index = 0\n outputs.color.event(mod.palette[mod.index])\n outputs.image.event()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // fill\n //\n div.appendChild(document.createTextNode('fill masks: '))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'fill'\n div.appendChild(input)\n mod.fill = input\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n//\n// make_mask\n//\nfunction make_mask() {\n //\n // save mask\n //\n save_mask()\n //\n // check for next mask\n //\n if (mod.index < (mod.palette.length-1)) {\n //\n // yes, output\n //\n mod.index += 1\n outputs.color.event(mod.palette[mod.index])\n outputs.image.event()\n }\n else {\n //\n // no, done\n //\n mod.labelspan.style.fontWeight = 'normal' \n } \n }\n//\n// save_mask\n//\nfunction save_mask(mask) {\n //\n // create SVG\n //\n var imgwidth = mod.image.width/parseFloat(mod.imageInfo.dpi)\n var imgheight = mod.image.height/parseFloat(mod.imageInfo.dpi)\n var svgNS = \"http://www.w3.org/2000/svg\"\n var svg = document.createElementNS(svgNS,\"svg\")\n svg.setAttributeNS(\"http://www.w3.org/2000/xmlns/\",\n \"xmlns:xlink\",\"http://www.w3.org/1999/xlink\")\n svg.setAttribute('width',(3+imgwidth)+'in')\n svg.setAttribute('height',(3+imgheight)+'in')\n svg.style.backgroundColor = 'rgb(255,255,255)'\n svg.setAttribute('viewBox','0 0 '+(3+imgwidth)+' '+(3+imgheight))\n //\n // background\n //\n var rect = document.createElementNS(svgNS,'rect')\n rect.setAttribute('x','0')\n rect.setAttribute('y','0')\n rect.setAttribute('width',3+imgwidth)\n rect.setAttribute('height',3+imgheight)\n rect.setAttribute('stroke','none')\n rect.setAttribute('fill','white')\n svg.appendChild(rect)\n //\n // registration\n //\n var g = document.createElementNS(svgNS,'g')\n svg.appendChild(g)\n var polyline = document.createElementNS(svgNS,'polyline')\n polyline.setAttribute('stroke','red')\n polyline.setAttribute('stroke-width','0.01')\n polyline.setAttribute('stroke-linecap','round')\n polyline.setAttribute('fill','none')\n polyline.setAttribute('points','0.5,0.5 '+\n '0.5,'+(imgheight+2.5)+' '+\n (imgwidth+2.5)+','+(imgheight+2.5)+' '+\n (imgwidth+2.5)+',0.9 '+\n (imgwidth+2.1)+',0.5 '+\n '0.5,0.5')\n g.appendChild(polyline)\n var circle = document.createElementNS(svgNS,'circle')\n circle.setAttribute('cx','1')\n circle.setAttribute('cy','1')\n circle.setAttribute('r','0.125')\n circle.setAttribute('stroke','red')\n circle.setAttribute('stroke-width','0.01')\n circle.setAttribute('fill','none')\n g.appendChild(circle)\n var circle = document.createElementNS(svgNS,'circle')\n circle.setAttribute('cx','1')\n circle.setAttribute('cy',(2+imgheight))\n circle.setAttribute('r','0.125')\n circle.setAttribute('stroke','red')\n circle.setAttribute('stroke-width','0.01')\n circle.setAttribute('fill','none')\n g.appendChild(circle)\n var circle = document.createElementNS(svgNS,'circle')\n circle.setAttribute('cx',(2+imgwidth))\n circle.setAttribute('cy',(2+imgheight))\n circle.setAttribute('r','0.125')\n circle.setAttribute('stroke','red')\n circle.setAttribute('stroke-width','0.01')\n circle.setAttribute('fill','none')\n g.appendChild(circle)\n var circle = document.createElementNS(svgNS,'circle')\n circle.setAttribute('cx',(2+imgwidth))\n circle.setAttribute('cy','1')\n circle.setAttribute('r','0.125')\n circle.setAttribute('stroke','red')\n circle.setAttribute('stroke-width','0.01')\n circle.setAttribute('fill','none')\n g.appendChild(circle)\n //\n // name\n //\n var name = mod.imageInfo.name+'.'+mod.palette[mod.index][0]\n name += '.'+mod.palette[mod.index][1]\n name += '.'+mod.palette[mod.index][2]\n if (mod.palette[mod.index][3] != undefined)\n name += '.'+mod.palette[mod.index][3]\n var text = document.createElementNS(svgNS,'text')\n text.setAttribute('id',mod.div.id+'svgtext')\n text.setAttribute('x',(3+imgwidth)/2)\n text.setAttribute('y','1')\n text.setAttribute('fill','red')\n text.setAttribute('font-size','.5')\n text.setAttribute('text-anchor','middle')\n text.setAttribute('dy','.2')\n text.textContent = name\n svg.appendChild(text)\n //\n // raster mask\n //\n var href = mod.convert.toDataURL()\n var img = document.createElementNS(svgNS,'image')\n img.setAttribute('id',mod.div.id+'svgimg')\n img.setAttribute('x','1.5')\n img.setAttribute('y','1.5')\n img.setAttribute('width',imgwidth)\n img.setAttribute('height',imgheight)\n img.setAttributeNS('http://www.w3.org/1999/xlink','href',href)\n svg.appendChild(img)\n //\n // file\n //\n var obj = {}\n obj.type = 'file'\n obj.name = name+'.svg'\n var xml = new XMLSerializer().serializeToString(svg)\n obj.contents = xml\n outputs.SVG.event(obj)\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\n","top":"94","left":"1160","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.5648025145147616\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3603827322636355\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.2403743422209378\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"text\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3603827322636355\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"palette\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.3603827322636355\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.5509389792243394\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.3603827322636355\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"palette\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.5509389792243394\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"palette\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.5648025145147616\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.5509389792243394\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.5509389792243394\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.10571271239124669\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.5509389792243394\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"color\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.10571271239124669\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"color\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.10571271239124669\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.5509389792243394\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"mask\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.5509389792243394\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"SVG\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3959513260329336\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"file\\\"}\"}"]}
\ No newline at end of file
{"modules":{"0.5648025145147616":{"definition":"//\n// read png\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 = 'read png'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\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(){\n var obj = {}\n obj.name = mod.name.nodeValue\n obj.dpi = parseFloat(mod.dpitext.value)\n obj.width = mod.img.width\n obj.height = mod.img.height\n mods.output(mod,'imageInfo',obj)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // file input control\n //\n var file = document.createElement('input')\n file.setAttribute('type','file')\n file.setAttribute('id',div.id+'file_input')\n file.style.position = 'absolute'\n file.style.left = 0\n file.style.top = 0\n file.style.width = 0\n file.style.height = 0\n file.style.opacity = 0\n file.addEventListener('change',function() {\n png_read_handler()\n })\n div.appendChild(file)\n mod.file = file\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 // file select 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('select png file'))\n btn.addEventListener('click',function(){\n var file = document.getElementById(div.id+'file_input')\n file.value = null\n file.click()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\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 // invert 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('invert'))\n btn.addEventListener('click',function(){\n invert_image()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // info div\n //\n var info = document.createElement('div')\n info.setAttribute('id',div.id+'info')\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 var text = document.createTextNode('')\n info.appendChild(text)\n mod.name = text\n div.appendChild(info)\n }\n//\n// local functions\n//\n// read handler\n//\nfunction png_read_handler(event) {\n var file_reader = new FileReader()\n file_reader.onload = png_binary_handler\n input_file = mod.file.files[0]\n file_name = input_file.name\n mod.name.nodeValue = file_name\n file_reader.readAsArrayBuffer(input_file)\n }\n//\n// binary load handler\n//\nfunction png_binary_handler(event) {\n //\n // get DPI\n //\n // 8 header\n // 4 len, 4 type, data, 4 crc\n // pHYs 4 ppx, 4 ppy, 1 unit: 0 ?, 1 meter\n // IEND\n //\n var units = ppx = ppy = 0\n var buf = event.target.result\n var view = new DataView(buf)\n var ptr = 8\n if (!((view.getUint8(1) == 80) && (view.getUint8(2) == 78) && (view.getUint8(3) == 71))) {\n set_prompt(\"error: PNG header not found\")\n return\n }\n while (1) {\n var length = view.getUint32(ptr)\n ptr += 4\n var type = String.fromCharCode(\n view.getUint8(ptr),view.getUint8(ptr+1),\n view.getUint8(ptr+2),view.getUint8(ptr+3))\n ptr += 4\n if (type == \"pHYs\") {\n ppx = view.getUint32(ptr)\n ppy = view.getUint32(ptr + 4)\n units = view.getUint8(ptr + 8)\n }\n if (type == \"IEND\")\n break\n ptr += length + 4\n }\n if (units == 0) {\n set_prompt(\"no PNG units not found, assuming 72 DPI\")\n ppx = 72*1000/25.4\n }\n dpi = ppx*25.4/1000\n //\n // read as URL for display\n //\n var file_reader = new FileReader()\n file_reader.onload = png_URL_handler\n file_reader.readAsDataURL(input_file)\n }\n//\n// URL load handler\n//\nfunction png_URL_handler(event) {\n var img = new Image()\n img.setAttribute(\"src\",event.target.result)\n img.onload = function() {\n if (img.width > img.height) {\n var x0 = 0\n var y0 = mod.canvas.height*.5*(1-img.height/img.width)\n var w = mod.canvas.width\n var h = mod.canvas.width*img.height/img.width\n }\n else {\n var x0 = mod.canvas.width*.5*(1-img.width/img.height)\n var y0 = 0\n var w = mod.canvas.height*img.width/img.height\n var h = 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(img,x0,y0,w,h)\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = img.width\n ctx.canvas.height = img.height \n ctx.drawImage(img,0,0)\n mod.dpitext.value = dpi.toFixed(3)\n mod.pxtext.nodeValue = img.width+' x '+img.height+' px'\n mod.mmtext.nodeValue = (25.4*img.width/dpi).toFixed(3)\n +' x '+(25.4*img.height/dpi).toFixed(3)+' mm'\n mod.intext.nodeValue = (img.width/dpi).toFixed(3)\n +' x '+(img.height/dpi).toFixed(3)+' in'\n outputs.image.event()\n outputs.imageInfo.event()\n }\n }\n//\n// invert image\n//\nfunction invert_image() {\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.drawImage(mod.img,x0,y0,wd,hd)\n webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var h = mod.img.height\n var w = mod.img.width\n var ctx = mod.img.getContext(\"2d\")\n var img = ctx.getImageData(0,0,w,h)\n webworker.postMessage({\n height:img.height,width:img.width,buffer:img.data.buffer},\n [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 buf = new Uint8ClampedArray(evt.data.buffer)\n for (var row = 0; row < h; ++row) {\n for (var col = 0; col < w; ++col) {\n buf[(h-1-row)*w*4+col*4+0] \n = 255-buf[(h-1-row)*w*4+col*4+0] \n buf[(h-1-row)*w*4+col*4+1] \n = 255-buf[(h-1-row)*w*4+col*4+1] \n buf[(h-1-row)*w*4+col*4+2] \n = 255-buf[(h-1-row)*w*4+col*4+2] \n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\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":"102","left":"204","inputs":{},"outputs":{}},"0.3959513260329336":{"definition":"//\n// save file\n//\n// Neil Gershenfeld \n// (c) Massachusetts Institute of Technology 2016\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 = 'save file'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n file:{type:'object',\n event:function(evt){\n mod.name = evt.detail.name\n mod.contents = evt.detail.contents\n save_file()\n }}}\n//\n// outputs\n//\nvar outputs = {}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // info\n //\n var text = document.createTextNode('name:')\n div.appendChild(text)\n mod.nametext = text\n div.appendChild(document.createElement('br'))\n var text = document.createTextNode('size:')\n div.appendChild(text)\n mod.sizetext = text\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\nfunction save_file() {\n var a = document.createElement('a')\n a.setAttribute('href','data:text/plain;charset=utf-8,'+ \n encodeURIComponent(mod.contents))\n a.setAttribute('download',mod.name)\n a.style.display = 'none'\n document.body.appendChild(a)\n a.click()\n document.body.removeChild(a)\n mod.nametext.nodeValue = 'name: '+mod.name\n mods.fit(mod.div)\n mod.sizetext.nodeValue = 'size: '+mod.contents.length\n mods.fit(mod.div)\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":"217","left":"1649","inputs":{},"outputs":{}},"0.3603827322636355":{"definition":"//\n// image palette\n// todo: linear time palette search\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 = 'image palette'\n//\n// initialization\n//\nvar init = function() {\n mod.palette.value = '[[255,255,255],\\n[0,0,0],\\n[255,0,0],\\n[0,255,0],\\n[0,0,255]]'\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n var ctx = mod.convert.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n show_palette()\n }\n },\n palette:{type:'text',\n event:function(evt){\n mod.palette.value = evt.detail\n show_palette()\n }\n }\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 palette:{type:'text',\n event:function(){\n mods.output(mod,'palette',mod.palette.value)\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 // off-screen conversion canvas\n //\n var canvas = document.createElement('canvas')\n mod.convert = canvas\n //\n // view\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 // image \n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('original')\n span.appendChild(text)\n span.style.fontWeight = 'normal'\n btn.appendChild(span)\n mod.originalspan = span\n btn.addEventListener('click',function(){\n mod.originalspan.style.fontWeight = 'bold'\n mod.palettespan.style.fontWeight = 'normal'\n show_original()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' image '))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('palette')\n span.appendChild(text)\n span.style.fontWeight = 'bold'\n btn.appendChild(span)\n mod.palettespan = span\n btn.addEventListener('click',function(){\n mod.originalspan.style.fontWeight = 'normal'\n mod.palettespan.style.fontWeight = 'bold'\n show_palette()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // palette\n //\n div.appendChild(document.createTextNode('palette'))\n div.appendChild(document.createElement('br'))\n var text = document.createElement('textarea')\n text.setAttribute('rows',mods.ui.rows)\n text.setAttribute('cols',mods.ui.cols)\n div.appendChild(text)\n mod.palette = text\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n// show_original\n//\nfunction show_original() {\n var h = mod.img.height\n var w = mod.img.width\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,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 }\n//\n// show palette\n//\nfunction show_palette() {\n var blob = new Blob(['('+palette_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 webworker.terminate()\n outputs.palette.event()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,0,0)\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var palette = JSON.parse(mod.palette.value)\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,palette:palette,\n buffer:img.data.buffer},\n [img.data.buffer])\n }\n//\n// palette worker\n// todo: sort palette\n//\nfunction palette_worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var palette = evt.data.palette\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var r,g,b,a,rc,gc,bc\n var cmin,dmin,d\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 a = buf[(h-1-row)*w*4+col*4+3] \n dmin = Number.MAX_VALUE\n for (color = 0; color < palette.length; ++color) {\n rc = palette[color][0]\n gc = palette[color][1]\n bc = palette[color][2]\n d = Math.sqrt(\n (rc-r)*(rc-r)+\n (gc-g)*(gc-g)+\n (bc-b)*(bc-b))\n if (d < dmin) {\n dmin = d\n cmin = color\n }\n }\n buf[(h-1-row)*w*4+col*4+0] = palette[cmin][0]\n buf[(h-1-row)*w*4+col*4+1] = palette[cmin][1]\n buf[(h-1-row)*w*4+col*4+2] = palette[cmin][2]\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\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":"235","left":"614","inputs":{},"outputs":{}},"0.2403743422209378":{"definition":"//\n// read text\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 = 'read text'\n//\n// initialization\n//\nvar init = function() {\n mod.text.value = \"load palette\"\n }\n//\n// inputs\n//\nvar inputs = {\n text:{type:'',\n event:function(evt) {\n mod.text.value = evt.detail\n }}}\n//\n// outputs\n//\nvar outputs = {\n text:{type:'',\n event:function(){\n mods.output(mod,'text',mod.text.value)}}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // file input control\n //\n var file = document.createElement('input')\n file.setAttribute('type','file')\n file.setAttribute('id',div.id+'file_input')\n file.style.position = 'absolute'\n file.style.left = 0\n file.style.top = 0\n file.style.width = 0\n file.style.height = 0\n file.style.opacity = 0\n file.addEventListener('change',function() {\n text_read_handler()\n })\n div.appendChild(file)\n mod.file = file\n //\n // text\n //\n var text = document.createElement('textarea')\n text.setAttribute('rows',mods.ui.rows)\n text.setAttribute('cols',mods.ui.cols)\n text.addEventListener('input',function() {\n outputs.text.event()\n })\n div.appendChild(text)\n mod.text = text\n div.appendChild(document.createElement('br'))\n //\n // file select 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('select text file'))\n btn.addEventListener('click',function(){\n var file = document.getElementById(div.id+'file_input')\n file.value = null\n file.click()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n// read handler\n//\nfunction text_read_handler(event) {\n //\n // read as text\n //\n var file_reader = new FileReader()\n file_reader.onload = text_load_handler\n var input_file = mod.file.files[0]\n file_reader.readAsText(input_file)\n }\n//\n// load handler\n//\nfunction text_load_handler(event) {\n mod.text.value = event.target.result\n outputs.text.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":"681","left":"212","inputs":{},"outputs":{}},"0.2834337891813209":{"definition":"//\n// raster mask\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 = 'raster mask'\n//\n// initialization\n//\nvar init = function() {\n }\n//\n// inputs\n//\nvar inputs = {\n imageInfo:{type:'object',\n event:function(evt){\n mod.imageInfo = evt.detail\n }},\n image:{type:'RGBA',\n event:function(evt){\n mod.image = evt.detail\n mod.labelspan.style.fontWeight = 'bold' \n var ctx = mod.convert.getContext(\"2d\")\n ctx.canvas.width = mod.image.width\n ctx.canvas.height = mod.image.height \n }},\n palette:{type:'text',\n event:function(evt){\n mod.palette = JSON.parse(evt.detail)\n }},\n mask:{type:'RGBA',\n event:function(evt){\n var ctx = mod.convert.getContext(\"2d\")\n ctx.putImageData(evt.detail,0,0)\n make_mask()\n }}}\n//\n// outputs\n//\nvar outputs = {\n image:{type:'RGBA',\n event:function(){\n mods.output(mod,'image',mod.image)\n }},\n color:{type:'RGB',\n event:function(evt){\n mods.output(mod,'color',evt)\n }},\n SVG:{type:'file',\n event:function(evt){\n mods.output(mod,'SVG',evt)\n }}}\n//\n// interface\n//\nvar interface = function(div){\n mod.div = div\n //\n // off-screen conversion canvas\n //\n var canvas = document.createElement('canvas')\n mod.convert = canvas\n //\n // button\n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('calculate masks')\n mod.label = text\n span.appendChild(text)\n mod.labelspan = span\n btn.appendChild(span)\n btn.addEventListener('click',function(){\n mod.index = 0\n outputs.color.event(mod.palette[mod.index])\n outputs.image.event()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n//\n// make_mask\n//\nfunction make_mask() {\n //\n // save mask\n //\n save_mask()\n //\n // check for next mask\n //\n if (mod.index < (mod.palette.length-1)) {\n //\n // yes, output\n //\n mod.index += 1\n outputs.color.event(mod.palette[mod.index])\n outputs.image.event()\n }\n else {\n //\n // no, done\n //\n mod.labelspan.style.fontWeight = 'normal' \n } \n }\n//\n// save_mask\n//\nfunction save_mask(mask) {\n //\n // create SVG\n //\n var imgwidth = mod.image.width/parseFloat(mod.imageInfo.dpi)\n var imgheight = mod.image.height/parseFloat(mod.imageInfo.dpi)\n var svgNS = \"http://www.w3.org/2000/svg\"\n var svg = document.createElementNS(svgNS,\"svg\")\n svg.setAttributeNS(\"http://www.w3.org/2000/xmlns/\",\n \"xmlns:xlink\",\"http://www.w3.org/1999/xlink\")\n svg.setAttribute('width',(3+imgwidth)+'in')\n svg.setAttribute('height',(3+imgheight)+'in')\n svg.style.backgroundColor = 'rgb(255,255,255)'\n svg.setAttribute('viewBox','0 0 '+(3+imgwidth)+' '+(3+imgheight))\n //\n // background\n //\n var rect = document.createElementNS(svgNS,'rect')\n rect.setAttribute('x','0')\n rect.setAttribute('y','0')\n rect.setAttribute('width',3+imgwidth)\n rect.setAttribute('height',3+imgheight)\n rect.setAttribute('stroke','none')\n rect.setAttribute('fill','white')\n svg.appendChild(rect)\n //\n // registration\n //\n var g = document.createElementNS(svgNS,'g')\n svg.appendChild(g)\n var polyline = document.createElementNS(svgNS,'polyline')\n polyline.setAttribute('stroke','red')\n polyline.setAttribute('stroke-width','0.01')\n polyline.setAttribute('stroke-linecap','round')\n polyline.setAttribute('fill','none')\n polyline.setAttribute('points','0.5,0.5 '+\n '0.5,'+(imgheight+2.5)+' '+\n (imgwidth+2.5)+','+(imgheight+2.5)+' '+\n (imgwidth+2.5)+',0.9 '+\n (imgwidth+2.1)+',0.5 '+\n '0.5,0.5')\n g.appendChild(polyline)\n var circle = document.createElementNS(svgNS,'circle')\n circle.setAttribute('cx','1')\n circle.setAttribute('cy','1')\n circle.setAttribute('r','0.125')\n circle.setAttribute('stroke','red')\n circle.setAttribute('stroke-width','0.01')\n circle.setAttribute('fill','none')\n g.appendChild(circle)\n var circle = document.createElementNS(svgNS,'circle')\n circle.setAttribute('cx','1')\n circle.setAttribute('cy',(2+imgheight))\n circle.setAttribute('r','0.125')\n circle.setAttribute('stroke','red')\n circle.setAttribute('stroke-width','0.01')\n circle.setAttribute('fill','none')\n g.appendChild(circle)\n var circle = document.createElementNS(svgNS,'circle')\n circle.setAttribute('cx',(2+imgwidth))\n circle.setAttribute('cy',(2+imgheight))\n circle.setAttribute('r','0.125')\n circle.setAttribute('stroke','red')\n circle.setAttribute('stroke-width','0.01')\n circle.setAttribute('fill','none')\n g.appendChild(circle)\n var circle = document.createElementNS(svgNS,'circle')\n circle.setAttribute('cx',(2+imgwidth))\n circle.setAttribute('cy','1')\n circle.setAttribute('r','0.125')\n circle.setAttribute('stroke','red')\n circle.setAttribute('stroke-width','0.01')\n circle.setAttribute('fill','none')\n g.appendChild(circle)\n //\n // name\n //\n var name = mod.imageInfo.name+'.'+mod.palette[mod.index][0]\n name += '.'+mod.palette[mod.index][1]\n name += '.'+mod.palette[mod.index][2]\n if (mod.palette[mod.index][3] != undefined)\n name += '.'+mod.palette[mod.index][3]\n var text = document.createElementNS(svgNS,'text')\n text.setAttribute('id',mod.div.id+'svgtext')\n text.setAttribute('x',(3+imgwidth)/2)\n text.setAttribute('y','1')\n text.setAttribute('fill','red')\n text.setAttribute('font-size','.5')\n text.setAttribute('text-anchor','middle')\n text.setAttribute('dy','.2')\n text.textContent = name\n svg.appendChild(text)\n //\n // raster mask\n //\n var href = mod.convert.toDataURL()\n var img = document.createElementNS(svgNS,'image')\n img.setAttribute('id',mod.div.id+'svgimg')\n img.setAttribute('x','1.5')\n img.setAttribute('y','1.5')\n img.setAttribute('width',imgwidth)\n img.setAttribute('height',imgheight)\n img.setAttributeNS('http://www.w3.org/1999/xlink','href',href)\n svg.appendChild(img)\n //\n // file\n //\n var obj = {}\n obj.type = 'file'\n obj.name = name+'.svg'\n var xml = new XMLSerializer().serializeToString(svg)\n obj.contents = xml\n outputs.SVG.event(obj)\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\n","top":"81","left":"1165","inputs":{},"outputs":{}},"0.825895834568156":{"definition":"//\n// image color separation\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 = 'color separation'\n//\n// initialization\n//\nvar init = function() {\n mod.input = null\n mod.color.value = '[255,0,0]'\n mod.fill.checked = false\n }\n//\n// inputs\n//\nvar inputs = {\n image:{type:'RGBA',\n event:function(evt){\n mod.input = evt.detail\n var ctx = mod.img.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n var ctx = mod.convert.getContext(\"2d\")\n ctx.canvas.width = mod.input.width\n ctx.canvas.height = mod.input.height \n show_separation()\n }\n },\n color:{type:'RGB',\n event:function(evt){\n mod.color.value = JSON.stringify(evt.detail)\n }\n }\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//\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 conversion canvas\n //\n var canvas = document.createElement('canvas')\n mod.convert = canvas\n //\n // view\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 // image \n //\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('original')\n span.appendChild(text)\n span.style.fontWeight = 'normal'\n btn.appendChild(span)\n mod.originalspan = span\n btn.addEventListener('click',function(){\n mod.originalspan.style.fontWeight = 'bold'\n mod.palettespan.style.fontWeight = 'normal'\n show_original()\n })\n div.appendChild(btn)\n div.appendChild(document.createTextNode(' image '))\n var btn = document.createElement('button')\n btn.style.padding = mods.ui.padding\n btn.style.margin = 1\n var span = document.createElement('span')\n var text = document.createTextNode('separation')\n span.appendChild(text)\n span.style.fontWeight = 'bold'\n btn.appendChild(span)\n mod.palettespan = span\n btn.addEventListener('click',function(){\n mod.originalspan.style.fontWeight = 'normal'\n mod.palettespan.style.fontWeight = 'bold'\n show_separation()\n })\n div.appendChild(btn)\n div.appendChild(document.createElement('br'))\n //\n // color\n //\n div.appendChild(document.createTextNode('color: '))\n var input = document.createElement('input')\n input.type = 'text'\n input.size = 10\n div.appendChild(input)\n mod.color = input\n div.appendChild(document.createElement('br'))\n //\n // edges\n //\n div.appendChild(document.createTextNode('fill edges: '))\n var input = document.createElement('input')\n input.type = 'checkbox'\n input.id = mod.div.id+'fill'\n div.appendChild(input)\n mod.fill = input\n div.appendChild(document.createElement('br'))\n }\n//\n// local functions\n//\n// show_original\n//\nfunction show_original() {\n var h = mod.img.height\n var w = mod.img.width\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,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 }\n//\n// show separation\n//\nfunction show_separation() {\n var blob = new Blob(['('+separation_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 webworker.terminate()\n outputs.image.event()\n })\n var ctx = mod.canvas.getContext(\"2d\")\n ctx.clearRect(0,0,mod.canvas.width,mod.canvas.height)\n var ctx = mod.img.getContext(\"2d\")\n ctx.putImageData(mod.input,0,0)\n var img = ctx.getImageData(0,0,mod.img.width,mod.img.height)\n var color = JSON.parse(mod.color.value)\n webworker.postMessage({\n height:mod.input.height,width:mod.input.width,color:color,\n fill:mod.fill.checked,buffer:img.data.buffer},\n [img.data.buffer])\n }\n//\n// separation worker\n//\nfunction separation_worker() {\n self.addEventListener('message',function(evt) {\n var h = evt.data.height\n var w = evt.data.width\n var color = evt.data.color\n var fill = evt.data.fill\n var buf = new Uint8ClampedArray(evt.data.buffer)\n var r,g,b,a,rc,gc,bc\n var cmin,dmin,d\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 a = buf[(h-1-row)*w*4+col*4+3] \n rc = color[0]\n gc = color[1]\n bc = color[2]\n if ((rc == r) && (gc == g) && (bc == b)) {\n buf[(h-1-row)*w*4+col*4+0] = 255\n buf[(h-1-row)*w*4+col*4+1] = 255\n buf[(h-1-row)*w*4+col*4+2] = 255\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n else {\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\n }\n if (fill == true) {\n for (var row = 0; row < h; ++row) {\n col = 0\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n col = w-1\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n for (var col = 0; col < w; ++col) {\n row = 0\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n row = h-1\n buf[(h-1-row)*w*4+col*4+0] = 0\n buf[(h-1-row)*w*4+col*4+1] = 0\n buf[(h-1-row)*w*4+col*4+2] = 0\n buf[(h-1-row)*w*4+col*4+3] = 255\n }\n }\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":"362","left":"1167","inputs":{},"outputs":{}}},"links":["{\"source\":\"{\\\"id\\\":\\\"0.5648025145147616\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3603827322636355\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.2403743422209378\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"text\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3603827322636355\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"palette\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.5648025145147616\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.2834337891813209\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"imageInfo\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.3603827322636355\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.2834337891813209\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.3603827322636355\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"palette\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.2834337891813209\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"palette\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.2834337891813209\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.825895834568156\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"image\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.2834337891813209\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"color\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.825895834568156\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"color\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.825895834568156\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"image\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.2834337891813209\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"mask\\\"}\"}","{\"source\":\"{\\\"id\\\":\\\"0.2834337891813209\\\",\\\"type\\\":\\\"outputs\\\",\\\"name\\\":\\\"SVG\\\"}\",\"dest\":\"{\\\"id\\\":\\\"0.3959513260329336\\\",\\\"type\\\":\\\"inputs\\\",\\\"name\\\":\\\"file\\\"}\"}"]}
\ No newline at end of file
This diff is collapsed.
Click to expand it.
Preview
0%
Loading
Try again
or
attach a new file
.
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Save comment
Cancel
Please
sign in
to comment