{"version":3,"sources":["src/assets/scripts/rgbquant.js"],"names":[],"mappings":"AAAA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA,uBAAuB;AACvB;AACA,QAAQ;AACR;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;AACA;;AAEA;;AAEA;AACA,4CAA4C;AAC5C,wDAAwD;AACxD;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,qBAAqB,SAAS;AAC9B;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA,qBAAqB,SAAS;AAC9B;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA,mBAAmB,YAAY;AAC/B;AACA;;AAEA;;AAEA,6EAA6E,YAAY;AACzF;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,sFAAsF,WAAW;AACjG;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA,iBAAiB;AACjB;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,oCAAoC,WAAW;;AAE/C;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;;AAEA,mBAAmB,wBAAwB;AAC3C;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,4BAA4B,wBAAwB;AACpD;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,wCAAwC;;AAExC,qBAAqB,SAAS;AAC9B;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;;AAEP;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA,yBAAyB,SAAS;AAClC;AACA;;AAEA,+BAA+B,SAAS;AACxC;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA,WAAW;;AAEX;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA,qBAAqB,SAAS;AAC9B;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,SAAS;AAC5B;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA,kBAAkB;;AAElB;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO;AACP,KAAK;;AAEL;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;;AAEL;AACA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA,mBAAmB,SAAS;AAC5B,oCAAoC;;AAEpC;;AAEA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA,oCAAoC,4DAA4D;AAChG;AACA;;AAEA;AACA;AACA;AACA;;AAEA,oBAAoB,eAAe;AACnC,uBAAuB;;AAEvB;AACA;;AAEA;AACA;AACA,+BAA+B;;AAE/B;AACA;AACA;AACA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA,oBAAoB,oBAAoB;AACxC;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;AACA;AACA;AACA,aAAa;AACb;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,KAAK;AACL;AACA;AACA;AACA,kDAAkD;AAClD,oCAAoC;AACpC,oCAAoC;AACpC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA,mBAAmB,UAAU;AAC7B;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA;;AAEA;;AAEA;AACA;AACA;;AAEA;AACA,kBAAkB;;AAElB,qBAAqB,SAAS;AAC9B;AACA;AACA;AACA;;AAEA;AACA;AACA,OAAO;AACP;AACA;AACA,qCAAqC,SAAS;;AAE9C;AACA;AACA,OAAO;AACP;AACA;;AAEA;AACA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA;AACA;AACA;;AAEA;AACA,mBAAmB,SAAS;AAC5B,qBAAqB,SAAS;AAC9B,kBAAkB,mDAAmD;;AAErE;AACA;;AAEA,uDAAuD;AACvD;AACA;AACA;AACA;AACA;;AAEA;AACA;AACA;AACA,KAAK;AACL;;AAEA;AACA;AACA;;AAEA;AACA;;AAEA;AACA;AACA,KAAK;AACL;;AAEA;AACA;;AAEA;AACA;AACA;AACA;;AAEA,CAAC","file":"scripts.js","sourcesContent":["/*\n* Copyright (c) 2015, Leon Sorokin\n* All rights reserved. (MIT Licensed)\n*\n* RgbQuant.js - an image quantization lib\n*/\n\n(function(){\n function RgbQuant(opts) {\n opts = opts || {};\n\n // 1 = by global population, 2 = subregion population threshold\n this.method = opts.method || 2;\n // desired final palette size\n this.colors = opts.colors || 256;\n // # of highest-frequency colors to start with for palette reduction\n this.initColors = opts.initColors || 4096;\n // color-distance threshold for initial reduction pass\n this.initDist = opts.initDist || 0.01;\n // subsequent passes threshold\n this.distIncr = opts.distIncr || 0.005;\n // palette grouping\n this.hueGroups = opts.hueGroups || 10;\n this.satGroups = opts.satGroups || 10;\n this.lumGroups = opts.lumGroups || 10;\n // if > 0, enables hues stats and min-color retention per group\n this.minHueCols = opts.minHueCols || 0;\n // HueStats instance\n this.hueStats = this.minHueCols ? new HueStats(this.hueGroups, this.minHueCols) : null;\n\n // subregion partitioning box size\n this.boxSize = opts.boxSize || [64,64];\n // number of same pixels required within box for histogram inclusion\n this.boxPxls = opts.boxPxls || 2;\n // palette locked indicator\n this.palLocked = false;\n // palette sort order\n//\t\tthis.sortPal = ['hue-','lum-','sat-'];\n\n // dithering/error diffusion kernel name\n this.dithKern = opts.dithKern || null;\n // dither serpentine pattern\n this.dithSerp = opts.dithSerp || false;\n // minimum color difference (0-1) needed to dither\n this.dithDelta = opts.dithDelta || 0;\n\n // accumulated histogram\n this.histogram = {};\n // palette - rgb triplets\n this.idxrgb = opts.palette ? opts.palette.slice(0) : [];\n // palette - int32 vals\n this.idxi32 = [];\n // reverse lookup {i32:idx}\n this.i32idx = {};\n // {i32:rgb}\n this.i32rgb = {};\n // enable color caching (also incurs overhead of cache misses and cache building)\n this.useCache = opts.useCache !== false;\n // min color occurance count needed to qualify for caching\n this.cacheFreq = opts.cacheFreq || 10;\n // allows pre-defined palettes to be re-indexed (enabling palette compacting and sorting)\n this.reIndex = opts.reIndex || this.idxrgb.length == 0;\n // selection of color-distance equation\n this.colorDist = opts.colorDist == \"manhattan\" ? distManhattan : distEuclidean;\n\n // if pre-defined palette, build lookups\n if (this.idxrgb.length > 0) {\n var self = this;\n this.idxrgb.forEach(function(rgb, i) {\n var i32 = (\n (255 << 24) |\t// alpha\n (rgb[2] << 16) |\t// blue\n (rgb[1] << 8) |\t// green\n rgb[0]\t\t\t\t// red\n ) >>> 0;\n\n self.idxi32[i]\t\t= i32;\n self.i32idx[i32]\t= i;\n self.i32rgb[i32]\t= rgb;\n });\n }\n }\n\n // gathers histogram info\n RgbQuant.prototype.sample = function sample(img, width) {\n if (this.palLocked)\n throw \"Cannot sample additional images, palette already assembled.\";\n\n var data = getImageData(img, width);\n\n switch (this.method) {\n case 1: this.colorStats1D(data.buf32); break;\n case 2: this.colorStats2D(data.buf32, data.width); break;\n }\n };\n\n // image quantizer\n // todo: memoize colors here also\n // @retType: 1 - Uint8Array (default), 2 - Indexed array, 3 - Match @img type (unimplemented, todo)\n RgbQuant.prototype.reduce = function reduce(img, retType, dithKern, dithSerp) {\n if (!this.palLocked)\n this.buildPal();\n\n dithKern = dithKern || this.dithKern;\n dithSerp = typeof dithSerp != \"undefined\" ? dithSerp : this.dithSerp;\n\n retType = retType || 1;\n\n // reduce w/dither\n if (dithKern)\n var out32 = this.dither(img, dithKern, dithSerp);\n else {\n var data = getImageData(img),\n buf32 = data.buf32,\n len = buf32.length,\n out32 = new Uint32Array(len);\n\n for (var i = 0; i < len; i++) {\n var i32 = buf32[i];\n out32[i] = this.nearestColor(i32);\n }\n }\n\n if (retType == 1)\n return new Uint8Array(out32.buffer);\n\n if (retType == 2) {\n var out = [],\n len = out32.length;\n\n for (var i = 0; i < len; i++) {\n var i32 = out32[i];\n out[i] = this.i32idx[i32];\n }\n\n return out;\n }\n };\n\n // adapted from http://jsbin.com/iXofIji/2/edit by PAEz\n RgbQuant.prototype.dither = function(img, kernel, serpentine) {\n // http://www.tannerhelland.com/4660/dithering-eleven-algorithms-source-code/\n var kernels = {\n FloydSteinberg: [\n [7 / 16, 1, 0],\n [3 / 16, -1, 1],\n [5 / 16, 0, 1],\n [1 / 16, 1, 1]\n ],\n FalseFloydSteinberg: [\n [3 / 8, 1, 0],\n [3 / 8, 0, 1],\n [2 / 8, 1, 1]\n ],\n Stucki: [\n [8 / 42, 1, 0],\n [4 / 42, 2, 0],\n [2 / 42, -2, 1],\n [4 / 42, -1, 1],\n [8 / 42, 0, 1],\n [4 / 42, 1, 1],\n [2 / 42, 2, 1],\n [1 / 42, -2, 2],\n [2 / 42, -1, 2],\n [4 / 42, 0, 2],\n [2 / 42, 1, 2],\n [1 / 42, 2, 2]\n ],\n Atkinson: [\n [1 / 8, 1, 0],\n [1 / 8, 2, 0],\n [1 / 8, -1, 1],\n [1 / 8, 0, 1],\n [1 / 8, 1, 1],\n [1 / 8, 0, 2]\n ],\n Jarvis: [\t\t\t// Jarvis, Judice, and Ninke / JJN?\n [7 / 48, 1, 0],\n [5 / 48, 2, 0],\n [3 / 48, -2, 1],\n [5 / 48, -1, 1],\n [7 / 48, 0, 1],\n [5 / 48, 1, 1],\n [3 / 48, 2, 1],\n [1 / 48, -2, 2],\n [3 / 48, -1, 2],\n [5 / 48, 0, 2],\n [3 / 48, 1, 2],\n [1 / 48, 2, 2]\n ],\n Burkes: [\n [8 / 32, 1, 0],\n [4 / 32, 2, 0],\n [2 / 32, -2, 1],\n [4 / 32, -1, 1],\n [8 / 32, 0, 1],\n [4 / 32, 1, 1],\n [2 / 32, 2, 1],\n ],\n Sierra: [\n [5 / 32, 1, 0],\n [3 / 32, 2, 0],\n [2 / 32, -2, 1],\n [4 / 32, -1, 1],\n [5 / 32, 0, 1],\n [4 / 32, 1, 1],\n [2 / 32, 2, 1],\n [2 / 32, -1, 2],\n [3 / 32, 0, 2],\n [2 / 32, 1, 2],\n ],\n TwoSierra: [\n [4 / 16, 1, 0],\n [3 / 16, 2, 0],\n [1 / 16, -2, 1],\n [2 / 16, -1, 1],\n [3 / 16, 0, 1],\n [2 / 16, 1, 1],\n [1 / 16, 2, 1],\n ],\n SierraLite: [\n [2 / 4, 1, 0],\n [1 / 4, -1, 1],\n [1 / 4, 0, 1],\n ],\n };\n\n if (!kernel || !kernels[kernel]) {\n throw 'Unknown dithering kernel: ' + kernel;\n }\n\n var ds = kernels[kernel];\n\n var data = getImageData(img),\n//\t\t\tbuf8 = data.buf8,\n buf32 = data.buf32,\n width = data.width,\n height = data.height,\n len = buf32.length;\n\n var dir = serpentine ? -1 : 1;\n\n for (var y = 0; y < height; y++) {\n if (serpentine)\n dir = dir * -1;\n\n var lni = y * width;\n\n for (var x = (dir == 1 ? 0 : width - 1), xend = (dir == 1 ? width : 0); x !== xend; x += dir) {\n // Image pixel\n var idx = lni + x,\n i32 = buf32[idx],\n r1 = (i32 & 0xff),\n g1 = (i32 & 0xff00) >> 8,\n b1 = (i32 & 0xff0000) >> 16;\n\n // Reduced pixel\n var i32x = this.nearestColor(i32),\n r2 = (i32x & 0xff),\n g2 = (i32x & 0xff00) >> 8,\n b2 = (i32x & 0xff0000) >> 16;\n\n buf32[idx] =\n (255 << 24)\t|\t// alpha\n (b2 << 16)\t|\t// blue\n (g2 << 8)\t|\t// green\n r2;\n\n // dithering strength\n if (this.dithDelta) {\n var dist = this.colorDist([r1, g1, b1], [r2, g2, b2]);\n if (dist < this.dithDelta)\n continue;\n }\n\n // Component distance\n var er = r1 - r2,\n eg = g1 - g2,\n eb = b1 - b2;\n\n for (var i = (dir == 1 ? 0 : ds.length - 1), end = (dir == 1 ? ds.length : 0); i !== end; i += dir) {\n var x1 = ds[i][1] * dir,\n y1 = ds[i][2];\n\n var lni2 = y1 * width;\n\n if (x1 + x >= 0 && x1 + x < width && y1 + y >= 0 && y1 + y < height) {\n var d = ds[i][0];\n var idx2 = idx + (lni2 + x1);\n\n var r3 = (buf32[idx2] & 0xff),\n g3 = (buf32[idx2] & 0xff00) >> 8,\n b3 = (buf32[idx2] & 0xff0000) >> 16;\n\n var r4 = Math.max(0, Math.min(255, r3 + er * d)),\n g4 = Math.max(0, Math.min(255, g3 + eg * d)),\n b4 = Math.max(0, Math.min(255, b3 + eb * d));\n\n buf32[idx2] =\n (255 << 24)\t|\t// alpha\n (b4 << 16)\t|\t// blue\n (g4 << 8)\t|\t// green\n r4;\t\t\t// red\n }\n }\n }\n }\n\n return buf32;\n };\n\n // reduces histogram to palette, remaps & memoizes reduced colors\n RgbQuant.prototype.buildPal = function buildPal(noSort) {\n if (this.palLocked || this.idxrgb.length > 0 && this.idxrgb.length <= this.colors) return;\n\n var histG = this.histogram,\n sorted = sortedHashKeys(histG, true);\n\n if (sorted.length == 0)\n throw \"Nothing has been sampled, palette cannot be built.\";\n\n switch (this.method) {\n case 1:\n var cols = this.initColors,\n last = sorted[cols - 1],\n freq = histG[last];\n\n var idxi32 = sorted.slice(0, cols);\n\n // add any cut off colors with same freq as last\n var pos = cols, len = sorted.length;\n while (pos < len && histG[sorted[pos]] == freq)\n idxi32.push(sorted[pos++]);\n\n // inject min huegroup colors\n if (this.hueStats)\n this.hueStats.inject(idxi32);\n\n break;\n case 2:\n var idxi32 = sorted;\n break;\n }\n\n // int32-ify values\n idxi32 = idxi32.map(function(v){return +v;});\n\n this.reducePal(idxi32);\n\n if (!noSort && this.reIndex)\n this.sortPal();\n\n // build cache of top histogram colors\n if (this.useCache)\n this.cacheHistogram(idxi32);\n\n this.palLocked = true;\n };\n\n RgbQuant.prototype.palette = function palette(tuples, noSort) {\n this.buildPal(noSort);\n return tuples ? this.idxrgb : new Uint8Array((new Uint32Array(this.idxi32)).buffer);\n };\n\n RgbQuant.prototype.prunePal = function prunePal(keep) {\n var i32;\n\n for (var j = 0; j < this.idxrgb.length; j++) {\n if (!keep[j]) {\n i32 = this.idxi32[j];\n this.idxrgb[j] = null;\n this.idxi32[j] = null;\n delete this.i32idx[i32];\n }\n }\n\n // compact\n if (this.reIndex) {\n var idxrgb = [],\n idxi32 = [],\n i32idx = {};\n\n for (var j = 0, i = 0; j < this.idxrgb.length; j++) {\n if (this.idxrgb[j]) {\n i32 = this.idxi32[j];\n idxrgb[i] = this.idxrgb[j];\n i32idx[i32] = i;\n idxi32[i] = i32;\n i++;\n }\n }\n\n this.idxrgb = idxrgb;\n this.idxi32 = idxi32;\n this.i32idx = i32idx;\n }\n };\n\n // reduces similar colors from an importance-sorted Uint32 rgba array\n RgbQuant.prototype.reducePal = function reducePal(idxi32) {\n // if pre-defined palette's length exceeds target\n if (this.idxrgb.length > this.colors) {\n // quantize histogram to existing palette\n var len = idxi32.length, keep = {}, uniques = 0, idx, pruned = false;\n\n for (var i = 0; i < len; i++) {\n // palette length reached, unset all remaining colors (sparse palette)\n if (uniques == this.colors && !pruned) {\n this.prunePal(keep);\n pruned = true;\n }\n\n idx = this.nearestIndex(idxi32[i]);\n\n if (uniques < this.colors && !keep[idx]) {\n keep[idx] = true;\n uniques++;\n }\n }\n\n if (!pruned) {\n this.prunePal(keep);\n pruned = true;\n }\n }\n // reduce histogram to create initial palette\n else {\n // build full rgb palette\n var idxrgb = idxi32.map(function(i32) {\n return [\n (i32 & 0xff),\n (i32 & 0xff00) >> 8,\n (i32 & 0xff0000) >> 16,\n ];\n });\n\n var len = idxrgb.length,\n palLen = len,\n thold = this.initDist;\n\n // palette already at or below desired length\n if (palLen > this.colors) {\n while (palLen > this.colors) {\n var memDist = [];\n\n // iterate palette\n for (var i = 0; i < len; i++) {\n var pxi = idxrgb[i], i32i = idxi32[i];\n if (!pxi) continue;\n\n for (var j = i + 1; j < len; j++) {\n var pxj = idxrgb[j], i32j = idxi32[j];\n if (!pxj) continue;\n\n var dist = this.colorDist(pxi, pxj);\n\n if (dist < thold) {\n // store index,rgb,dist\n memDist.push([j, pxj, i32j, dist]);\n\n // kill squashed value\n delete(idxrgb[j]);\n palLen--;\n }\n }\n }\n\n // palette reduction pass\n // console.log(\"palette length: \" + palLen);\n\n // if palette is still much larger than target, increment by larger initDist\n thold += (palLen > this.colors * 3) ? this.initDist : this.distIncr;\n }\n\n // if palette is over-reduced, re-add removed colors with largest distances from last round\n if (palLen < this.colors) {\n // sort descending\n sort.call(memDist, function(a,b) {\n return b[3] - a[3];\n });\n\n var k = 0;\n while (palLen < this.colors) {\n // re-inject rgb into final palette\n idxrgb[memDist[k][0]] = memDist[k][1];\n\n palLen++;\n k++;\n }\n }\n }\n\n var len = idxrgb.length;\n for (var i = 0; i < len; i++) {\n if (!idxrgb[i]) continue;\n\n this.idxrgb.push(idxrgb[i]);\n this.idxi32.push(idxi32[i]);\n\n this.i32idx[idxi32[i]] = this.idxi32.length - 1;\n this.i32rgb[idxi32[i]] = idxrgb[i];\n }\n }\n };\n\n // global top-population\n RgbQuant.prototype.colorStats1D = function colorStats1D(buf32) {\n var histG = this.histogram,\n num = 0, col,\n len = buf32.length;\n\n for (var i = 0; i < len; i++) {\n col = buf32[i];\n\n // skip transparent\n if ((col & 0xff000000) >> 24 == 0) continue;\n\n // collect hue stats\n if (this.hueStats)\n this.hueStats.check(col);\n\n if (col in histG)\n histG[col]++;\n else\n histG[col] = 1;\n }\n };\n\n // population threshold within subregions\n // FIXME: this can over-reduce (few/no colors same?), need a way to keep\n // important colors that dont ever reach local thresholds (gradients?)\n RgbQuant.prototype.colorStats2D = function colorStats2D(buf32, width) {\n var boxW = this.boxSize[0],\n boxH = this.boxSize[1],\n area = boxW * boxH,\n boxes = makeBoxes(width, buf32.length / width, boxW, boxH),\n histG = this.histogram,\n self = this;\n\n boxes.forEach(function(box) {\n var effc = Math.max(Math.round((box.w * box.h) / area) * self.boxPxls, 2),\n histL = {}, col;\n\n iterBox(box, width, function(i) {\n col = buf32[i];\n\n // skip transparent\n if ((col & 0xff000000) >> 24 == 0) return;\n\n // collect hue stats\n if (self.hueStats)\n self.hueStats.check(col);\n\n if (col in histG)\n histG[col]++;\n else if (col in histL) {\n if (++histL[col] >= effc)\n histG[col] = histL[col];\n }\n else\n histL[col] = 1;\n });\n });\n\n if (this.hueStats)\n this.hueStats.inject(histG);\n };\n\n // TODO: group very low lum and very high lum colors\n // TODO: pass custom sort order\n RgbQuant.prototype.sortPal = function sortPal() {\n var self = this;\n\n this.idxi32.sort(function(a,b) {\n var idxA = self.i32idx[a],\n idxB = self.i32idx[b],\n rgbA = self.idxrgb[idxA],\n rgbB = self.idxrgb[idxB];\n\n var hslA = rgb2hsl(rgbA[0],rgbA[1],rgbA[2]),\n hslB = rgb2hsl(rgbB[0],rgbB[1],rgbB[2]);\n\n // sort all grays + whites together\n var hueA = (rgbA[0] == rgbA[1] && rgbA[1] == rgbA[2]) ? -1 : hueGroup(hslA.h, self.hueGroups);\n var hueB = (rgbB[0] == rgbB[1] && rgbB[1] == rgbB[2]) ? -1 : hueGroup(hslB.h, self.hueGroups);\n\n var hueDiff = hueB - hueA;\n if (hueDiff) return -hueDiff;\n\n var lumDiff = lumGroup(+hslB.l.toFixed(2)) - lumGroup(+hslA.l.toFixed(2));\n if (lumDiff) return -lumDiff;\n\n var satDiff = satGroup(+hslB.s.toFixed(2)) - satGroup(+hslA.s.toFixed(2));\n if (satDiff) return -satDiff;\n });\n\n // sync idxrgb & i32idx\n this.idxi32.forEach(function(i32, i) {\n self.idxrgb[i] = self.i32rgb[i32];\n self.i32idx[i32] = i;\n });\n };\n\n // TOTRY: use HUSL - http://boronine.com/husl/\n RgbQuant.prototype.nearestColor = function nearestColor(i32) {\n var idx = this.nearestIndex(i32);\n return idx === null ? 0 : this.idxi32[idx];\n };\n\n // TOTRY: use HUSL - http://boronine.com/husl/\n RgbQuant.prototype.nearestIndex = function nearestIndex(i32) {\n // alpha 0 returns null index\n if ((i32 & 0xff000000) >> 24 == 0)\n return null;\n\n if (this.useCache && (\"\"+i32) in this.i32idx)\n return this.i32idx[i32];\n\n var min = 1000,\n idx,\n rgb = [\n (i32 & 0xff),\n (i32 & 0xff00) >> 8,\n (i32 & 0xff0000) >> 16,\n ],\n len = this.idxrgb.length;\n\n for (var i = 0; i < len; i++) {\n if (!this.idxrgb[i]) continue;\t\t// sparse palettes\n\n var dist = this.colorDist(rgb, this.idxrgb[i]);\n\n if (dist < min) {\n min = dist;\n idx = i;\n }\n }\n\n return idx;\n };\n\n RgbQuant.prototype.cacheHistogram = function cacheHistogram(idxi32) {\n for (var i = 0, i32 = idxi32[i]; i < idxi32.length && this.histogram[i32] >= this.cacheFreq; i32 = idxi32[i++])\n this.i32idx[i32] = this.nearestIndex(i32);\n };\n\n function HueStats(numGroups, minCols) {\n this.numGroups = numGroups;\n this.minCols = minCols;\n this.stats = {};\n\n for (var i = -1; i < numGroups; i++)\n this.stats[i] = {num: 0, cols: []};\n\n this.groupsFull = 0;\n }\n\n HueStats.prototype.check = function checkHue(i32) {\n if (this.groupsFull == this.numGroups + 1)\n this.check = function() {return;};\n\n var r = (i32 & 0xff),\n g = (i32 & 0xff00) >> 8,\n b = (i32 & 0xff0000) >> 16,\n hg = (r == g && g == b) ? -1 : hueGroup(rgb2hsl(r,g,b).h, this.numGroups),\n gr = this.stats[hg],\n min = this.minCols;\n\n gr.num++;\n\n if (gr.num > min)\n return;\n if (gr.num == min)\n this.groupsFull++;\n\n if (gr.num <= min)\n this.stats[hg].cols.push(i32);\n };\n\n HueStats.prototype.inject = function injectHues(histG) {\n for (var i = -1; i < this.numGroups; i++) {\n if (this.stats[i].num <= this.minCols) {\n switch (typeOf(histG)) {\n case \"Array\":\n this.stats[i].cols.forEach(function(col){\n if (histG.indexOf(col) == -1)\n histG.push(col);\n });\n break;\n case \"Object\":\n this.stats[i].cols.forEach(function(col){\n if (!histG[col])\n histG[col] = 1;\n else\n histG[col]++;\n });\n break;\n }\n }\n }\n };\n\n // Rec. 709 (sRGB) luma coef\n var Pr = .2126,\n Pg = .7152,\n Pb = .0722;\n\n // http://alienryderflex.com/hsp.html\n function rgb2lum(r,g,b) {\n return Math.sqrt(\n Pr * r*r +\n Pg * g*g +\n Pb * b*b\n );\n }\n\n var rd = 255,\n gd = 255,\n bd = 255;\n\n var euclMax = Math.sqrt(Pr*rd*rd + Pg*gd*gd + Pb*bd*bd);\n // perceptual Euclidean color distance\n function distEuclidean(rgb0, rgb1) {\n var rd = rgb1[0]-rgb0[0],\n gd = rgb1[1]-rgb0[1],\n bd = rgb1[2]-rgb0[2];\n\n return Math.sqrt(Pr*rd*rd + Pg*gd*gd + Pb*bd*bd) / euclMax;\n }\n\n var manhMax = Pr*rd + Pg*gd + Pb*bd;\n // perceptual Manhattan color distance\n function distManhattan(rgb0, rgb1) {\n var rd = Math.abs(rgb1[0]-rgb0[0]),\n gd = Math.abs(rgb1[1]-rgb0[1]),\n bd = Math.abs(rgb1[2]-rgb0[2]);\n\n return (Pr*rd + Pg*gd + Pb*bd) / manhMax;\n }\n\n // http://rgb2hsl.nichabi.com/javascript-function.php\n function rgb2hsl(r, g, b) {\n var max, min, h, s, l, d;\n r /= 255;\n g /= 255;\n b /= 255;\n max = Math.max(r, g, b);\n min = Math.min(r, g, b);\n l = (max + min) / 2;\n if (max == min) {\n h = s = 0;\n } else {\n d = max - min;\n s = l > 0.5 ? d / (2 - max - min) : d / (max + min);\n switch (max) {\n case r: h = (g - b) / d + (g < b ? 6 : 0); break;\n case g:\th = (b - r) / d + 2; break;\n case b:\th = (r - g) / d + 4; break\n }\n h /= 6;\n }\n//\t\th = Math.floor(h * 360)\n//\t\ts = Math.floor(s * 100)\n//\t\tl = Math.floor(l * 100)\n return {\n h: h,\n s: s,\n l: rgb2lum(r,g,b),\n };\n }\n\n function hueGroup(hue, segs) {\n var seg = 1/segs,\n haf = seg/2;\n\n if (hue >= 1 - haf || hue <= haf)\n return 0;\n\n for (var i = 1; i < segs; i++) {\n var mid = i*seg;\n if (hue >= mid - haf && hue <= mid + haf)\n return i;\n }\n }\n\n function satGroup(sat) {\n return sat;\n }\n\n function lumGroup(lum) {\n return lum;\n }\n\n function typeOf(val) {\n return Object.prototype.toString.call(val).slice(8,-1);\n }\n\n var sort = isArrSortStable() ? Array.prototype.sort : stableSort;\n\n // must be used via stableSort.call(arr, fn)\n function stableSort(fn) {\n var type = typeOf(this[0]);\n\n if (type == \"Number\" || type == \"String\") {\n var ord = {}, len = this.length, val;\n\n for (var i = 0; i < len; i++) {\n val = this[i];\n if (ord[val] || ord[val] === 0) continue;\n ord[val] = i;\n }\n\n return this.sort(function(a,b) {\n return fn(a,b) || ord[a] - ord[b];\n });\n }\n else {\n var ord = this.map(function(v){return v});\n\n return this.sort(function(a,b) {\n return fn(a,b) || ord.indexOf(a) - ord.indexOf(b);\n });\n }\n }\n\n // test if js engine's Array#sort implementation is stable\n function isArrSortStable() {\n var str = \"abcdefghijklmnopqrstuvwxyz\";\n\n return \"xyzvwtursopqmnklhijfgdeabc\" == str.split(\"\").sort(function(a,b) {\n return ~~(str.indexOf(b)/2.3) - ~~(str.indexOf(a)/2.3);\n }).join(\"\");\n }\n\n // returns uniform pixel data from various img\n // TODO?: if array is passed, createimagedata, createlement canvas? take a pxlen?\n function getImageData(img, width) {\n var can, ctx, imgd, buf8, buf32, height;\n\n switch (typeOf(img)) {\n case \"HTMLImageElement\":\n can = document.createElement(\"canvas\");\n can.width = img.naturalWidth;\n can.height = img.naturalHeight;\n ctx = can.getContext(\"2d\");\n ctx.drawImage(img,0,0);\n case \"Canvas\":\n case \"HTMLCanvasElement\":\n can = can || img;\n ctx = ctx || can.getContext(\"2d\");\n case \"CanvasRenderingContext2D\":\n ctx = ctx || img;\n can = can || ctx.canvas;\n imgd = ctx.getImageData(0, 0, can.width, can.height);\n case \"ImageData\":\n imgd = imgd || img;\n width = imgd.width;\n if (typeOf(imgd.data) == \"CanvasPixelArray\")\n buf8 = new Uint8Array(imgd.data);\n else\n buf8 = imgd.data;\n case \"Array\":\n case \"CanvasPixelArray\":\n buf8 = buf8 || new Uint8Array(img);\n case \"Uint8Array\":\n case \"Uint8ClampedArray\":\n buf8 = buf8 || img;\n buf32 = new Uint32Array(buf8.buffer);\n case \"Uint32Array\":\n buf32 = buf32 || img;\n buf8 = buf8 || new Uint8Array(buf32.buffer);\n width = width || buf32.length;\n height = buf32.length / width;\n }\n\n return {\n can: can,\n ctx: ctx,\n imgd: imgd,\n buf8: buf8,\n buf32: buf32,\n width: width,\n height: height,\n };\n }\n\n // partitions a rect of wid x hgt into\n // array of bboxes of w0 x h0 (or less)\n function makeBoxes(wid, hgt, w0, h0) {\n var wnum = ~~(wid/w0), wrem = wid%w0,\n hnum = ~~(hgt/h0), hrem = hgt%h0,\n xend = wid-wrem, yend = hgt-hrem;\n\n var bxs = [];\n for (var y = 0; y < hgt; y += h0)\n for (var x = 0; x < wid; x += w0)\n bxs.push({x:x, y:y, w:(x==xend?wrem:w0), h:(y==yend?hrem:h0)});\n\n return bxs;\n }\n\n // iterates @bbox within a parent rect of width @wid; calls @fn, passing index within parent\n function iterBox(bbox, wid, fn) {\n var b = bbox,\n i0 = b.y * wid + b.x,\n i1 = (b.y + b.h - 1) * wid + (b.x + b.w - 1),\n cnt = 0, incr = wid - b.w + 1, i = i0;\n\n do {\n fn.call(this, i);\n i += (++cnt % b.w == 0) ? incr : 1;\n } while (i <= i1);\n }\n\n // returns array of hash keys sorted by their values\n function sortedHashKeys(obj, desc) {\n var keys = [];\n\n for (var key in obj)\n keys.push(key);\n\n return sort.call(keys, function(a,b) {\n return desc ? obj[b] - obj[a] : obj[a] - obj[b];\n });\n }\n\n // expose\n this.RgbQuant = RgbQuant;\n\n // expose to commonJS\n if (typeof module !== 'undefined' && module.exports) {\n module.exports = RgbQuant;\n }\n\n}).call(this);\n"],"sourceRoot":"webpack:///"}