diff --git a/Gruntfile.js b/Gruntfile.js
index 25396196..5560cab2 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -16,6 +16,7 @@ module.exports = function(grunt) {
'src/filters/Mask.js',
'src/filters/RGB.js',
'src/filters/HSV.js',
+ 'src/filters/HSL.js',
'src/filters/Emboss.js',
'src/filters/Enhance.js',
'src/filters/Posterize.js',
diff --git a/src/filters/HSL.js b/src/filters/HSL.js
new file mode 100644
index 00000000..9d70057a
--- /dev/null
+++ b/src/filters/HSL.js
@@ -0,0 +1,118 @@
+(function () {
+
+ HSV = function (imageData) {
+ var data = imageData.data,
+ nPixels = data.length,
+ v = Math.pow(2,this.value()),
+ s = Math.pow(2,this.saturation()),
+ h = Math.abs((this.hue()) + 360) % 360,
+ i;
+
+ // Basis for the technique used:
+ // http://beesbuzz.biz/code/hsv_color_transforms.php
+ // V is the value multiplier (1 for none, 2 for double, 0.5 for half)
+ // S is the saturation multiplier (1 for none, 2 for double, 0.5 for half)
+ // H is the hue shift in degrees (0 to 360)
+ // vsu = V*S*cos(H*PI/180);
+ // vsw = V*S*sin(H*PI/180);
+ //[ .299V+.701vsu+.168vsw .587V-.587vsu+.330vsw .114V-.114vsu-.497vsw ] [R]
+ //[ .299V-.299vsu-.328vsw .587V+.413vsu+.035vsw .114V-.114vsu+.292vsw ]*[G]
+ //[ .299V-.300vsu+1.25vsw .587V-.588vsu-1.05vsw .114V+.886vsu-.203vsw ] [B]
+
+ // Precompute the values in the matrix:
+ var vsu = v*s*Math.cos(h*Math.PI/180),
+ vsw = v*s*Math.sin(h*Math.PI/180);
+ // (result spot)(source spot)
+ var rr = 0.299*v+0.701*vsu+0.167*vsw,
+ rg = 0.587*v-0.587*vsu+0.330*vsw,
+ rb = 0.114*v-0.114*vsu-0.497*vsw;
+ var gr = 0.299*v-0.299*vsu-0.328*vsw,
+ gg = 0.587*v+0.413*vsu+0.035*vsw,
+ gb = 0.114*v-0.114*vsu+0.293*vsw;
+ var br = 0.299*v-0.300*vsu+1.250*vsw,
+ bg = 0.587*v-0.586*vsu-1.050*vsw,
+ bb = 0.114*v+0.886*vsu-0.200*vsw;
+
+ var r,g,b,a;
+
+ for (i = 0; i < nPixels; i += 4) {
+ r = data[i+0];
+ g = data[i+1];
+ b = data[i+2];
+ a = data[i+3];
+
+ data[i+0] = rr*r + rg*g + rb*b;
+ data[i+1] = gr*r + gg*g + gb*b;
+ data[i+2] = br*r + bg*g + bb*b;
+ data[i+3] = a; // alpha
+ }
+
+ };
+
+ Kinetic.Factory.addGetterSetter(Kinetic.Node, 'hue', 0, null, Kinetic.Factory.afterSetFilter);
+ /**
+ * get/set hsv hue in degrees
+ * @name hue
+ * @method
+ * @memberof Kinetic.Node.prototype
+ * @param {Number} hue value between 0 and 359
+ * @returns {Number}
+ */
+
+ Kinetic.Factory.addGetterSetter(Kinetic.Node, 'saturation', 0, null, Kinetic.Factory.afterSetFilter);
+ /**
+ * get/set hsv saturation
+ * @name saturation
+ * @method
+ * @memberof Kinetic.Node.prototype
+ * @param {Number} saturation 0 is no change, -1.0 halves the saturation, 1.0 doubles, etc..
+ * @returns {Number}
+ */
+
+ Kinetic.Factory.addGetterSetter(Kinetic.Node, 'value', 0, null, Kinetic.Factory.afterSetFilter);
+ /**
+ * get/set hsv value
+ * @name value
+ * @method
+ * @memberof Kinetic.Node.prototype
+ * @param {Number} value 0 is no change, -1.0 halves the value, 1.0 doubles, etc..
+ * @returns {Number}
+ */
+
+ Kinetic.Factory.addGetterSetter(Kinetic.Node, 'luminance', 0, null, Kinetic.Factory.afterSetFilter);
+ /**
+ * get/set hsl luminance
+ * @name value
+ * @method
+ * @memberof Kinetic.Node.prototype
+ * @param {Number} value 0 is no change, -1.0 halves the value, 1.0 doubles, etc..
+ * @returns {Number}
+ */
+
+ /**
+ * HSL Filter. Adjusts the hue, saturation and luminance (or lightness)
+ * @function
+ * @memberof Kinetic.Filters
+ * @param {Object} imageData
+ * @author ippo615
+ */
+
+ Kinetic.Filters.HSL = function (imageData) {
+ // Hue stays the same but saturation, value and brightness will be
+ // adjusted to match common photo-editing software's extreme values
+ var oldSaturation = this.saturation(),
+ oldBrightness = this.brightness(),
+ oldValue = this.value();
+
+ this.saturation(oldSaturation);
+ this.brightness(0.5*this.luminance());
+ this.value(0.0);
+
+ HSV.call(this,imageData);
+ Kinetic.Filters.Brighten.call(this,imageData);
+
+ this.saturation(oldSaturation);
+ this.brightness(oldBrightness);
+ this.value(oldValue);
+ };
+})();
diff --git a/src/filters/HSV.js b/src/filters/HSV.js
index 8669d214..372eaf5c 100644
--- a/src/filters/HSV.js
+++ b/src/filters/HSV.js
@@ -11,8 +11,8 @@
Kinetic.Filters.HSV = function (imageData) {
var data = imageData.data,
nPixels = data.length,
- v = this.value(),
- s = this.saturation(),
+ v = Math.pow(2,this.value()),
+ s = Math.pow(2,this.saturation()),
h = Math.abs((this.hue()) + 360) % 360,
i;
@@ -67,60 +67,24 @@
* @returns {Number}
*/
- Kinetic.Factory.addGetterSetter(Kinetic.Node, 'saturation', 1, null, Kinetic.Factory.afterSetFilter);
+ Kinetic.Factory.addGetterSetter(Kinetic.Node, 'saturation', 0, null, Kinetic.Factory.afterSetFilter);
/**
* get/set hsv saturation
* @name saturation
* @method
* @memberof Kinetic.Node.prototype
- * @param {Number} saturation 1 is no change, 0.5 halves the saturation, 2.0 doubles, etc..
+ * @param {Number} saturation 0 is no change, -1.0 halves the saturation, 1.0 doubles, etc..
* @returns {Number}
*/
- Kinetic.Factory.addGetterSetter(Kinetic.Node, 'value', 1, null, Kinetic.Factory.afterSetFilter);
+ Kinetic.Factory.addGetterSetter(Kinetic.Node, 'value', 0, null, Kinetic.Factory.afterSetFilter);
/**
* get/set hsv value
* @name value
* @method
* @memberof Kinetic.Node.prototype
- * @param {Number} value 1 is no change, 0.5 halves the value, 2.0 doubles, etc..
+ * @param {Number} value 0 is no change, -1.0 halves the value, 1.0 doubles, etc..
* @returns {Number}
*/
- Kinetic.Factory.addGetterSetter(Kinetic.Node, 'luminance', 1, null, Kinetic.Factory.afterSetFilter);
- /**
- * get/set hsl luminance
- * @name value
- * @method
- * @memberof Kinetic.Node.prototype
- * @param {Number} value 1 is no change, 0.5 halves the value, 2.0 doubles, etc..
- * @returns {Number}
- */
-
- /**
- * HSL Filter. Adjusts the hue, saturation and luminance (or lightness)
- * @function
- * @memberof Kinetic.Filters
- * @param {Object} imageData
- * @author ippo615
- */
-
- Kinetic.Filters.HSL = function (imageData) {
- // Hue stays the same but saturation, value and brightness will be
- // adjusted to match common photo-editing software's extreme values
- var oldSaturation = this.saturation(),
- oldBrightness = this.brightness(),
- oldValue = this.value();
-
- this.saturation(oldSaturation*oldSaturation);
- this.brightness(0.5*(this.luminance()-1));
- this.value(1.0);
-
- Kinetic.Filters.HSV.call(this,imageData);
- Kinetic.Filters.Brighten.call(this,imageData);
-
- this.saturation(oldSaturation);
- this.brightness(oldBrightness);
- this.value(oldValue);
- };
})();
diff --git a/test/runner.html b/test/runner.html
index 645885c3..e429dfd5 100644
--- a/test/runner.html
+++ b/test/runner.html
@@ -84,6 +84,7 @@
+
diff --git a/test/unit/filters/HSL-test.js b/test/unit/filters/HSL-test.js
new file mode 100644
index 00000000..51a422b4
--- /dev/null
+++ b/test/unit/filters/HSL-test.js
@@ -0,0 +1,135 @@
+suite('HSL', function() {
+
+
+ // ======================================================
+ test('hue shift tween transparancy', 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.HSL]);
+ darth.hue(360);
+ layer.draw();
+
+ var tween = new Kinetic.Tween({
+ node: darth,
+ duration: 1.0,
+ hue: 0,
+ easing: Kinetic.Easings.EaseInOut
+ });
+
+ darth.on('mouseover', function() {
+ tween.play();
+ });
+
+ darth.on('mouseout', function() {
+ tween.reverse();
+ });
+
+ done();
+ };
+ imageObj.src = 'assets/lion.png';
+
+ });
+
+ // ======================================================
+ test('HSL luminance tween transparancy', 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.HSL]);
+ darth.luminance(1.0);
+ layer.draw();
+
+ var tween = new Kinetic.Tween({
+ node: darth,
+ duration: 1.0,
+ luminance: -1.0,
+ easing: Kinetic.Easings.EaseInOut
+ });
+
+ darth.on('mouseover', function() {
+ tween.play();
+ });
+
+ darth.on('mouseout', function() {
+ tween.reverse();
+ });
+
+ done();
+ };
+ imageObj.src = 'assets/lion.png';
+
+ });
+
+ // ======================================================
+ test('HSL saturation tween transparancy', 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.HSL]);
+ darth.saturation(1.0);
+ layer.draw();
+
+ var tween = new Kinetic.Tween({
+ node: darth,
+ duration: 1.0,
+ saturation: -1.0,
+ easing: Kinetic.Easings.EaseInOut
+ });
+
+ darth.on('mouseover', function() {
+ tween.play();
+ });
+
+ darth.on('mouseout', function() {
+ tween.reverse();
+ });
+
+ done();
+ };
+ imageObj.src = 'assets/lion.png';
+
+ });
+});
diff --git a/test/unit/filters/HSV-test.js b/test/unit/filters/HSV-test.js
index 2e488804..33fa8355 100644
--- a/test/unit/filters/HSV-test.js
+++ b/test/unit/filters/HSV-test.js
@@ -66,13 +66,13 @@ suite('HSV', function() {
darth.cache();
darth.filters([Kinetic.Filters.HSV]);
- darth.saturation(2);
+ darth.saturation(1.0);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 1.0,
- saturation: 0,
+ saturation: -1.0,
easing: Kinetic.Easings.EaseInOut
});
@@ -110,13 +110,13 @@ suite('HSV', function() {
darth.cache();
darth.filters([Kinetic.Filters.HSV]);
- darth.saturation(2.0);
+ darth.saturation(1.0);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 1.0,
- saturation: 0.001,
+ saturation: -1,
easing: Kinetic.Easings.EaseInOut
});
@@ -154,13 +154,13 @@ suite('HSV', function() {
darth.cache();
darth.filters([Kinetic.Filters.HSV]);
- darth.value(2.0);
+ darth.value(1.0);
layer.draw();
var tween = new Kinetic.Tween({
node: darth,
duration: 1.0,
- value: 0.001,
+ value: -1.0,
easing: Kinetic.Easings.EaseInOut
});
@@ -178,91 +178,4 @@ suite('HSV', function() {
});
- // ======================================================
- test('HSL luminance tween transparancy', 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.HSL]);
- darth.luminance(2.0);
- layer.draw();
-
- var tween = new Kinetic.Tween({
- node: darth,
- duration: 1.0,
- luminance: 0.001,
- easing: Kinetic.Easings.EaseInOut
- });
-
- darth.on('mouseover', function() {
- tween.play();
- });
-
- darth.on('mouseout', function() {
- tween.reverse();
- });
-
- done();
- };
- imageObj.src = 'assets/lion.png';
-
- });
-
- // ======================================================
- test('HSL saturation tween transparancy', 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.HSL]);
- darth.saturation(2.0);
- layer.draw();
-
- var tween = new Kinetic.Tween({
- node: darth,
- duration: 1.0,
- saturation: 0.001,
- easing: Kinetic.Easings.EaseInOut
- });
-
- darth.on('mouseover', function() {
- tween.play();
- });
-
- darth.on('mouseout', function() {
- tween.reverse();
- });
-
- done();
- };
- imageObj.src = 'assets/lion.png';
-
- });
});