Figured I may as well take care of that other caveat from the original post. I need to publicly state that I simply translated this code from Grant Skinner’s ActionScript 2 ColorMatrix class. It is with Grant’s kind permission that I can post this for anyone else to use.
This took a while to complete, and I apologize for being MIA recently. The work of this script didn’t take very long at all, but gathering my wits to blog about it just kept taking a backseat. We’ve been rather busy, and hopefully we’ll have some cool new things to share soon.
At any rate, a complete code listing is available here, and below:
function ColorMatrix(m) {
this._matrix = m?m.concat():ColorMatrix.IDENTITY_MATRIX.concat();
/**
* Copies the supplied matrix to the internal matrix.
* @param m Array
**/
this.copyMatrix = function(m) {
this._matrix = m.concat();
}
/**
* Ensures that the supplied matrix Array is of the correct length. It slices off extraneous elements, or
* fills in missing elements with IDENTITY elements.
* @param m Array
* @return Fixed Array
**/
this.fixMatrix = function(m) {
if (m.length < ColorMatrix.LENGTH) {
m = m.slice(0, m.length).concat(ColorMatrix.IDENTITY_MATRIX.slice(m.length,ColorMatrix.LENGTH));
} else if (m.length > ColorMatrix.LENGTH) {
m = m.slice(0, ColorMatrix.LENGTH);
}
return m;
}
/**
* Makes sure the incoming value in between a negative and positive limit value.
* @param val The value to clean
* @param limit The absolute value of the range. If the limit is 100, then the value is ensured to be between -100 and 100.
* @return Number; the cleaned value.
**/
this.cleanValue = function(val, limit) {
return Math.min(limit, Math.max(-limit, val));
}
/**
* Core function for translating color adjustments to matrix arrays. The internal matrix is affected.
* @param m Array
**/
this.multiplyMatrix = function(m) {
var col = [];
for (var i=0; i<5; i++) {
for (j=0; j<5; j++) {
col[j] = this._matrix[j+i*5];
}
for (var j=0; j<5; j++) {
var val=0;
for (var k=0; k<5; k++) {
val += m[j+k*5]*col[k];
}
this._matrix[j+i*5] = val;
}
}
}
/**
* Adjusts the internal matrix array to reflect a brightness adjustment.
* @param val The brightness, from -100 to 100.
**/
this.adjustBrightness = function(val) {
val = this.cleanValue(val,100);
if (val == 0 || isNaN(val)) { return; }
this.multiplyMatrix([
1,0,0,0,val,
0,1,0,0,val,
0,0,1,0,val,
0,0,0,1,0,
0,0,0,0,1
]);
}
/**
* @param val The Contrast, from -100 to 100
**/
this.adjustContrast = function(val) {
val = this.cleanValue(val,100);
if (val == 0 || isNaN(val)) { return; }
var x;
if (val < 0) {
x = 127 + (val / 100) * 127
} else {
x = val % 1;
if (x == 0) {
x = ColorMatrix.DELTA_INDEX[val];
} else {
//x = ColorMatrix.DELTA_INDEX[(val<<0)]; // this is how the IDE does it.
x = ColorMatrix.DELTA_INDEX[(val<<0)]*(1-x)+ColorMatrix.DELTA_INDEX[(val<<0)+1]*x; // use linear interpolation for more granularity.
}
x = x*127+127;
}
this.multiplyMatrix([
x/127,0,0,0,0.5*(127-x),
0,x/127,0,0,0.5*(127-x),
0,0,x/127,0,0.5*(127-x),
0,0,0,1,0,
0,0,0,0,1
]);
}
/**
* @param val The Saturation, from -100 to 100
**/
this.adjustSaturation = function(val) {
val = this.cleanValue(val,100);
if (val == 0 || isNaN(val)) { return; }
var x = 1+((val > 0) ? 3*val/100 : val/100);
var lumR = 0.3086;
var lumG = 0.6094;
var lumB = 0.0820;
this.multiplyMatrix([
lumR*(1-x)+x,lumG*(1-x),lumB*(1-x),0,0,
lumR*(1-x),lumG*(1-x)+x,lumB*(1-x),0,0,
lumR*(1-x),lumG*(1-x),lumB*(1-x)+x,0,0,
0,0,0,1,0,
0,0,0,0,1
]);
}
/**
* @param val The Hue, from -180 to 180
**/
this.adjustHue = function(val) {
val = this.cleanValue(val,180)/180*Math.PI;
if (val == 0 || isNaN(val)) { return; }
var cosVal = Math.cos(val);
var sinVal = Math.sin(val);
var lumR = 0.213;
var lumG = 0.715;
var lumB = 0.072;
this.multiplyMatrix([
lumR+cosVal*(1-lumR)+sinVal*(-lumR),lumG+cosVal*(-lumG)+sinVal*(-lumG),lumB+cosVal*(-lumB)+sinVal*(1-lumB),0,0,
lumR+cosVal*(-lumR)+sinVal*(0.143),lumG+cosVal*(1-lumG)+sinVal*(0.140),lumB+cosVal*(-lumB)+sinVal*(-0.283),0,0,
lumR+cosVal*(-lumR)+sinVal*(-(1-lumR)),lumG+cosVal*(-lumG)+sinVal*(lumG),lumB+cosVal*(1-lumB)+sinVal*(lumB),0,0,
0,0,0,1,0,
0,0,0,0,1
]);
}
/**
* Adjust all four properties at once
* @param brightness (-100 - 100)
* @param contrast (-100 - 100)
* @param saturation (-100 - 100)
* @param hue (-180 - 180)
**/
this.adjustColor = function(brightness, contrast, saturation, hue) {
this.adjustHue(hue);
this.adjustContrast(contrast);
this.adjustBrightness(brightness);
this.adjustSaturation(saturation);
}
this.__defineGetter__("matrix", function() {return this._matrix.concat(); });
this.toString = function() {
//return "ColorMatrix: " + this._matrix.toString();
var out = "ColorMatrix:\n";
var v;
var iLen = this._matrix.length;
var l = 4;
for (var i = 0; i < iLen; i++) {
v = this._matrix[i].toString();
if (v.length > l) {
v = v.substr(0, l);
} else {
while (v.length < l) {
v += " ";
}
}
out += v;
if (i % 5 == 4) {
out += "\n";
} else {
out += " ";
}
}
return out;
}
}
ColorMatrix._DELTA_INDEX = [
0, 0.01, 0.02, 0.04, 0.05, 0.06, 0.07, 0.08, 0.1, 0.11,
0.12, 0.14, 0.15, 0.16, 0.17, 0.18, 0.20, 0.21, 0.22, 0.24,
0.25, 0.27, 0.28, 0.30, 0.32, 0.34, 0.36, 0.38, 0.40, 0.42,
0.44, 0.46, 0.48, 0.5, 0.53, 0.56, 0.59, 0.62, 0.65, 0.68,
0.71, 0.74, 0.77, 0.80, 0.83, 0.86, 0.89, 0.92, 0.95, 0.98,
1.0, 1.06, 1.12, 1.18, 1.24, 1.30, 1.36, 1.42, 1.48, 1.54,
1.60, 1.66, 1.72, 1.78, 1.84, 1.90, 1.96, 2.0, 2.12, 2.25,
2.37, 2.50, 2.62, 2.75, 2.87, 3.0, 3.2, 3.4, 3.6, 3.8,
4.0, 4.3, 4.7, 4.9, 5.0, 5.5, 6.0, 6.5, 6.8, 7.0,
7.3, 7.5, 7.8, 8.0, 8.4, 8.7, 9.0, 9.4, 9.6, 9.8,
10.0
];
ColorMatrix._IDENTITY_MATRIX = [
1,0,0,0,0,
0,1,0,0,0,
0,0,1,0,0,
0,0,0,1,0,
0,0,0,0,1
]
ColorMatrix._LENGTH = ColorMatrix._IDENTITY_MATRIX.length;
ColorMatrix.__defineGetter__("DELTA_INDEX", function() { return ColorMatrix._DELTA_INDEX; } );
ColorMatrix.__defineGetter__("IDENTITY_MATRIX", function() { return ColorMatrix._IDENTITY_MATRIX; } );
ColorMatrix.__defineGetter__("LENGTH", function() { return ColorMatrix._LENGTH; } );
var sel = fl.getDocumentDOM().selection;
fl.outputPanel.clear();
var iLen = sel.length;
var qualities = {
low:1,
medium:2,
high:3
}
for (var i = 0; i < iLen; i++) {
var s = sel[i];
if (s.instanceType != "symbol") continue;
// fl.trace("FILTERS FOR " + (s.name == "" ? "UNNAMED INSTANCE" : s.name) + " -------------------------------------");
var filters = s.filters;
var jLen = filters.length;
for (var j = 0; j < jLen; j++) {
var f = filters[j];
// for (var p in f) {
// fl.trace(p + " :: " + f[p]);
// }
var en = f.enabled ? "" : "//";
var q = qualities[f.quality];
if (f.color) {
var colorInfo = getColorAndAlpha(f.color);
}
if (f.highlightColor) {
var highlightColorInfo = getColorAndAlpha(f.highlightColor);
}
if (f.shadowColor) {
var shadowColorInfo = getColorAndAlpha(f.shadowColor);
}
if (f.colorArray) {
var colorArray = [];
var alphaArray = [];
var iLen = f.colorArray.length;
for (var i = 0; i < iLen; i++) {
var info = getColorAndAlpha(f.colorArray[i]);
colorArray.push(info.color);
alphaArray.push (info.alpha);
}
}
var s = f.strength / 100;
switch (f.name) {
case "glowFilter":
fl.trace(en + "new GlowFilter("+colorInfo.color+", "+colorInfo.alpha+", "+f.blurX+", "+f.blurY+", "+s+", "+q+", "+f.inner+", "+f.knockout+");");
break;
case "dropShadowFilter":
fl.trace(en + "new DropShadowFilter("+f.distance+", "+f.angle+", "+colorInfo.color+", "+colorInfo.alpha+", "+f.blurX+", "+f.blurY+", "+s+", "+q+", "+f.inner+", "+f.knockout+", "+f.hideObject+");");
break;
case "blurFilter":
fl.trace(en + "new BlurFilter("+f.blurX+", "+f.blurY+", "+q+");");
break;
case "bevelFilter":
fl.trace(en + "new BevelFilter("+f.distance+", "+f.angle+", "+highlightColorInfo.color+", "+highlightColorInfo.alpha+", "+shadowColorInfo.color+", "+shadowColorInfo.alpha+", "+f.blurX+", "+f.blurY+", "+f.strength+", "+q+", \""+f.type+"\", "+f.knockout+");");
break;
case "gradientBevelFilter":
fl.trace(en + "new GradientBevelFilter("+f.distance+", "+f.angle+", ["+colorArray+"], ["+alphaArray+"], ["+f.posArray+"], "+f.blurX+", "+f.blurY+", "+f.strength+", "+q+", \""+f.type+"\", "+f.knockout+");");
break;
case "gradientGlowFilter":
fl.trace(en + "new GradientGlowFilter("+f.distance+", "+f.angle+", ["+colorArray+"], ["+alphaArray+"], ["+f.posArray+"], "+f.blurX+", "+f.blurY+", "+f.strength+", "+q+", \""+f.type+"\", "+f.knockout+");");
break;
case "adjustColorFilter":
var m = new ColorMatrix();
m.adjustColor(f.brightness, f.contrast, f.saturation, f.hue);
fl.trace(en + "new ColorMatrixFilter(["+m.matrix+"]);");
break;
}
}
fl.trace("\n");
}
/**
* Returns an Object with two properties, color and alpha, as strings, based on the parsing of the color string coming in. The color string
* will be something like "#FF9933" or "#FF993366". If it's a 32-bit color, the alpha channel is contained in the last two bytes
* (66 in this case).
**/
function getColorAndAlpha(color) {
var colorInfo = {};
if (color.length == 9) {
colorInfo.alpha = Math.round(parseInt(color.substr(7, 2), 16) / 0xFF * 100) / 100;
colorInfo.color = color.substr(0, 7).replace(/^#/, "0x")
} else if (color.length == 7) {
colorInfo.alpha = 1;
colorInfo.color = color.replace(/^#/, "0x")
} else {
fl.trace("Problem parsing color.")
}
return colorInfo;
}
Thank you, Grant, for doing all of the hard work on this one!




