I\'ve been trying to use ImageMagick to replicate Photoshops Colour Blend Mode. I found the following formulas in an online guide but I don\'t know what they mean. Do I just
A while ago I reversed engineered Photoshop blending modes.
Have a look here:
http://www.kineticsystem.org/?q=node/13
And here below the code I use to convert between HSY (Hue, Saturation, Luminosity) to and from RGB (Red, Green, Blue). Photoshop use something called Hexacones to calculate the saturation.
Giovanni
/**
* This is the formula used by Photoshop to convert a color from
* RGB (Red, Green, Blue) to HSY (Hue, Saturation, Luminosity).
* The hue is calculated using the exacone approximation of the saturation
* cone.
* @param rgb The input color RGB normalized components.
* @param hsy The output color HSY normalized components.
*/
public static void rgbToHsy(double rgb[], double hsy[]) {
double r = Math.min(Math.max(rgb[0], 0d), 1d);
double g = Math.min(Math.max(rgb[1], 0d), 1d);
double b = Math.min(Math.max(rgb[2], 0d), 1d);
double h;
double s;
double y;
// For saturation equals to 0 any value of hue are valid.
// In this case we choose 0 as a default value.
if (r == g && g == b) { // Limit case.
s = 0d;
h = 0d;
} else if ((r >= g) && (g >= b)) { // Sector 0: 0° - 60°
s = r - b;
h = 60d * (g - b) / s;
} else if ((g > r) && (r >= b)) { // Sector 1: 60° - 120°
s = g - b;
h = 60d * (g - r) / s + 60d;
} else if ((g >= b) && (b > r)) { // Sector 2: 120° - 180°
s = g - r;
h = 60d * (b - r) / s + 120d;
} else if ((b > g) && (g > r)) { // Sector 3: 180° - 240°
s = b - r;
h = 60d * (b - g) / s + 180d;
} else if ((b > r) && (r >= g)) { // Sector 4: 240° - 300°
s = b - g;
h = 60d * (r - g) / s + 240d;
} else { // Sector 5: 300° - 360°
s = r - g;
h = 60d * (r - b) / s + 300d;
}
y = R * r + G * g + B * b;
// Approximations erros can cause values to exceed bounds.
hsy[0] = h % 360;
hsy[1] = Math.min(Math.max(s, 0d), 1d);
hsy[2] = Math.min(Math.max(y, 0d), 1d);
}
/**
* This is the formula used by Photoshop to convert a color from
* HSY (Hue, Saturation, Luminosity) to RGB (Red, Green, Blue).
* The hue is calculated using the exacone approximation of the saturation
* cone.
* @param hsy The input color HSY normalized components.
* @param rgb The output color RGB normalized components.
*/
public static void hsyToRgb(double hsy[], double rgb[]) {
double h = hsy[0] % 360;
double s = Math.min(Math.max(hsy[1], 0d), 1d);
double y = Math.min(Math.max(hsy[2], 0d), 1d);
double r;
double g;
double b;
double k; // Intermediate variable.
if (h >= 0d && h < 60d) { // Sector 0: 0° - 60°
k = s * h / 60d;
b = y - R * s - G * k;
r = b + s;
g = b + k;
} else if (h >= 60d && h < 120d) { // Sector 1: 60° - 120°
k = s * (h - 60d) / 60d;
g = y + B * s + R * k;
b = g - s;
r = g - k;
} else if (h >= 120d && h < 180d) { // Sector 2: 120° - 180°
k = s * (h - 120d) / 60d;
r = y - G * s - B * k;
g = r + s;
b = r + k;
} else if (h >= 180d && h < 240d) { // Sector 3: 180° - 240°
k = s * (h - 180d) / 60d;
b = y + R * s + G * k;
r = b - s;
g = b - k;
} else if (h >= 240d && h < 300d) { // Sector 4: 240° - 300°
k = s * (h - 240d) / 60d;
g = y - B * s - R * k;
b = g + s;
r = g + k;
} else { // Sector 5: 300° - 360°
k = s * (h - 300d) / 60d;
r = y + G * s + B * k;
g = r - s;
b = r - k;
}
// Approximations erros can cause values to exceed bounds.
rgb[0] = Math.min(Math.max(r, 0d), 1d);
rgb[1] = Math.min(Math.max(g, 0d), 1d);
rgb[2] = Math.min(Math.max(b, 0d), 1d);
}