Skip to content

Instantly share code, notes, and snippets.

@yogthos
Created April 4, 2013 21:41
Show Gist options
  • Save yogthos/5314625 to your computer and use it in GitHub Desktop.
Save yogthos/5314625 to your computer and use it in GitHub Desktop.
(function() {
var colorChooser, AlbumImage, AlbumColors;
/* colorChooser
* A series of function that is used to pick up 3 colors among 10 dominating colors
*/
colorChooser = {
colorStringToRGBArray: function(colorString) {
var n, arr = colorString.split(',');
for (n = 0; n < arr.length; n++) {
colorString[n] = parseInt(colorString[n], 10);
}
return colorString;
},
colorDistance: function(colorA, colorB) {
var colorARGB = colorA,
colorBRGB = colorB,
distance = 0,
n;
for (n = 0; n < colorARGB.length; n++) {
distance += (colorARGB[n] - colorBRGB[n]) * (colorARGB[n] - colorBRGB[n]);
}
return Math.sqrt(distance);
},
getDistances: function(colors) {
var distances = [],
c1, c2;
for (c1 = 0; c1 < colors.length; c1++) {
distances[c1] = [];
for (c2 = 0; c2 < colors.length; c2++) {
distances[c1][c2] = colorChooser.colorDistance(colors[c1], colors[c2]);
}
}
return distances;
},
chooseThreeColors: function(colors) {
var color1 = colors[0],
colorDistances = colorChooser.getDistances(colors),
color2Index = 0,
color3Index = 1, c, c2, color2, color3;
for (c = 0; c < colors.length; c++) {
if (colorDistances[0][c] > colorDistances[0][color2Index]) {
color2Index = c;
}
}
color2 = colors[color2Index];
color3Index = color2Index + 1;
if (color3Index >= colors.length) {
color3Index = 1;
}
for (c = 1; c < colors.length; c++) {
if (c !== color2Index && colorDistances[0][c] > colorDistances[0][color3Index]) {
color3Index = c;
}
}
color3 = colors[color3Index];
return [color1, color2, color3];
}
};
/*
* A Class for the to wrap image,
* used for counting raw color pixels
*/
AlbumImage = function(url) {
this.url = url;
};
AlbumImage.prototype.fetch = function(callback) {
var that = this;
this.image = new Image();
this.image.onload = function() {
if (callback) {
callback(this);
}
};
this.image.src = this.url;
};
AlbumImage.prototype.getCanvas = function() {
if (this.canvas) {
return this.canvas;
}
var canvas, context;
canvas = document.createElement('canvas');
canvas.width = this.image.width;
canvas.height = this.image.height;
context = canvas.getContext('2d');
context.drawImage(this.image, 0, 0);
return (this.canvas = canvas);
};
AlbumImage.prototype.getPixelArray = function() {
return this.getCanvas().getContext('2d').getImageData(0, 0, this.image.width, this.image.height).data;
};
AlbumImage.prototype.getColors = function() {
if (this.colors) {
return this.colors;
}
var p, colors = [],
pixelArray = this.getPixelArray();
for (p = 0; p < pixelArray.length; p += 4) {
colors.push([pixelArray[p], pixelArray[p + 1], pixelArray[p + 2]]);
}
return (this.colors = colors);
};
/*
* AlbumColors
* Generate pallete among dominating colors
*/
AlbumColors = function(imageUrl) {
this.imageUrl = imageUrl;
this.image = new AlbumImage(imageUrl);
};
AlbumColors.prototype.getColors = function(callback) {
var that = this;
this.image.fetch(function() {
that.colors = that.extractMainColors(10);
if (callback) {
callback(colorChooser.chooseThreeColors(that.colors));
}
});
};
AlbumColors.prototype.generateRGBString = function(color) {
return color.join(',');
};
AlbumColors.prototype.getBucket = function(color) {
// Throw a color into one color bucket
var bucket = [],
c;
for (c = 0; c < color.length; c++) {
// Naive
bucket[c] = Math.round(color[c] / 64) * 64;
}
return bucket;
};
AlbumColors.prototype.getColorsByBucket = function() {
if (this.colorsByBucket) {
return this.colorsByBucket;
}
var colors, c, color, bucket, colorsByBucket, rgbString;
colors = this.image.getColors();
colorsByBucket = {};
for (c = 0; c < colors.length; c++) {
color = colors[c];
bucket = this.getBucket(color);
rgbString = this.generateRGBString(bucket);
colorsByBucket[rgbString] = colorsByBucket[rgbString] || [];
if (colorsByBucket[rgbString]) {
colorsByBucket[rgbString].push(color);
}
}
return (this.colorsByBucket = colorsByBucket);
};
AlbumColors.prototype.getAverageColor = function(colors) {
var c, r = 0,
g = 0,
b = 0;
for (c = 0; c < colors.length; c++) {
r += colors[c][0];
g += colors[c][1];
b += colors[c][2];
}
r = parseInt(r / colors.length, 10);
g = parseInt(g / colors.length, 10);
b = parseInt(b / colors.length, 10);
return [r, g, b];
};
AlbumColors.prototype.getColorBuckets = function() {
if (this.colorBuckets) {
return this.colorBuckets;
}
var colorsByBucket = this.getColorsByBucket(),
bucket, buckets = [];
for (bucket in colorsByBucket) {
if (colorsByBucket.hasOwnProperty(bucket)) {
buckets.push(bucket);
}
}
return (this.colorBuckets = buckets);
};
AlbumColors.prototype.extractMainColors = function(count) {
if (!this.mainColors) {
var colorsByBucket = this.getColorsByBucket(),
colorBuckets = this.getColorBuckets().slice(0),
b, mainColors = [];
colorBuckets.sort(function(colorBucketA, colorBucketB) {
return colorsByBucket[colorBucketB].length - colorsByBucket[colorBucketA].length;
});
for (b = 0; b < colorBuckets.length; b++) {
mainColors.push(this.getAverageColor(colorsByBucket[colorBuckets[b]]));
}
this.mainColors = mainColors;
}
return this.mainColors.slice(0, count);
};
AlbumColors.AlbumImage = AlbumImage;
window.AlbumColors = AlbumColors;
}());
<html>
<head>
<title>Interop test</title>
<style>
div {
padding: 10px;
}
</style>
</head>
<body>
<div>
<div>
Album 1 <img src="/img/1.jpg" />
</div>
<div>
Album 2 <img src="/img/2.png" />
</div>
<div>
Album 3 <img src="/img/3.jpg" />
</div>
</div>
<script type="text/javascript" src="/js/colors.js"></script>
<script type="text/javascript" src="/js/site.js"></script>
</body>
</html>
(ns site
(:require
[domina :as d]
[domina.css :as css]))
(defn set-colors [node]
(.getColors (js/AlbumColors. (.-src node))
(fn [[[r1,g1,b1]
[r2,g2,b2]
[r3,g3,b3]]]
(set! (.-backgroundColor (.-style (.-parentNode node)))
(str "rgb(" r3 "," g3 "," b3 ")"))
(set! (.-color (.-style (.-parentNode node)))
(str "rgb(" r1 "," g1 "," b1 ")")))))
(doseq [node (d/nodes (css/sel "img"))]
(set-colors node))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment