Skip to content

Instantly share code, notes, and snippets.

@nmaier
Created June 9, 2011 19:42
Show Gist options
  • Save nmaier/1017533 to your computer and use it in GitHub Desktop.
Save nmaier/1017533 to your computer and use it in GitHub Desktop.
Dominant FavIcon color, see dominantColor_opt; optimized processing + IMO better results on black/gray; requires chrome privs
<!DOCTYPE html>
<style type="text/css">
body {
-moz-column-count: 4;
}
</style>
<script type="text/javascript;version=1.8">
function getDominantColor(aImg) {
let canvas = document.createElement("canvas");
canvas.height = aImg.height;
canvas.width = aImg.width;
let context = canvas.getContext("2d");
context.drawImage(aImg, 0, 0);
// keep track of how many times a color appears in the image
let colorCount = {};
let maxCount = 0;
let dominantColor = "";
// data is an array of a series of 4 one-byte values representing the rgba values of each pixel
let data = context.getImageData(0, 0, aImg.height, aImg.width).data;
for (let i = 0; i < data.length; i += 4) {
// ignore transparent pixels
if (data[i+3] == 0)
continue;
let color = data[i] + "," + data[i+1] + "," + data[i+2];
// ignore white
if (color == "255,255,255")
continue;
colorCount[color] = colorCount[color] ? colorCount[color] + 1 : 1;
// keep track of the color that appears the most times
if (colorCount[color] > maxCount) {
maxCount = colorCount[color];
dominantColor = color;
}
}
let rgb = dominantColor.split(",");
return rgb;
}
function getDominantColor_opt(aImg) {
let canvas = document.createElement("canvas");
canvas.height = aImg.height;
canvas.width = aImg.width;
let context = canvas.getContext("2d");
context.drawImage(aImg, 0, 0);
// keep track of how many times a color appears in the image
let colorCount = {};
let maxCount = 0;
let dominantColor = 0;
// data is an array of a series of 4 one-byte values representing the rgba values of each pixel
let data = context.getImageData(0, 0, aImg.height, aImg.width).data;
let cc, color, r, b, g, a;
for (let i = 0, e = data.length; i < e;) {
r = data[i++];
g = data[i++];
b = data[i++];
a = data[i++];
// transparent
if (a < 10) {
continue;
}
// bright
if (r < 10 && g < 10 && b < 10) {
continue;
}
// dark
if (r > 250 && g > 250 && b > 250) {
continue;
}
// gray
if (Math.abs(r - g) < 10 && Math.abs(g - b) < 10 && Math.abs(r - b) < 10) {
continue;
}
color = (r << 16) + (g << 8) + b;
cc = colorCount[color] = colorCount[color] + 1 || 1;
// keep track of the color that appears the most times
if (cc > maxCount) {
maxCount = cc;
dominantColor = color;
}
}
return dominantColor ? [dominantColor >> 16, (dominantColor >> 8) & 255, dominantColor & 255] : [128, 128, 128];
}
function bench(func, iterations, aImg) {
Components.utils.forceGC();
// precompile
for (let i = 0; i < 2; ++i) {
func(aImg);
}
// run
let s = new Date().getTime();
for (let i = 0; i < iterations; ++i) {
func(aImg);
}
let e = new Date().getTime();
console.log(func.name, func(aImg), s, e, (e - s) + "ms", ((e - s) / iterations).toFixed(4) + "ms");
Components.utils.forceGC();
return ((e - s) / iterations);
}
let known = {};
function putImage() {
let [rgb_ref, rgb_opt] = [
getDominantColor(this),
getDominantColor_opt(this)
].map(function(e) e.join(","));
let div = document.createElement("div");
div.style.margin = "1ex";
div.style.padding = "1ex";
if (rgb_ref != rgb_opt) {
div.style.borderLeft = "2px solid red";
}
else {
div.style.borderLeft = "2px solid transparent";
}
for each (let rgb in [rgb_ref, rgb_opt]) {
let img = this.cloneNode(false);
img.style.padding = "6px";
img.style.margin = "2ex";
img.style.background = "-moz-linear-gradient(rgba(" + rgb + ",0.15), rgba(" + rgb + ",0.33))";
img.style.border = "1px solid rgb(" + rgb + ")";
img.style.borderRadius = "5px";
img.setAttribute("alt", rgb);
img.setAttribute("title", rgb);
div.appendChild(img);
}
document.body.appendChild(div);
}
let iterations = 100;
let imgs = ["https://tn123.org/favicon.ico",
"https://bugzilla.mozilla.org/extensions/BMO/web/images/bugzilla.png",
"http://www.facebook.com/favicon.ico",
"http://twitter.com/favicon.ico",
"http://mail.google.com/favicon.ico",
"http://google.com/favicon.ico",
"http://vbulletin.com/favicon.ico",
"http://dailymile.com/favicon.ico",
"http://getfirebug.com/img/favicon.ico",
"https://github.com/favicon.ico",
"http://mozilla.com/favicon.ico",
"http://mozilla.org/favicon.ico",
"http://mozillalabs.com/wp-content/themes/labs2.0/favicon.png",
"https://static-cdn.addons.mozilla.net/media/img/favicon.ico",
"http://mozdev.org/favicon.ico",
"http://en.wikipedia.org/favicon.ico",
"http://www.google.com/images/icons/product/chrome-16.png",
"http://www.opera.com/favicon.ico",
"http://www.microsoft.com/favicon.ico",
"http://yahoo.com/favicon.ico",
"http://baidu.com/favicon.ico",
"http://www.volkswagen.com/favicon.ico",
"http://www.quibblo.com/favicon.ico",
"http://sstatic.net/stackoverflow/img/favicon.ico",
];
// top sites
imgs = imgs.concat(['http://Domain/favicon.ico', 'http://facebook.com/favicon.ico', 'http://youtube.com/favicon.ico', 'http://live.com/favicon.ico', 'http://baidu.com/favicon.ico', 'http://blogspot.com/favicon.ico', 'http://wikipedia.org/favicon.ico', 'http://qq.com/favicon.ico', 'http://twitter.com/favicon.ico', 'http://msn.com/favicon.ico', 'http://yahoo.co.jp/favicon.ico', 'http://taobao.com/favicon.ico', 'http://amazon.com/favicon.ico', 'http://sina.com.cn/favicon.ico', 'http://linkedin.com/favicon.ico', 'http://bing.com/favicon.ico', 'http://wordpress.com/favicon.ico', 'http://ebay.com/favicon.ico', 'http://yandex.ru/favicon.ico', 'http://microsoft.com/favicon.ico', 'http://163.com/favicon.ico', 'http://paypal.com/favicon.ico', 'http://mail.ru/favicon.ico', 'http://fc2.com/favicon.ico', 'http://flickr.com/favicon.ico', 'http://imdb.com/favicon.ico', 'http://vkontakte.ru/favicon.ico', 'http://craigslist.org/favicon.ico', 'http://apple.com/favicon.ico', 'http://bbc.co.uk/favicon.ico', 'http://sohu.com/favicon.ico', 'http://livejasmin.com/favicon.ico', 'http://go.com/favicon.ico', 'http://conduit.com/favicon.ico', 'http://youku.com/favicon.ico', 'http://tudou.com/favicon.ico', 'http://soso.com/favicon.ico', 'http://ask.com/favicon.ico', 'http://aol.com/favicon.ico', 'http://xvideos.com/favicon.ico', 'http://cnn.com/favicon.ico', 'http://hotfile.com/favicon.ico', 'http://megaupload.com/favicon.ico', 'http://xhamster.com/favicon.ico', 'http://mediafire.com/favicon.ico', 'http://pornhub.com/favicon.ico', 'http://myspace.com/favicon.ico', 'http://tumblr.com/favicon.ico', 'http://espn.go.com/favicon.ico', 'http://godaddy.com/favicon.ico', 'http://adobe.com/favicon.ico', 'http://about.com/favicon.ico', 'http://ameblo.jp/favicon.ico', 'http://4shared.com/favicon.ico', 'http://zedo.com/favicon.ico', 'http://rakuten.co.jp/favicon.ico', 'http://livejournal.com/favicon.ico', 'http://ebay.de/favicon.ico', 'http://orkut.com.br/favicon.ico', 'http://doubleclick.com/favicon.ico', 'http://youporn.com/favicon.ico', 'http://wordpress.org/favicon.ico', 'http://ifeng.com/favicon.ico', 'http://yieldmanager.com/favicon.ico', 'http://cnet.com/favicon.ico', 'http://uol.com.br/favicon.ico', 'http://thepiratebay.org/favicon.ico', 'http://livedoor.com/favicon.ico', 'http://sogou.com/favicon.ico', 'http://rapidshare.com/favicon.ico', 'http://imageshack.us/favicon.ico', 'http://nytimes.com/favicon.ico', 'http://amazon.de/favicon.ico', 'http://alibaba.com/favicon.ico', 'http://weather.com/favicon.ico', 'http://megavideo.com/favicon.ico', 'http://ezinearticles.com/favicon.ico', 'http://netflix.com/favicon.ico', 'http://ebay.co.uk/favicon.ico', 'http://mozilla.com/favicon.ico', 'http://ehow.com/favicon.ico']);
let img = new Image();
img.onload = function() {
let ref = bench(getDominantColor, iterations, this);
let opt = bench(getDominantColor_opt, iterations, this);
console.log(ref.toFixed(3), "vs", opt.toFixed(3), ((ref - opt) * 100.0 / ref).toFixed(2) + "%");
for each (let i in imgs) {
let img = new Image();
img.onload = putImage;
img.src = i;
}
}
img.src = imgs[0];
</script>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment