removed convolve pack. Added pixastic emboss filter

This commit is contained in:
Eric Rowell 2014-01-04 05:21:44 -08:00
parent 7f0dc2085b
commit 0d944aac27
6 changed files with 267 additions and 382 deletions

View File

@ -17,7 +17,7 @@ module.exports = function(grunt) {
'src/filters/Mask.js',
'src/filters/RGB.js',
'src/filters/HSV.js',
'src/filters/ConvolvePack.js',
'src/filters/Emboss.js',
'src/filters/Enhance.js',
'src/filters/Posterize.js',
'src/filters/Noise.js',

View File

@ -1,201 +0,0 @@
(function() {
// Definition of a gaussian function
var gaussian = function(x,mean,sigma){
var dx = x - mean;
return Math.pow(Math.E, -dx*dx / (2*sigma*sigma));
};
var make_blur_kernel = function( size, scale, sigma ){
// make sure size is odd:
if( size % 2 === 0 ){ size += 1; }
// Generate the kernel, we can just multiply 2 single dimensional
// gaussians to get a 2D guassian
var kernel = [], i,j, row;
for( i=0; i<size; i+=1 ){
row = [];
for( j=0; j<size; j+=1 ){
row.push( scale * gaussian(i,size/2,sigma) * gaussian(j,size/2,sigma) );
}
kernel.push(row);
}
return kernel;
};
var make_edge_detect_kernel = function( size, scale, sigma ){
// make sure size is odd:
if( size % 2 === 0 ){ size += 1; }
// Create a difference-of-gaussians kernel (by subtracting gaussians)
// 1.6 is a good sigma ratio to approximate a laplacian of gaussian
var kernel = [], i,j, row, g;
for( i=0; i<size; i+=1 ){
row = [];
for( j=0; j<size; j+=1 ){
g1 = gaussian(i,size/2,sigma) * gaussian(j,size/2,sigma);
g2 = gaussian(i,size/2,sigma*1.6) * gaussian(j,size/2,sigma*1.6);
row.push( scale * (g2-g1) );
}
kernel.push(row);
}
return kernel;
};
var make_soft_blur_kernel = function( size, percent ){
// A soft blur is achieve by blurring the image then
// merging the blured and unblurred image (ie 60/40).
// Instead of that we've scaling the blur kernel (ie 60)
// and adding the identity scaled (ie 40) to the kernel
var kernel = make_blur_kernel( size, percent, 1 ),
mid = Math.floor(size/2);
kernel[mid][mid] += 1-percent;
return kernel;
};
var make_unsharp_kernel = function( size, percent ){
// An 'unsharp mask' is made by blurring the inverted image
// and combining it with the original (like a soft blur but
// with the blur negated). We can achieve this by negating
// blur kernel, and adding twice the identity to that kernel.
var kernel = make_blur_kernel( size, -percent, 1 ),
mid = Math.floor(size/2);
kernel[mid][mid] += 1+percent;
return kernel;
};
Kinetic.Factory.addFilterGetterSetter(Kinetic.Node, 'filterAmount', 50);
/**
* get the current filter amount
* @name getFilterAmount
* @method
* @memberof Kinetic.Image.prototype
*/
/**
* set the current filter amount 0 = no filter, 100 = max filter
* @name setFilterAmount
* @method
* @memberof Kinetic.Image.prototype
*/
/**
* Unsharp Mask Filter.
* @function
* @memberof Kinetic.Filters
* @param {Object} imageData
* @author ippo615
*/
/**
* Soft Blur Filter.
* @function
* @memberof Kinetic.Filters
* @param {Object} imageData
* @author ippo615
*/
/**
* Edge Filter.
* Makes edges more noticable.
* @function
* @memberof Kinetic.Filters
* @param {Object} imageData
* @author ippo615
*/
/**
* Emboss Filter.
* Makes the image apear to have some depth.
* @function
* @memberof Kinetic.Filters
* @param {Object} imageData
* @author ippo615
*/
var convolve = function (src, dst, opt) {
var xSize = src.width,
ySize = src.height,
srcPixels = src.data,
dstPixels = dst.data;
// Determine the size and demsionality of the matrix
// Note: it should be square and odd (3,5,7,9 etc...)
var matrix = opt.kernel;
var matrixSizeX = matrix.length,
matrixSizeY = matrix[0].length,
matrixMidX = Math.floor(matrix.length / 2),
matrixMidY = Math.floor(matrix[0].length / 2);
// Accumlators and positions for iterating
var r, g, b, a, x, y, px, py, pos, i, j;
for (y = 0; y < ySize; y += 1) {
for (x = 0; x < xSize; x += 1) {
// Perform the convolution
r = 0; g = 0; b = 0; a = 0;
for (i = 0; i < matrixSizeX; i += 1) {
for (j = 0; j < matrixSizeY; j += 1) {
// tile the image to account for pixels past the
// edge (and make sure they are positive)
px = (x + i - matrixMidX) % xSize;
px = (px > 0) ? px : -px;
py = (y + i - matrixMidY) % ySize;
py = (py > 0) ? py : -py;
// get the pixel and convolve
pos = (py * xSize + px) * 4;
r += matrix[j][i] * srcPixels[pos + 0];
g += matrix[j][i] * srcPixels[pos + 1];
b += matrix[j][i] * srcPixels[pos + 2];
//a += matrix[j][i]*srcPixels[pos+3];
}
}
// Store the result
pos = (y * xSize + x) * 4;
dstPixels[pos + 0] = r;
dstPixels[pos + 1] = g;
dstPixels[pos + 2] = b;
dstPixels[pos + 3] = srcPixels[pos + 3];
}
}
};
Kinetic.Filters.Emboss = Kinetic.Util._FilterWrapDoubleBuffer(function(src,dst,opt){
var s = this.getFilterAmount()/100;
convolve(src,dst,{kernel:[
[-1*s, -0.5*s, 0],
[-0.5*s,1+0.5*s, 0.5*s],
[ 0, 0.5*s, 1*s]
]});
});
Kinetic.Filters.Edge = Kinetic.Util._FilterWrapDoubleBuffer(function(src,dst,opt){
var s = this.getFilterAmount()/100;
convolve(src,dst,{kernel:[
[ 0, -1*s, 0],
[-1*s,(1-s)+4*s,-1*s],
[ 0, -1*s, 0]
]});
});
Kinetic.Filters.SoftBlur = Kinetic.Util._FilterWrapDoubleBuffer(function(src,dst,opt){
var s = this.getFilterAmount()/100;
convolve(src,dst,{kernel:make_soft_blur_kernel(5,s)});
});
Kinetic.Filters.UnsharpMask = Kinetic.Util._FilterWrapDoubleBuffer(function(src,dst,opt){
var s = this.getFilterAmount()/100;
convolve(src,dst,{kernel:make_unsharp_kernel(5,s)});
});
})();

169
src/filters/Emboss.js Normal file
View File

@ -0,0 +1,169 @@
(function () {
/**
* Emboss Filter
* @function
* @memberof Kinetic.Filters
* @param {Object} imageData
* Pixastic Lib - Emboss filter - v0.1.0
* Copyright (c) 2008 Jacob Seidelin, jseidelin@nihilogic.dk, http://blog.nihilogic.dk/
* License: [http://www.pixastic.com/lib/license.txt]
*/
Kinetic.Filters.Emboss = function (imageData) {
// pixastic strength is between 0 and 10. I want it between 0 and 1
// pixastic greyLevel is between 0 and 255. I want it between 0 and 1. Also,
// a max value of greyLevel yields a white emboss, and the min value yields a black
// emboss. Therefore, I changed greyLevel to whiteLevel
var strength = this.embossStrength() * 10,
greyLevel = this.embossWhiteLevel() * 255,
direction = this.embossDirection(),
blend = this.embossBlend(),
dirY = 0,
dirX = 0,
data = imageData.data,
invertAlpha = false,
w = imageData.width,
h = imageData.height,
w4 = w*4,
y = h;
switch (direction) {
case 'top-left':
dirY = -1;
dirX = -1;
break;
case 'top':
dirY = -1;
dirX = 0;
break;
case 'top-right':
dirY = -1;
dirX = 1;
break;
case 'right':
dirY = 0;
dirX = 1;
break;
case 'bottom-right':
dirY = 1;
dirX = 1;
break;
case 'bottom':
dirY = 1;
dirX = 0;
break;
case 'bottom-left':
dirY = 1;
dirX = -1;
break;
case 'left':
dirY = 0;
dirX = -1;
break;
}
do {
var offsetY = (y-1)*w4;
var otherY = dirY;
if (y + otherY < 1) otherY = 0;
if (y + otherY > h) otherY = 0;
var offsetYOther = (y-1+otherY)*w*4;
var x = w;
do {
var offset = offsetY + (x-1)*4;
var otherX = dirX;
if (x + otherX < 1) otherX = 0;
if (x + otherX > w) otherX = 0;
var offsetOther = offsetYOther + (x-1+otherX)*4;
var dR = data[offset] - data[offsetOther];
var dG = data[offset+1] - data[offsetOther+1];
var dB = data[offset+2] - data[offsetOther+2];
var dif = dR;
var absDif = dif > 0 ? dif : -dif;
var absG = dG > 0 ? dG : -dG;
var absB = dB > 0 ? dB : -dB;
if (absG > absDif) {
dif = dG;
}
if (absB > absDif) {
dif = dB;
}
dif *= strength;
if (blend) {
var r = data[offset] + dif;
var g = data[offset+1] + dif;
var b = data[offset+2] + dif;
data[offset] = (r > 255) ? 255 : (r < 0 ? 0 : r);
data[offset+1] = (g > 255) ? 255 : (g < 0 ? 0 : g);
data[offset+2] = (b > 255) ? 255 : (b < 0 ? 0 : b);
} else {
var grey = greyLevel - dif;
if (grey < 0) {
grey = 0;
} else if (grey > 255) {
grey = 255;
}
data[offset] = data[offset+1] = data[offset+2] = grey;
}
} while (--x);
} while (--y);
};
Kinetic.Factory.addFilterGetterSetter(Kinetic.Node, 'embossStrength', 0.5);
/**
* get/set emboss strength
* @name embossStrength
* @method
* @memberof Kinetic.Node.prototype
* @param {Number} level between 0 and 1. Default is 0.5
* @returns {Number}
*/
Kinetic.Factory.addFilterGetterSetter(Kinetic.Node, 'embossWhiteLevel', 0.5);
/**
* get/set emboss white level
* @name embossWhiteLevel
* @method
* @memberof Kinetic.Node.prototype
* @param {Number} embossWhiteLevel between 0 and 1. Default is 0.5
* @returns {Number}
*/
Kinetic.Factory.addFilterGetterSetter(Kinetic.Node, 'embossDirection', 'top-left');
/**
* get/set emboss direction
* @name embossDirection
* @method
* @memberof Kinetic.Node.prototype
* @param {String} embossDirection can be top-left, top, top-right, right, bottom-right, bottom, bottom-left or left
* The default is top-left
* @returns {String}
*/
Kinetic.Factory.addFilterGetterSetter(Kinetic.Node, 'embossBlend', false);
/**
* get/set emboss blend
* @name embossBlend
* @method
* @memberof Kinetic.Node.prototype
* @param {Boolean} embossBlend
* @returns {Boolean}
*/
})();

View File

@ -87,7 +87,6 @@
<script src="unit/filters/Invert-test.js"></script>
<script src="unit/filters/Mask-test.js"></script>
<script src="unit/filters/ConvolvePack-test.js"></script>
<script src="unit/filters/Grayscale-test.js"></script>
<script src="unit/filters/Enhance-test.js"></script>
<!--<script src="unit/filters/Polar-test.js"></script>-->
@ -97,6 +96,7 @@
<script src="unit/filters/Posterize-test.js"></script>
<script src="unit/filters/Sepia-test.js"></script>
<script src="unit/filters/Emboss-test.js"></script>
<!--=============== functional tests ================-->

View File

@ -1,179 +0,0 @@
suite('ConvolvePack', function() {
// ======================================================
test('emboss', function(done) {
var stage = addStage();
var imageObj = new Image();
imageObj.onload = function() {
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true
});
layer.add(darth);
stage.add(layer);
darth.cache();
darth.filters([Kinetic.Filters.Emboss]);
darth.filterAmount(100);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 0.6,
filterAmount: 0,
easing: Kinetic.Easings.EaseInOut
});
darth.on('mouseover', function() {
tween.play();
});
darth.on('mouseout', function() {
tween.reverse();
});
done();
};
imageObj.src = 'assets/darth-vader.jpg';
//imageObj.src = 'assets/lion.png';
});
// ======================================================
test('edge detect', function(done) {
var stage = addStage();
var imageObj = new Image();
imageObj.onload = function() {
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true
});
layer.add(darth);
stage.add(layer);
darth.cache();
darth.filters([Kinetic.Filters.Edge]);
darth.setFilterAmount(100);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 0.6,
filterAmount: 0,
easing: Kinetic.Easings.EaseInOut
});
darth.on('mouseover', function() {
tween.play();
});
darth.on('mouseout', function() {
tween.reverse();
});
done();
};
//imageObj.src = 'assets/darth-vader.jpg';
imageObj.src = 'assets/lion.png';
});
// ======================================================
test('unsharp mask', function(done) {
var stage = addStage();
var imageObj = new Image();
imageObj.onload = function() {
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true
});
layer.add(darth);
stage.add(layer);
darth.cache();
darth.filters([Kinetic.Filters.UnsharpMask]);
darth.setFilterAmount(100);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 0.6,
filterAmount: 0,
easing: Kinetic.Easings.EaseInOut
});
darth.on('mouseover', function() {
tween.play();
});
darth.on('mouseout', function() {
tween.reverse();
});
done();
};
//imageObj.src = 'assets/darth-vader.jpg';
imageObj.src = 'assets/lion.png';
});
// ======================================================
test('soft blur', function(done) {
var stage = addStage();
var imageObj = new Image();
imageObj.onload = function() {
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true
});
layer.add(darth);
stage.add(layer);
darth.cache();
darth.filters([Kinetic.Filters.SoftBlur]);
darth.setFilterAmount(100);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 0.6,
filterAmount: 0,
easing: Kinetic.Easings.EaseInOut
});
darth.on('mouseover', function() {
tween.play();
});
darth.on('mouseout', function() {
tween.reverse();
});
done();
};
//imageObj.src = 'assets/darth-vader.jpg';
imageObj.src = 'assets/lion.png';
});
});

View File

@ -0,0 +1,96 @@
suite('Emboss', function() {
// ======================================================
test('basic emboss', function(done) {
var stage = addStage();
var imageObj = new Image();
imageObj.onload = function() {
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true
});
layer.add(darth);
stage.add(layer);
darth.cache();
darth.filters([Kinetic.Filters.Emboss]);
darth.embossStrength(0.5);
darth.embossWhiteLevel(0.8);
darth.embossDirection('top-right');
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 0.6,
embossStrength: 10,
easing: Kinetic.Easings.EaseInOut
});
darth.on('mouseover', function() {
tween.play();
});
darth.on('mouseout', function() {
tween.reverse();
});
done();
};
imageObj.src = 'assets/darth-vader.jpg';
//imageObj.src = 'assets/lion.png';
});
// ======================================================
test('blended emboss', function(done) {
var stage = addStage();
var imageObj = new Image();
imageObj.onload = function() {
var layer = new Kinetic.Layer();
darth = new Kinetic.Image({
x: 10,
y: 10,
image: imageObj,
draggable: true
});
layer.add(darth);
stage.add(layer);
darth.cache();
darth.filters([Kinetic.Filters.Emboss]);
darth.embossStrength(0.5);
darth.embossWhiteLevel(0.2);
darth.embossBlend(true);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 0.6,
embossStrength: 10,
easing: Kinetic.Easings.EaseInOut
});
darth.on('mouseover', function() {
tween.play();
});
darth.on('mouseout', function() {
tween.reverse();
});
done();
};
imageObj.src = 'assets/darth-vader.jpg';
//imageObj.src = 'assets/lion.png';
});
});