2017-08-07 21:03:34 +02:00
|
|
|
/* This Source Code Form is subject to the terms of the Mozilla Public
|
|
|
|
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
|
|
|
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
|
|
|
(function(){
|
|
|
|
"use strict";
|
|
|
|
|
|
|
|
|
2019-11-28 01:26:35 +01:00
|
|
|
let scope;
|
2017-08-07 21:03:34 +02:00
|
|
|
if ((typeof exports) !== "undefined"){
|
|
|
|
scope = exports;
|
|
|
|
}
|
|
|
|
else {
|
2019-03-12 22:24:23 +01:00
|
|
|
scope = require.register("./colorStatistics", {});
|
2017-08-07 21:03:34 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
class Statistic{
|
|
|
|
constructor(){
|
|
|
|
this.colors = Object.create(null);
|
|
|
|
this.numberOfColors = 0;
|
|
|
|
|
|
|
|
this.minBoundary = {count: Number.NEGATIVE_INFINITY};
|
|
|
|
this.maxBoundary = {count: Number.POSITIVE_INFINITY, previousColor: this.minBoundary};
|
|
|
|
this.minBoundary.nextColor = this.maxBoundary;
|
|
|
|
}
|
|
|
|
addColor(r, g, b, a){
|
2019-11-28 01:26:35 +01:00
|
|
|
const index = String.fromCharCode(r, g, b, a);
|
|
|
|
let color = this.colors[index];
|
2017-08-07 21:03:34 +02:00
|
|
|
if (!color){
|
2017-10-06 16:06:31 +02:00
|
|
|
color = {
|
|
|
|
index,
|
|
|
|
color: [r, g, b, a],
|
|
|
|
count: 0,
|
|
|
|
previousColor: this.minBoundary,
|
|
|
|
nextColor: this.minBoundary.nextColor
|
|
|
|
};
|
2017-08-07 21:03:34 +02:00
|
|
|
this.numberOfColors += 1;
|
|
|
|
this.minBoundary.nextColor = color;
|
|
|
|
color.nextColor.previousColor = color;
|
|
|
|
this.colors[index] = color;
|
|
|
|
}
|
|
|
|
color.count += 1;
|
|
|
|
if (color.count > color.nextColor.count){
|
|
|
|
// swap colors to remain in right order
|
2017-10-03 15:35:31 +02:00
|
|
|
// a_ -> b_ -> c -> d becomes a_ -> c -> b_ -> d
|
2019-11-28 01:26:35 +01:00
|
|
|
const a_ = color.previousColor;
|
|
|
|
const b_ = color;
|
|
|
|
const c = color.nextColor;
|
|
|
|
const d = color.nextColor.nextColor;
|
2017-08-07 21:03:34 +02:00
|
|
|
|
2017-10-03 15:35:31 +02:00
|
|
|
a_.nextColor = c;
|
|
|
|
c.previousColor = a_;
|
2017-08-07 21:03:34 +02:00
|
|
|
|
2017-10-03 15:35:31 +02:00
|
|
|
c.nextColor = b_;
|
|
|
|
b_.previousColor = c;
|
2017-08-07 21:03:34 +02:00
|
|
|
|
2017-10-03 15:35:31 +02:00
|
|
|
b_.nextColor = d;
|
|
|
|
d.previousColor = b_;
|
2017-08-07 21:03:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
getMaxColors(n){
|
2017-10-03 15:35:31 +02:00
|
|
|
n = Math.min(n, this.numberOfColors);
|
2019-11-28 01:26:35 +01:00
|
|
|
const colors = Object.create(null);
|
|
|
|
let current = this.maxBoundary;
|
2017-08-07 21:03:34 +02:00
|
|
|
for (;n && current;n -= 1){
|
|
|
|
current = current.previousColor;
|
|
|
|
colors[current.index] = current;
|
|
|
|
}
|
|
|
|
return colors;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
scope.compute = function computeColorStatistics(rawData){
|
2019-11-28 01:26:35 +01:00
|
|
|
const statistic = new Statistic();
|
|
|
|
for (let i = 0, l = rawData.length; i < l; i += 4){
|
2017-08-07 21:03:34 +02:00
|
|
|
statistic.addColor(
|
|
|
|
rawData[i + 0],
|
|
|
|
rawData[i + 1],
|
|
|
|
rawData[i + 2],
|
|
|
|
rawData[i + 3]
|
|
|
|
);
|
|
|
|
}
|
|
|
|
return statistic;
|
2017-10-03 15:35:31 +02:00
|
|
|
};
|
2017-12-11 12:47:43 +01:00
|
|
|
scope.hasMoreColors = function hasMoreColors(rawData, threshold, statistic){
|
|
|
|
if (statistic){
|
|
|
|
return statistic.numberOfColors > threshold;
|
|
|
|
}
|
|
|
|
else {
|
2019-11-28 01:26:35 +01:00
|
|
|
const colors = Object.create(null);
|
|
|
|
let count = 0;
|
|
|
|
for (let i = 0, l = rawData.length; i < l; i += 4){
|
|
|
|
const index = String.fromCharCode(
|
2017-12-11 12:47:43 +01:00
|
|
|
rawData[i + 0],
|
|
|
|
rawData[i + 1],
|
|
|
|
rawData[i + 2],
|
|
|
|
rawData[i + 3]
|
|
|
|
);
|
|
|
|
if (!Object.prototype.hasOwnProperty.call(colors, index)){
|
|
|
|
colors[index] = true;
|
|
|
|
count += 1;
|
|
|
|
if (count > threshold){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return count > threshold;
|
|
|
|
}
|
|
|
|
};
|
2017-08-07 21:03:34 +02:00
|
|
|
}());
|