mirror of
https://github.com/janishutz/color-thief.git
synced 2025-11-25 13:54:25 +00:00
All of jfsiii awesome edits are now in place.
This commit is contained in:
66
index.html
66
index.html
@@ -35,7 +35,6 @@
|
|||||||
</div> <!--! end of #container -->
|
</div> <!--! end of #container -->
|
||||||
|
|
||||||
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.2.min.js"><\/script>')</script>
|
<script>window.jQuery || document.write('<script src="js/libs/jquery-1.6.2.min.js"><\/script>')</script>
|
||||||
<script src="js/libs/jquery.imagesloaded.js"></script>
|
|
||||||
<script src="js/libs/jquery.lettering.js"></script>
|
<script src="js/libs/jquery.lettering.js"></script>
|
||||||
<script src="js/libs/mustache.js"></script>
|
<script src="js/libs/mustache.js"></script>
|
||||||
|
|
||||||
@@ -65,69 +64,6 @@
|
|||||||
{{/images}}
|
{{/images}}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<script>
|
<script src="index.js"></script>
|
||||||
$(document).ready(function(){
|
|
||||||
|
|
||||||
// Use mustache.js templating to create layout
|
|
||||||
|
|
||||||
var imageArray = { images: [
|
|
||||||
{"file": "3.jpg"},
|
|
||||||
{"file": "4.jpg"},
|
|
||||||
{"file": "5.jpg"},
|
|
||||||
{"file": "logo1.png"},
|
|
||||||
{"file": "icon1.png", "colorCount": "4", "class": "fbIcon"}
|
|
||||||
]};
|
|
||||||
|
|
||||||
var html = Mustache.to_html($('#template').html(), imageArray);
|
|
||||||
$('#main').append(html);
|
|
||||||
|
|
||||||
// Use lettering.js to give letter by letter styling control for the h1 title
|
|
||||||
$("h1").lettering();
|
|
||||||
|
|
||||||
|
|
||||||
// Once images are loaded, loop through each one, getting dominant color
|
|
||||||
// and palette and displaying them.
|
|
||||||
$('img').imagesLoaded(function(){
|
|
||||||
|
|
||||||
$('img').each(function(index){
|
|
||||||
|
|
||||||
var imageSection = $(this).closest('.imageSection'),
|
|
||||||
swatchEl;
|
|
||||||
|
|
||||||
// Dominant Color
|
|
||||||
var dominantColor = getDominantColor(this);
|
|
||||||
|
|
||||||
swatchEl = $('<div>', {
|
|
||||||
'class': 'swatch'
|
|
||||||
}).css('background-color','rgba('+dominantColor.r+','+dominantColor.g+ ','+dominantColor.b+', 1)');
|
|
||||||
imageSection.find('.dominantColor .swatches').append(swatchEl);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Palette
|
|
||||||
var colorCount = $(this).attr('data-colorcount')? $(this).data('colorcount'): 10;
|
|
||||||
var medianPalette = createPalette(this, colorCount);
|
|
||||||
|
|
||||||
var medianCutPalette = imageSection.find('.medianCutPalette .swatches');
|
|
||||||
$.each(medianPalette, function(index, value){
|
|
||||||
swatchEl = $('<div>', {
|
|
||||||
'class': 'swatch'
|
|
||||||
}).css('background-color','rgba('+value[0]+','+value[1]+ ','+value[2]+', 1)');
|
|
||||||
medianCutPalette.append(swatchEl);
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
</script>
|
|
||||||
|
|
||||||
<script src="http://www.google-analytics.com/urchin.js" type="text/javascript"></script>
|
|
||||||
<script type="text/javascript">
|
|
||||||
_uacct = "UA-2196019-1";
|
|
||||||
urchinTracker();
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
45
index.js
Normal file
45
index.js
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
$(document).ready(function () {
|
||||||
|
|
||||||
|
// Use mustache.js templating to create layout
|
||||||
|
|
||||||
|
var imageArray = { images: [
|
||||||
|
{"file": "3.jpg"},
|
||||||
|
{"file": "4.jpg"},
|
||||||
|
{"file": "5.jpg"},
|
||||||
|
{"file": "logo1.png"},
|
||||||
|
{"file": "icon1.png", "colorCount": "4", "class": "fbIcon"}
|
||||||
|
]};
|
||||||
|
|
||||||
|
var html = Mustache.to_html($('#template').html(), imageArray);
|
||||||
|
$('#main').append(html);
|
||||||
|
|
||||||
|
// Use lettering.js to give letter by letter styling control for the h1 title
|
||||||
|
$("h1").lettering();
|
||||||
|
|
||||||
|
|
||||||
|
// For each image:
|
||||||
|
// Once image is loaded, get dominant color and palette and display them.
|
||||||
|
$('img').bind('load', function (event) {
|
||||||
|
var image = event.target;
|
||||||
|
var $image = $(image);
|
||||||
|
var imageSection = $image.closest('.imageSection');
|
||||||
|
var appendColors = function (colors, root) {
|
||||||
|
$.each(colors, function (index, value) {
|
||||||
|
var swatchEl = $('<div>', {'class': 'swatch'})
|
||||||
|
.css('background-color', 'rgba('+ value +', 1)');
|
||||||
|
root.append(swatchEl);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Dominant Color
|
||||||
|
var dominantColor = getDominantColor(image);
|
||||||
|
var dominantSwatch = imageSection.find('.dominantColor .swatches');
|
||||||
|
appendColors([dominantColor], dominantSwatch);
|
||||||
|
|
||||||
|
// Palette
|
||||||
|
var colorCount = $image.attr('data-colorcount') ? $image.data('colorcount') : 10;
|
||||||
|
var medianPalette = createPalette(image, colorCount);
|
||||||
|
var medianCutPalette = imageSection.find('.medianCutPalette .swatches');
|
||||||
|
appendColors(medianPalette, medianCutPalette);
|
||||||
|
});
|
||||||
|
});
|
||||||
@@ -16,49 +16,49 @@
|
|||||||
* createAreaBasedPalette()
|
* createAreaBasedPalette()
|
||||||
*
|
*
|
||||||
* Requires jquery and quantize.js.
|
* Requires jquery and quantize.js.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
CanvasImage Class
|
CanvasImage Class
|
||||||
Class that wraps the html image element and canvas.
|
Class that wraps the html image element and canvas.
|
||||||
It also simplifies some of the canvas context manipulation
|
It also simplifies some of the canvas context manipulation
|
||||||
with a set of helper functions.
|
with a set of helper functions.
|
||||||
*/
|
*/
|
||||||
var CanvasImage = function(image){
|
var CanvasImage = function (image) {
|
||||||
// If jquery object is passed in, get html element
|
// If jquery object is passed in, get html element
|
||||||
this.imgEl = (image.jquery)? image[0]: image;
|
this.imgEl = (image.jquery) ? image[0] : image;
|
||||||
|
|
||||||
this.canvas = document.createElement('canvas'),
|
this.canvas = document.createElement('canvas');
|
||||||
this.context = this.canvas.getContext('2d');
|
this.context = this.canvas.getContext('2d');
|
||||||
|
|
||||||
document.body.appendChild(this.canvas);
|
document.body.appendChild(this.canvas);
|
||||||
|
|
||||||
this.width = this.canvas.width = $(this.imgEl).width(),
|
this.width = this.canvas.width = $(this.imgEl).width();
|
||||||
this.height = this.canvas.height = $(this.imgEl).height();
|
this.height = this.canvas.height = $(this.imgEl).height();
|
||||||
|
|
||||||
this.context.drawImage(this.imgEl, 0, 0);
|
this.context.drawImage(this.imgEl, 0, 0);
|
||||||
}
|
};
|
||||||
|
|
||||||
CanvasImage.prototype.clear = function() {
|
CanvasImage.prototype.clear = function () {
|
||||||
this.context.clearRect(0, 0, this.width, this.height);
|
this.context.clearRect(0, 0, this.width, this.height);
|
||||||
}
|
};
|
||||||
|
|
||||||
CanvasImage.prototype.update = function(imageData) {
|
CanvasImage.prototype.update = function (imageData) {
|
||||||
this.context.putImageData(imageData, 0, 0);
|
this.context.putImageData(imageData, 0, 0);
|
||||||
}
|
};
|
||||||
|
|
||||||
CanvasImage.prototype.getPixelCount = function() {
|
CanvasImage.prototype.getPixelCount = function () {
|
||||||
return this.width * this.height;
|
return this.width * this.height;
|
||||||
}
|
};
|
||||||
|
|
||||||
CanvasImage.prototype.getImageData = function() {
|
CanvasImage.prototype.getImageData = function () {
|
||||||
return this.context.getImageData(0, 0, this.width, this.height);
|
return this.context.getImageData(0, 0, this.width, this.height);
|
||||||
}
|
};
|
||||||
|
|
||||||
CanvasImage.prototype.removeCanvas = function() {
|
CanvasImage.prototype.removeCanvas = function () {
|
||||||
$(this.canvas).remove();
|
$(this.canvas).remove();
|
||||||
}
|
};
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@@ -67,41 +67,16 @@ CanvasImage.prototype.removeCanvas = function() {
|
|||||||
*
|
*
|
||||||
* Use the median cut algorithm provided by quantize.js to cluster similar
|
* Use the median cut algorithm provided by quantize.js to cluster similar
|
||||||
* colors and return the base color from the largest cluster.
|
* colors and return the base color from the largest cluster.
|
||||||
*/
|
*/
|
||||||
function getDominantColor(sourceImage){
|
function getDominantColor(sourceImage) {
|
||||||
|
|
||||||
var palette = [];
|
var palette = createPalette(sourceImage, 5);
|
||||||
|
var dominant = palette[0];
|
||||||
|
|
||||||
// Create custom CanvasImage object
|
return dominant;
|
||||||
var image = new CanvasImage(sourceImage),
|
|
||||||
imageData = image.getImageData(),
|
|
||||||
pixels = imageData.data,
|
|
||||||
pixelCount = image.getPixelCount();
|
|
||||||
|
|
||||||
// Store the RGB values in an array format suitable for quantize function
|
|
||||||
var pixelArray = [];
|
|
||||||
for (var i = 0; i < pixelCount; i++) {
|
|
||||||
// If pixel is mostly opaque and not white
|
|
||||||
if(pixels[i*4+3] >= 125){
|
|
||||||
if(!(pixels[i*4] > 250 && pixels[i*4+1] > 250 && pixels[i*4+2] > 250)){
|
|
||||||
pixelArray.push( [pixels[i*4], pixels[i*4+1], pixels[i*4+2]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send array to quantize function which clusters values
|
|
||||||
// using median cut algorithm
|
|
||||||
var cmap = MMCQ.quantize(pixelArray, 5);
|
|
||||||
var newPalette = cmap.palette();
|
|
||||||
|
|
||||||
// Clean up
|
|
||||||
image.removeCanvas();
|
|
||||||
|
|
||||||
return {r: newPalette[0][0], g: newPalette[0][1], b: newPalette[0][2]};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* createPalette(sourceImage, colorCount)
|
* createPalette(sourceImage, colorCount)
|
||||||
* returns array[ {r: num, g: num, b: num}, {r: num, g: num, b: num}, ...]
|
* returns array[ {r: num, g: num, b: num}, {r: num, g: num, b: num}, ...]
|
||||||
@@ -110,37 +85,41 @@ function getDominantColor(sourceImage){
|
|||||||
* colors.
|
* colors.
|
||||||
*
|
*
|
||||||
* BUGGY: Function does not always return the requested amount of colors. It can be +/- 2.
|
* BUGGY: Function does not always return the requested amount of colors. It can be +/- 2.
|
||||||
*/
|
*/
|
||||||
function createPalette(sourceImage, colorCount){
|
function createPalette(sourceImage, colorCount) {
|
||||||
|
|
||||||
var palette = [];
|
// Create custom CanvasImage object
|
||||||
|
var image = new CanvasImage(sourceImage),
|
||||||
|
imageData = image.getImageData(),
|
||||||
|
pixels = imageData.data,
|
||||||
|
pixelCount = image.getPixelCount();
|
||||||
|
|
||||||
// Create custom CanvasImage object
|
// Store the RGB values in an array format suitable for quantize function
|
||||||
var image = new CanvasImage(sourceImage),
|
var pixelArray = [];
|
||||||
imageData = image.getImageData(),
|
for (var i = 0, offset, r, g, b, a; i < pixelCount; i++) {
|
||||||
pixels = imageData.data,
|
offset = i * 4;
|
||||||
pixelCount = image.getPixelCount();
|
r = pixels[offset + 0];
|
||||||
|
g = pixels[offset + 1];
|
||||||
|
b = pixels[offset + 2];
|
||||||
|
a = pixels[offset + 3];
|
||||||
|
// If pixel is mostly opaque and not white
|
||||||
|
if (a >= 125) {
|
||||||
|
if (!(r > 250 && g > 250 && b > 250)) {
|
||||||
|
pixelArray.push([r, g, b]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Store the RGB values in an array format suitable for quantize function
|
// Send array to quantize function which clusters values
|
||||||
var pixelArray = [];
|
// using median cut algorithm
|
||||||
for (var i = 0; i < pixelCount; i++) {
|
|
||||||
// If pixel is mostly opaque and not white
|
|
||||||
if(pixels[i*4+3] >= 125){
|
|
||||||
if(!(pixels[i*4] > 250 && pixels[i*4+1] > 250 && pixels[i*4+2] > 250)){
|
|
||||||
pixelArray.push( [pixels[i*4], pixels[i*4+1], pixels[i*4+2]]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Send array to quantize function which clusters values
|
var cmap = MMCQ.quantize(pixelArray, colorCount);
|
||||||
// using median cut algorithm
|
var palette = cmap.palette();
|
||||||
var cmap = MMCQ.quantize(pixelArray, colorCount);
|
|
||||||
var newPalette = cmap.palette();
|
|
||||||
|
|
||||||
// Clean up
|
// Clean up
|
||||||
image.removeCanvas();
|
image.removeCanvas();
|
||||||
|
|
||||||
return newPalette;
|
return palette;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -151,40 +130,40 @@ function createPalette(sourceImage, colorCount){
|
|||||||
* Add up all pixels RGB values and return average.
|
* Add up all pixels RGB values and return average.
|
||||||
* Tends to return muddy gray/brown color. Most likely, you'll be better
|
* Tends to return muddy gray/brown color. Most likely, you'll be better
|
||||||
* off using getDominantColor() instead.
|
* off using getDominantColor() instead.
|
||||||
*/
|
*/
|
||||||
function getAverageRGB(sourceImage) {
|
function getAverageRGB(sourceImage) {
|
||||||
// Config
|
// Config
|
||||||
var sampleSize = 10;
|
var sampleSize = 10;
|
||||||
|
|
||||||
// Create custom CanvasImage object
|
// Create custom CanvasImage object
|
||||||
var image = new CanvasImage(sourceImage),
|
var image = new CanvasImage(sourceImage),
|
||||||
imageData = image.getImageData(),
|
imageData = image.getImageData(),
|
||||||
pixels = imageData.data,
|
pixels = imageData.data,
|
||||||
pixelCount = image.getPixelCount();
|
pixelCount = image.getPixelCount();
|
||||||
|
|
||||||
// Reset vars
|
// Reset vars
|
||||||
var i = 0,
|
var i = 0,
|
||||||
count = 0,
|
count = 0,
|
||||||
rgb = {r:0,g:0,b:0};
|
rgb = {r:0, g:0, b:0};
|
||||||
|
|
||||||
// Loop through every # pixels. (# is set in Config above via the blockSize var)
|
// Loop through every # pixels. (# is set in Config above via the blockSize var)
|
||||||
// Add all the red values together, repeat for blue and green.
|
// Add all the red values together, repeat for blue and green.
|
||||||
// Last step, divide by the number of pixels checked to get average.
|
// Last step, divide by the number of pixels checked to get average.
|
||||||
while ( (i += sampleSize * 4) < pixelCount ) {
|
while ( (i += sampleSize * 4) < pixelCount ) {
|
||||||
// if pixel is mostly opaque
|
// if pixel is mostly opaque
|
||||||
if(pixels[i+3] > 125){
|
if (pixels[i+3] > 125) {
|
||||||
++count;
|
++count;
|
||||||
rgb.r += pixels[i];
|
rgb.r += pixels[i];
|
||||||
rgb.g += pixels[i+1];
|
rgb.g += pixels[i+1];
|
||||||
rgb.b += pixels[i+2];
|
rgb.b += pixels[i+2];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
rgb.r = Math.floor(rgb.r/count);
|
rgb.r = ~~(rgb.r/count);
|
||||||
rgb.g = Math.floor(rgb.g/count);
|
rgb.g = ~~(rgb.g/count);
|
||||||
rgb.b = Math.floor(rgb.b/count);
|
rgb.b = ~~(rgb.b/count);
|
||||||
|
|
||||||
return rgb;
|
return rgb;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -197,56 +176,52 @@ function getAverageRGB(sourceImage) {
|
|||||||
*
|
*
|
||||||
* BUGGY: Function does not always return the requested amount of colors. It can be +/- 2.
|
* BUGGY: Function does not always return the requested amount of colors. It can be +/- 2.
|
||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
function createAreaBasedPalette(sourceImage, colorCount){
|
function createAreaBasedPalette(sourceImage, colorCount) {
|
||||||
|
|
||||||
var palette = [];
|
var palette = [];
|
||||||
|
|
||||||
// Create custom CanvasImage object
|
// Create custom CanvasImage object
|
||||||
var image = new CanvasImage(sourceImage),
|
var image = new CanvasImage(sourceImage),
|
||||||
imageData = image.getImageData(),
|
imageData = image.getImageData(),
|
||||||
pixels = imageData.data,
|
pixels = imageData.data,
|
||||||
pixelCount = image.getPixelCount();
|
pixelCount = image.getPixelCount();
|
||||||
|
|
||||||
|
|
||||||
// How big a pixel area does each palette color get
|
// How big a pixel area does each palette color get
|
||||||
var rowCount = colCount = Math.round(Math.sqrt(colorCount)),
|
var rowCount = Math.round(Math.sqrt(colorCount)),
|
||||||
colWidth = Math.round(image.width / colCount),
|
colCount = rowCount,
|
||||||
rowHeight = Math.round(image.height / rowCount);
|
colWidth = Math.round(image.width / colCount),
|
||||||
|
rowHeight = Math.round(image.height / rowCount);
|
||||||
|
|
||||||
var count = offset = rowOffset = vertOffset = horizOffset = 0,
|
// Loop through pixels section by section.
|
||||||
rgb = {r:0,g:0,b:0};
|
// At the end of each section, push the average rgb color to palette array.
|
||||||
|
for (var i = 0, vertOffset; i<rowCount; i++) {
|
||||||
|
vertOffset = i * rowHeight * image.width * 4;
|
||||||
|
|
||||||
// Loop through pixels section by section.
|
for (var j = 0, horizOffset, rgb, count; j<colCount; j++) {
|
||||||
// At the end of each section, push the average rgb color to palette array.
|
horizOffset = j * colWidth * 4;
|
||||||
for(var i=0; i<rowCount; i++){
|
rgb = {r:0, g:0, b:0};
|
||||||
vertOffset = i * rowHeight * image.width * 4;
|
count = 0;
|
||||||
|
|
||||||
for(var j=0; j<colCount; j++){
|
for (var k = 0, rowOffset; k < rowHeight; k++) {
|
||||||
horizOffset = j * colWidth * 4;
|
rowOffset = k * image.width * 4;
|
||||||
|
|
||||||
for( var k = 0; k < rowHeight; k++){
|
for (var l = 0, offset; l < colWidth; l++) {
|
||||||
rowOffset = k * image.width * 4;
|
offset = vertOffset + horizOffset + rowOffset + (l * 4);
|
||||||
|
rgb.r += pixels[offset];
|
||||||
|
rgb.g += pixels[offset+1];
|
||||||
|
rgb.b += pixels[offset+2];
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
for( var l = 0; l < colWidth; l++){
|
}
|
||||||
offset = vertOffset + horizOffset + rowOffset + (l * 4);
|
rgb.r = ~~(rgb.r/count);
|
||||||
rgb.r += pixels[offset];
|
rgb.g = ~~(rgb.g/count);
|
||||||
rgb.g += pixels[offset+1];
|
rgb.b = ~~(rgb.b/count);
|
||||||
rgb.b += pixels[offset+2];
|
palette.push(rgb);
|
||||||
count++;
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
return palette;
|
||||||
rgb.r = Math.floor(rgb.r/count);
|
|
||||||
rgb.g = Math.floor(rgb.g/count);
|
|
||||||
rgb.b = Math.floor(rgb.b/count);
|
|
||||||
palette.push(rgb);
|
|
||||||
|
|
||||||
// reset before next section
|
|
||||||
rgb = {r:0,g:0,b:0};
|
|
||||||
count = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return palette;
|
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user