const pipe = (first, ...more) => more.reduce((acc,curr) => (...arguments) => curr(acc(...arguments)) , first); const offsetHelper = (distances, offset, width, height) => { var w = width; var h = height; var offset = offset; var input = distances; var output = new Uint8ClampedArray(4 * h * w); for (var row = 0; row < h; ++row) { for (var col = 0; col < w; ++col) { if (input[(h - 1 - row) * w + col] <= offset) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } } } const imgData = new ImageData(output, w, h); return imgData; }; const edgeDetectHelper = imageRGBA => { var h = imageRGBA.height; var w = imageRGBA.width; var input = imageRGBA.data; var output = new Uint8ClampedArray(h * w * 4); var i00, i0m, i0p, im0, ip0, imm, imp, ipm, ipp, row, col; // // find edges - interior // for (row = 1; row < h - 1; ++row) { for (col = 1; col < w - 1; ++col) { i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0p = input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; ip0 = input[(h - 2 - row) * w * 4 + col * 4 + 0] + input[(h - 2 - row) * w * 4 + col * 4 + 1] + input[(h - 2 - row) * w * 4 + col * 4 + 2]; ipp = input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 2]; i0m = input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; im0 = input[(h - row) * w * 4 + col * 4 + 0] + input[(h - row) * w * 4 + col * 4 + 1] + input[(h - row) * w * 4 + col * 4 + 2]; imm = input[(h - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - row) * w * 4 + (col - 1) * 4 + 2]; imp = input[(h - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - row) * w * 4 + (col + 1) * 4 + 2]; ipm = input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 2]; if ( i00 != i0p || i00 != ip0 || i00 != ipp || i00 != i0m || i00 != im0 || i00 != imm || i00 != imp || i00 != ipm ) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } } } // // left and right edges // for (row = 1; row < h - 1; ++row) { col = w - 1; i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0m = input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; imm = input[(h - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - row) * w * 4 + (col - 1) * 4 + 2]; ipm = input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 2]; im0 = input[(h - row) * w * 4 + col * 4 + 0] + input[(h - row) * w * 4 + col * 4 + 1] + input[(h - row) * w * 4 + col * 4 + 2]; ip0 = input[(h - 2 - row) * w * 4 + col * 4 + 0] + input[(h - 2 - row) * w * 4 + col * 4 + 1] + input[(h - 2 - row) * w * 4 + col * 4 + 2]; if (i00 != i0m || i00 != ip0 || i00 != ipm || i00 != im0 || i00 != imm) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } col = 0; i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0p = input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; imp = input[(h - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - row) * w * 4 + (col + 1) * 4 + 2]; ipp = input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 2]; im0 = input[(h - row) * w * 4 + col * 4 + 0] + input[(h - row) * w * 4 + col * 4 + 1] + input[(h - row) * w * 4 + col * 4 + 2]; ip0 = input[(h - 2 - row) * w * 4 + col * 4 + 0] + input[(h - 2 - row) * w * 4 + col * 4 + 1] + input[(h - 2 - row) * w * 4 + col * 4 + 2]; if (i00 != i0p || i00 != ip0 || i00 != ipp || i00 != im0 || i00 != imp) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } } // // top and bottom edges // for (col = 1; col < w - 1; ++col) { row = h - 1; i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0m = input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; i0p = input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; imm = input[(h - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - row) * w * 4 + (col - 1) * 4 + 2]; im0 = input[(h - row) * w * 4 + col * 4 + 0] + input[(h - row) * w * 4 + col * 4 + 1] + input[(h - row) * w * 4 + col * 4 + 2]; imp = input[(h - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - row) * w * 4 + (col + 1) * 4 + 2]; if (i00 != i0m || i00 != i0p || i00 != imm || i00 != im0 || i00 != imp) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } row = 0; i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0m = input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; i0p = input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; ipm = input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 2]; ip0 = input[(h - 2 - row) * w * 4 + col * 4 + 0] + input[(h - 2 - row) * w * 4 + col * 4 + 1] + input[(h - 2 - row) * w * 4 + col * 4 + 2]; ipp = input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 2]; if (i00 != i0m || i00 != i0p || i00 != ipm || i00 != ip0 || i00 != ipp) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } } // // corners // row = 0; col = 0; i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0p = input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; ip0 = input[(h - 2 - row) * w * 4 + col * 4 + 0] + input[(h - 2 - row) * w * 4 + col * 4 + 1] + input[(h - 2 - row) * w * 4 + col * 4 + 2]; ipp = input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 2 - row) * w * 4 + (col + 1) * 4 + 2]; if (i00 != i0p || i00 != ip0 || i00 != ipp) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } row = 0; col = w - 1; i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0m = input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; ip0 = input[(h - 2 - row) * w * 4 + col * 4 + 0] + input[(h - 2 - row) * w * 4 + col * 4 + 1] + input[(h - 2 - row) * w * 4 + col * 4 + 2]; ipm = input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 2 - row) * w * 4 + (col - 1) * 4 + 2]; if (i00 != i0m || i00 != ip0 || i00 != ipm) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } row = h - 1; col = 0; i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0p = input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col + 1) * 4 + 2]; im0 = input[(h - row) * w * 4 + col * 4 + 0] + input[(h - row) * w * 4 + col * 4 + 1] + input[(h - row) * w * 4 + col * 4 + 2]; imp = input[(h - row) * w * 4 + (col + 1) * 4 + 0] + input[(h - row) * w * 4 + (col + 1) * 4 + 1] + input[(h - row) * w * 4 + (col + 1) * 4 + 2]; if (i00 != i0p || i00 != im0 || i00 != imp) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } row = h - 1; col = w - 1; i00 = input[(h - 1 - row) * w * 4 + col * 4 + 0] + input[(h - 1 - row) * w * 4 + col * 4 + 1] + input[(h - 1 - row) * w * 4 + col * 4 + 2]; i0m = input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - 1 - row) * w * 4 + (col - 1) * 4 + 2]; im0 = input[(h - row) * w * 4 + col * 4 + 0] + input[(h - row) * w * 4 + col * 4 + 1] + input[(h - row) * w * 4 + col * 4 + 2]; imm = input[(h - row) * w * 4 + (col - 1) * 4 + 0] + input[(h - row) * w * 4 + (col - 1) * 4 + 1] + input[(h - row) * w * 4 + (col - 1) * 4 + 2]; if (i00 != i0m || i00 != im0 || i00 != imm) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else if (i00 == 0) { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } else { output[(h - 1 - row) * w * 4 + col * 4 + 0] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 1] = 255; output[(h - 1 - row) * w * 4 + col * 4 + 2] = 0; output[(h - 1 - row) * w * 4 + col * 4 + 3] = 255; } const imgData = new ImageData(output, w, h); return imgData; }; const orientEdgesHelper = imageRGBA => { var h = imageRGBA.height; var w = imageRGBA.width; var input = imageRGBA.data; var output = new Uint8ClampedArray(h * w * 4); var row, col; var boundary = 0; var interior = 1; var exterior = 2; var alpha = 3; var northsouth = 0; var north = 128; var south = 64; var eastwest = 1; var east = 128; var west = 64; var startstop = 2; var start = 128; var stop = 64; // // orient body states // for (row = 1; row < h - 1; ++row) { for (col = 1; col < w - 1; ++col) { output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { if ( input[(h - 1 - (row + 1)) * w * 4 + col * 4 + boundary] != 0 && (input[(h - 1 - row) * w * 4 + (col + 1) * 4 + interior] != 0 || input[(h - 1 - (row + 1)) * w * 4 + (col + 1) * 4 + interior] != 0) ) output[(h - 1 - row) * w * 4 + col * 4 + northsouth] |= north; if ( input[(h - 1 - (row - 1)) * w * 4 + col * 4 + boundary] != 0 && (input[(h - 1 - row) * w * 4 + (col - 1) * 4 + interior] != 0 || input[(h - 1 - (row - 1)) * w * 4 + (col - 1) * 4 + interior] != 0) ) output[(h - 1 - row) * w * 4 + col * 4 + northsouth] |= south; if ( input[(h - 1 - row) * w * 4 + (col + 1) * 4 + boundary] != 0 && (input[(h - 1 - (row - 1)) * w * 4 + col * 4 + interior] != 0 || input[(h - 1 - (row - 1)) * w * 4 + (col + 1) * 4 + interior] != 0) ) output[(h - 1 - row) * w * 4 + col * 4 + eastwest] |= east; if ( input[(h - 1 - row) * w * 4 + (col - 1) * 4 + boundary] != 0 && (input[(h - 1 - (row + 1)) * w * 4 + col * 4 + interior] != 0 || input[(h - 1 - (row + 1)) * w * 4 + (col - 1) * 4 + interior] != 0) ) output[(h - 1 - row) * w * 4 + col * 4 + eastwest] |= west; } } } // // orient edge states // for (col = 1; col < w - 1; ++col) { row = 0; output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { if ( input[(h - 1 - (row + 1)) * w * 4 + col * 4 + boundary] != 0 && input[(h - 1 - row) * w * 4 + (col + 1) * 4 + interior] != 0 ) { output[(h - 1 - row) * w * 4 + col * 4 + northsouth] |= north; output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= start; } if (input[(h - 1 - row) * w * 4 + (col - 1) * 4 + interior] != 0) output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= stop; } row = h - 1; output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { if (input[(h - 1 - row) * w * 4 + (col + 1) * 4 + interior] != 0) output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= stop; if ( input[(h - 1 - (row - 1)) * w * 4 + col * 4 + boundary] != 0 && input[(h - 1 - row) * w * 4 + (col - 1) * 4 + interior] != 0 ) { output[(h - 1 - row) * w * 4 + col * 4 + northsouth] |= south; output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= start; } } } for (row = 1; row < h - 1; ++row) { col = 0; output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { if ( input[(h - 1 - row) * w * 4 + (col + 1) * 4 + boundary] != 0 && input[(h - 1 - (row - 1)) * w * 4 + col * 4 + interior] != 0 ) { output[(h - 1 - row) * w * 4 + col * 4 + eastwest] |= east; output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= start; } if (input[(h - 1 - (row + 1)) * w * 4 + col * 4 + interior] != 0) output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= stop; } col = w - 1; output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; if (input[(h - 1 - row) * w * 4 + col * 4 + boundary] != 0) { if (input[(h - 1 - (row - 1)) * w * 4 + col * 4 + interior] != 0) output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= stop; if ( input[(h - 1 - row) * w * 4 + (col - 1) * 4 + boundary] != 0 && input[(h - 1 - (row + 1)) * w * 4 + col * 4 + interior] != 0 ) { output[(h - 1 - row) * w * 4 + col * 4 + eastwest] |= west; output[(h - 1 - row) * w * 4 + col * 4 + startstop] |= start; } } } // // orient corner states (todo) // row = 0; col = 0; output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; row = h - 1; col = 0; output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; row = 0; col = w - 1; output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; row = h - 1; col = w - 1; output[(h - 1 - row) * w * 4 + col * 4 + northsouth] = 0; output[(h - 1 - row) * w * 4 + col * 4 + eastwest] = 0; output[(h - 1 - row) * w * 4 + col * 4 + startstop] = 0; output[(h - 1 - row) * w * 4 + col * 4 + alpha] = 255; // var display = new Uint8ClampedArray(h*w*4) // var r,g,b,i // for (row = 0; row < h; ++row) { // for (col = 0; col < w; ++col) { // r = output[(h-1-row)*w*4+col*4+0] // g = output[(h-1-row)*w*4+col*4+1] // b = output[(h-1-row)*w*4+col*4+2] // i = r+g+b // if (i != 0) { // display[(h-1-row)*w*4+col*4+0] = output[(h-1-row)*w*4+col*4+0] // display[(h-1-row)*w*4+col*4+1] = output[(h-1-row)*w*4+col*4+1] // display[(h-1-row)*w*4+col*4+2] = output[(h-1-row)*w*4+col*4+2] // display[(h-1-row)*w*4+col*4+3] = output[(h-1-row)*w*4+col*4+3] // } // else { // display[(h-1-row)*w*4+col*4+0] = 255 // display[(h-1-row)*w*4+col*4+1] = 255 // display[(h-1-row)*w*4+col*4+2] = 255 // display[(h-1-row)*w*4+col*4+3] = 255 // } // } // } const imgData = new ImageData(output, w, h); return imgData; }; const vectorizeHelper = (imageRGBA, vectorFit = 1, sort = true) => { var h = imageRGBA.height; var w = imageRGBA.width; var input = imageRGBA.data; var northsouth = 0; var north = 128; var south = 64; var eastwest = 1; var east = 128; var west = 64; var startstop = 2; var start = 128; var stop = 64; var path = []; // // edge follower // function follow_edges(row, col) { if ( input[(h - 1 - row) * w * 4 + col * 4 + northsouth] != 0 || input[(h - 1 - row) * w * 4 + col * 4 + eastwest] != 0 ) { path[path.length] = [[col, row]]; while (1) { if ( input[(h - 1 - row) * w * 4 + col * 4 + northsouth] & north ) { input[(h - 1 - row) * w * 4 + col * 4 + northsouth] = input[(h - 1 - row) * w * 4 + col * 4 + northsouth] & ~north; row += 1; path[path.length - 1][path[path.length - 1].length] = [ col, row ]; } else if ( input[(h - 1 - row) * w * 4 + col * 4 + northsouth] & south ) { input[(h - 1 - row) * w * 4 + col * 4 + northsouth] = input[(h - 1 - row) * w * 4 + col * 4 + northsouth] & ~south; row -= 1; path[path.length - 1][path[path.length - 1].length] = [ col, row ]; } else if ( input[(h - 1 - row) * w * 4 + col * 4 + eastwest] & east ) { input[(h - 1 - row) * w * 4 + col * 4 + eastwest] = input[(h - 1 - row) * w * 4 + col * 4 + eastwest] & ~east; col += 1; path[path.length - 1][path[path.length - 1].length] = [ col, row ]; } else if ( input[(h - 1 - row) * w * 4 + col * 4 + eastwest] & west ) { input[(h - 1 - row) * w * 4 + col * 4 + eastwest] = input[(h - 1 - row) * w * 4 + col * 4 + eastwest] & ~west; col -= 1; path[path.length - 1][path[path.length - 1].length] = [ col, row ]; } else break; } } } // // follow boundary starts // for (var row = 1; row < h - 1; ++row) { col = 0; follow_edges(row, col); col = w - 1; follow_edges(row, col); } for (var col = 1; col < w - 1; ++col) { row = 0; follow_edges(row, col); row = h - 1; follow_edges(row, col); } // // follow interior paths // for (var row = 1; row < h - 1; ++row) { for (var col = 1; col < w - 1; ++col) { follow_edges(row, col); } } // // vectorize path // var error = vectorFit; var vecpath = []; for (var seg = 0; seg < path.length; ++seg) { var x0 = path[seg][0][0]; var y0 = path[seg][0][1]; vecpath[vecpath.length] = [[x0, y0]]; var xsum = x0; var ysum = y0; var sum = 1; for (var pt = 1; pt < path[seg].length; ++pt) { var xold = x; var yold = y; var x = path[seg][pt][0]; var y = path[seg][pt][1]; if (sum == 1) { xsum += x; ysum += y; sum += 1; } else { var xmean = xsum / sum; var ymean = ysum / sum; var dx = xmean - x0; var dy = ymean - y0; var d = Math.sqrt(dx * dx + dy * dy); var nx = dy / d; var ny = -dx / d; var l = Math.abs(nx * (x - x0) + ny * (y - y0)); if (l < error) { xsum += x; ysum += y; sum += 1; } else { vecpath[vecpath.length - 1][ vecpath[vecpath.length - 1].length ] = [xold, yold]; x0 = xold; y0 = yold; xsum = xold; ysum = yold; sum = 1; } } if (pt == path[seg].length - 1) { vecpath[vecpath.length - 1][ vecpath[vecpath.length - 1].length ] = [x, y]; } } } // // sort path // if (vecpath.length > 1 && sort == true) { var dmin = w * w + h * h; var segmin = null; for (var seg = 0; seg < vecpath.length; ++seg) { var x = vecpath[seg][0][0]; var y = vecpath[seg][0][0]; var d = x * x + y * y; if (d < dmin) { dmin = d; segmin = seg; } } if (segmin != null) { var sortpath = [vecpath[segmin]]; vecpath.splice(segmin, 1); } while (vecpath.length > 0) { var dmin = w * w + h * h; var x0 = sortpath[sortpath.length - 1][ sortpath[sortpath.length - 1].length - 1 ][0]; var y0 = sortpath[sortpath.length - 1][ sortpath[sortpath.length - 1].length - 1 ][1]; segmin = null; for (var seg = 0; seg < vecpath.length; ++seg) { var x = vecpath[seg][0][0]; var y = vecpath[seg][0][1]; var d = (x - x0) * (x - x0) + (y - y0) * (y - y0); if (d < dmin) { dmin = d; segmin = seg; } } if (segmin != null) { sortpath[sortpath.length] = vecpath[segmin]; vecpath.splice(segmin, 1); } } } else if ( (vecpath.length > 1 && sort == false) || vecpath.length == 1 ) sortpath = vecpath; else sortpath = []; return sortpath; }; const test = () => console.log("import is working");