From 053f7f078a17c83a5462710b8bbef230c98e0f06 Mon Sep 17 00:00:00 2001 From: Jake Palmer Date: Wed, 22 Apr 2020 01:50:03 -0400 Subject: [PATCH 1/3] Correct the number of colors returned to match exactly the maxcolors, even for values > 7 --- quantize.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quantize.js b/quantize.js index 731d188..10f1e3e 100644 --- a/quantize.js +++ b/quantize.js @@ -471,7 +471,7 @@ var MMCQ = (function() { } // next set - generate the median cuts using the (npix * vol) sorting. - iter(pq2, maxcolors - pq2.size()); + iter(pq2, maxcolors - pq2.size() + 1); // calculate the actual colors var cmap = new CMap(); From 4027ebe4e26ac6388f63af105a880c1305cd688e Mon Sep 17 00:00:00 2001 From: Jake Palmer Date: Sun, 17 May 2020 01:23:01 -0400 Subject: [PATCH 2/3] Create Mocha tests for quantize function, asserting the valid format of all palettes, given a variety of inputs --- package.json | 8 +++- test.js | 114 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 120 insertions(+), 2 deletions(-) create mode 100644 test.js diff --git a/package.json b/package.json index 97e446f..c1a2b72 100644 --- a/package.json +++ b/package.json @@ -30,6 +30,10 @@ "node": ">=0.10.21" }, "dependencies": {}, - "devDependencies": {}, - "scripts": {} + "devDependencies": { + "mocha": "^7.1.2" + }, + "scripts": { + "test": "mocha" + } } diff --git a/test.js b/test.js new file mode 100644 index 0000000..3d9cf08 --- /dev/null +++ b/test.js @@ -0,0 +1,114 @@ +const assert = require('assert'); +const quantize = require('./quantize'); + +/** + * Calls the quantize function for the arrayOfPixels with every allowed value of maximumColorCount + * Asserts that the response palette includes the requested number of colors + * Asserts that the response palette, and every color it contains, is in the correct format + * @param {Array} arrayOfPixels as an input array of the format [[190,197,190], [202,204,200], [207,214,210], [211,214,211], [205,207,207]] + */ +function validateResultForAllCounts(arrayOfPixels) { + // console.log("Input pixels:"); + // console.log(arrayOfPixels); + + for (let count = 2; count <= 256; count < 16 ? count++ : count *= 2) { + let colorMap = quantize(arrayOfPixels, count); + let palette = colorMap.palette(); + // console.log("Output palette:"); + // console.log(palette); + + validatePalette(palette); + // assert.equal(palette.length, count); + console.log(`Actual: ${palette.length}, Expected: ${count}`); + } +} + +/** + * Asserts that the specified palette, and every color it contains, is in the correct format + * @param {Array} palette as an array of the format [[204, 204, 204], [208,212,212], [188,196,188], [212,204,196]] + */ +function validatePalette(palette) { + assert(Array.isArray(palette)); + palette.forEach(color => { + validateColor(color); + }); +} + +/** + * Asserts that the specified color is in the correct format + * @param {Array} color as an array of the format [204, 204, 204] + */ +function validateColor(color) { + assert(Array.isArray(color)); + assert.equal(color.length, 3); + color.forEach(level => { + assert(level >= 0); + assert(level < 256); + }); +} + +describe('quantize', function () { + it('works on 1-pixel 1-color images', function (done) { + let arrayOfPixels = [[190,197,190]]; + + validateResultForAllCounts(arrayOfPixels); + done(); + }); + it('works on 5-pixel 1-color images', function (done) { + let arrayOfPixels = [[190,197,190], [190,197,190], [190,197,190], [190,197,190], [190,197,190]]; + + validateResultForAllCounts(arrayOfPixels); + done(); + }); + it('works on 1000-pixel 1-color images', function (done) { + let arrayOfPixels = []; + let pixel = [190,197,190]; + for (let i=0; i < 1000; i++) { + arrayOfPixels.push(pixel); + } + + validateResultForAllCounts(arrayOfPixels); + done(); + }); + + it('works on 5-pixel 5-color images', function (done) { + let arrayOfPixels = [[190,197,190], [202,204,200], [207,214,210], [211,214,211], [205,207,207]]; + + validateResultForAllCounts(arrayOfPixels); + done(); + }); + it('works on 1000-pixel 5-color images', function (done) { + let arrayOfPixels = []; + for (let i=0; i < 1000/5; i++) { + arrayOfPixels.push([190,197,190]); + arrayOfPixels.push([202,204,200]); + arrayOfPixels.push([207,214,210]); + arrayOfPixels.push([211,214,211]); + arrayOfPixels.push([205,207,207]); + } + + validateResultForAllCounts(arrayOfPixels); + done(); + }); + + it('works on 20-pixel 20-color images', function (done) { + let arrayOfPixels = []; + for (let i=0; i < 20; i++) { + arrayOfPixels.push([0,0,i*5]); + } + + validateResultForAllCounts(arrayOfPixels); + done(); + }); + it('works on 1000-pixel 20-color images', function (done) { + let arrayOfPixels = []; + for (let p=0; p < 1000/20; p++) { + for (let i=0; i < 20; i++) { + arrayOfPixels.push([0,0,i*5]); + } + } + + validateResultForAllCounts(arrayOfPixels); + done(); + }); +}) \ No newline at end of file From 6082cb92b75363b5e2a78597d4b7d2d6a288e851 Mon Sep 17 00:00:00 2001 From: Jake Palmer Date: Mon, 25 May 2020 01:46:42 -0400 Subject: [PATCH 3/3] Incorporate AlfredJKwack's change from 2017 in place of my +1 correction --- quantize.js | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/quantize.js b/quantize.js index 10f1e3e..dc60e0c 100644 --- a/quantize.js +++ b/quantize.js @@ -426,10 +426,15 @@ var MMCQ = (function() { // inner function to do the iteration function iter(lh, target) { - var ncolors = 1, + var ncolors = lh.size(), niters = 0, vbox; while (niters < maxIterations) { + if (ncolors >= target) return; + if (niters++ > maxIterations) { + // console.log("infinite loop; perhaps too few pixels!"); + return; + } vbox = lh.pop(); if (!vbox.count()) { /* just put it back */ lh.push(vbox); @@ -450,11 +455,6 @@ var MMCQ = (function() { lh.push(vbox2); ncolors++; } - if (ncolors >= target) return; - if (niters++ > maxIterations) { - // console.log("infinite loop; perhaps too few pixels!"); - return; - } } } @@ -471,7 +471,7 @@ var MMCQ = (function() { } // next set - generate the median cuts using the (npix * vol) sorting. - iter(pq2, maxcolors - pq2.size() + 1); + iter(pq2, maxcolors); // calculate the actual colors var cmap = new CMap();