ComfyUI Node
HSV ADJUST (JOV_GL)
Hue, Saturation and Value adjustment control. Maintains alpha/mask.
HSV ADJUST (JOV_GL)
- image
- HSV
- RGBA
- RGB
- MASK
◄FRAGMENT// name: HSV ADJUST
// desc: Hue, Saturation and Value adjustment control. Maintains alpha/mask.
// category: COLOR
#ifndef LIB_CONVERT
#define LIB_CONVERT
//------------------------------------------------------------------------------
// COLOR
//------------------------------------------------------------------------------
#ifndef LIB_CONST
#define LIB_CONST
//------------------------------------------------------------------------------
// CONSTANT
//------------------------------------------------------------------------------
#define M_EPSILON 1.0e-10 // zero value for float comparisons
#define M_DEG2RAD 0.017453292519943 // Degree to radian conversion factor
#define M_RAD2DEG 57.29577951308232 // Radian to degree conversion factor
#define M_TAU 6.283185307179586 // TAU (2 * π)
#define M_TAU_INV 0.159154943091895 // TAU Inverse (1 / TAU)
#define M_PI 3.141592653589793 // π
#define M_PI_INV 0.318309886183790 // π Inverse (1 / π)
#define M_PI_2 1.570796326794896 // π divided by 2 (π / 2)
#define M_PI_4 0.785398163397448 // π divided by 4 (π / 4)
#define M_3PI_4 2.356194490192345 // 3 * π divided by 4 (3π / 4)
#define M_PHI 1.618033988749895 // Golden ratio (φ)
#define M_PHI_INV 0.618033988749895 // Inverse of golden ratio (1 / φ)
#define M_PHI_SQ 2.618033988749895 // Square of the golden ratio (φ^2)
#define M_PHI_SQRT5 0.723606797749979 // φ / √5 (useful for fibonacci spherical distribution)
#define M_GOLD_ANG 2.399963229728653 // Golden angle in radians
#define M_E 2.718281828459045 // Euler's number (base of natural logarithm)
#define M_LOG2E 1.442695040888963 // Log base 2 of e
#define M_LOG10E 0.434294481903252 // Log base 10 of e
#define M_LN2 0.693147180559945 // Natural log of 2
#define M_LN10 2.302585092994046 // Natural log of 10
#define M_SQRT2 1.414213562373095 // Square root of 2
#define M_SQRT3 1.732050807568877 // Square root of 3
#define M_SQRT2_INV 0.707106781186547 // 1 divided by square root of 2 (1 / sqrt(2))
#define M_SQRT3_INV 0.577350269189626 // 1 divided by square root of 3 (1 / sqrt(3))
#define M_SQRT5 2.236067977499790 // Square root of 5
//------------------------------------------------------------------------------
// GENERAL
//------------------------------------------------------------------------------
// useful for triangle interpolation
vec3 barycentricCoords(vec2 p, vec2 a, vec2 b, vec2 c) {
vec2 v0 = b - a;
vec2 v1 = c - a;
vec2 v2 = p - a;
float d00 = dot(v0, v0);
float d01 = dot(v0, v1);
float d11 = dot(v1, v1);
float d20 = dot(v2, v0);
float d21 = dot(v2, v1);
float denom = d00 * d11 - d01 * d01;
vec3 result;
result.y = (d11 * d20 - d01 * d21) / denom;
result.z = (d00 * d21 - d01 * d20) / denom;
result.x = 1.0 - result.y - result.z;
return result;
}
#endif
#define M_SRGB_ALPHA 0.055
#define M_SRGB_THRESH 0.04045
// LAB constants
#define M_LAB_E 0.008856 // LAB epsilon
#define M_LAB_K 903.3 // LAB kappa
#define M_LAB_16_116 0.137931 // 16/116
// Additional illuminants
#define M_D50 vec3(96.422, 100.0, 82.521) // D50 reference white
#define M_D65 vec3(95.047, 100.0, 108.883) // D65 reference white
#define M_D75 vec3(94.972, 100.0, 122.638) // D75 reference white
// =============================================================================
// PROTOTYPES
// =============================================================================
vec3 convert_rgb2hsv(vec3 rgb);
vec3 convert_rgb2lab(vec3 rgb);
vec3 convert_rgb2xyz(vec3 rgb);
vec3 convert_hsv2rgb(vec3 hsv);
vec3 convert_hsv2lab(vec3 hsv);
vec3 convert_hsv2xyz(vec3 hsv);
vec3 convert_lab2rgb(vec3 lab);
vec3 convert_lab2hsv(vec3 lab);
vec3 convert_lab2xyz(vec3 lab);
vec3 convert_xyz2rgb(vec3 xyz);
vec3 convert_xyz2hsv(vec3 xyz);
vec3 convert_xyz2lab(vec3 xyz);
vec3 convert_rgb2oklab(vec3 rgb);
vec3 convert_oklab2rgb(vec3 lab);
//------------------------------------------------------------------------------
// RGB
//------------------------------------------------------------------------------
vec3 convert_rgb2hsv(vec3 rgb) {
vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0);
vec4 p = mix(vec4(rgb.bg, K.wz), vec4(rgb.gb, K.xy), step(rgb.b, rgb.g));
vec4 q = mix(vec4(p.xyw, rgb.r), vec4(rgb.r, p.yzx), step(p.x, rgb.r));
float d = q.x - min(q.w, q.y);
return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + M_EPSILON)), d / (q.x + M_EPSILON), q.x);
}
vec3 convert_rgb2lab(vec3 rgb) {
vec3 xyz = convert_rgb2xyz(rgb);
return convert_xyz2lab(xyz);
}
vec3 convert_rgb2xyz(vec3 rgb) {
vec3 tmp;
tmp.x = (rgb.r > 0.04045) ? pow((rgb.r + 0.055) / 1.055, 2.4) : rgb.r / 12.92;
tmp.y = (rgb.g > 0.04045) ? pow((rgb.g + 0.055) / 1.055, 2.4) : rgb.g / 12.92;
tmp.z = (rgb.b > 0.04045) ? pow((rgb.b + 0.055) / 1.055, 2.4) : rgb.b / 12.92;
return 100.0 * tmp * mat3(
0.4124, 0.3576, 0.1805,
0.2126, 0.7152, 0.0722,
0.0193, 0.1192, 0.9505
);
}
//------------------------------------------------------------------------------
// HSV
//------------------------------------------------------------------------------
vec3 convert_hsv2rgb(vec3 hsv) {
hsv = vec3(hsv.x, clamp(hsv.yz, 0.0, 1.0));
vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0);
vec3 p = abs(fract(hsv.xxx + K.xyz) * 6.0 - K.www);
return hsv.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), hsv.y);
}
vec3 convert_hsv2lab(vec3 hsv) {
float H = hsv.x * 360.0;
float S = hsv.y;
float V = hsv.z;
// Convert to LAB
float L = V * 100.0;
float C = S * L;
float h = H * M_PI / 180.0;
float a = C * cos(h);
float b = C * sin(h);
// Normalize LAB
return vec3(L / 100.0, (a + 128.0) / 255.0, (b + 128.0) / 255.0);
}
vec3 convert_hsv2xyz(vec3 hsv) {
vec3 rgb = convert_hsv2rgb(hsv);
return convert_rgb2xyz(rgb);
}
//------------------------------------------------------------------------------
// LAB
//------------------------------------------------------------------------------
vec3 convert_lab2rgb(vec3 lab) {
vec3 xyz = convert_lab2xyz(lab);
return convert_xyz2rgb(xyz);
}
vec3 convert_lab2hsv(vec3 lab) {
vec3 rgb = convert_lab2rgb(lab);
return convert_rgb2hsv(rgb);
}
vec3 convert_lab2xyz(vec3 lab) {
float fy = (lab.x + 16.0) / 116.0;
float fx = lab.y / 500.0 + fy;
float fz = fy - lab.z / 200.0;
vec3 f = vec3(fx, fy, fz);
vec3 thresh = step(vec3(0.206897), f);
vec3 xyz = mix(
(f - vec3(16.0/116.0)) / 7.787,
f * f * f,
thresh
);
return xyz * M_D65;
}
//------------------------------------------------------------------------------
// XYZ
//------------------------------------------------------------------------------
vec3 convert_xyz2rgb(vec3 xyz) {
vec3 v = xyz / M_D65;
vec3 thresh = step(0.0031308, v);
return mix(
12.92 * v,
1.055 * pow(v, vec3(1.0/2.4)) - 0.055,
thresh
);
}
vec3 convert_xyz2hsv(vec3 xyz) {
vec3 rgb = convert_xyz2rgb(xyz);
return convert_rgb2hsv(rgb);
}
vec3 convert_xyz2lab(vec3 xyz) {
vec3 n = xyz / M_D65;
vec3 thresh = step(vec3(0.008856), n);
vec3 v = mix(
7.787 * n + vec3(16.0/116.0),
pow(n, vec3(1.0/3.0)),
thresh
);
return vec3(
116.0 * v.y - 16.0,
500.0 * (v.x - v.y),
200.0 * (v.y - v.z)
);
}
//------------------------------------------------------------------------------
// OKLAB
//------------------------------------------------------------------------------
// RGB to Oklab (perceptually uniform color space)
vec3 convert_rgb2oklab(vec3 rgb) {
vec3 lms = rgb * mat3(
0.4122214708, 0.5363325363, 0.0514459929,
0.2119034982, 0.6806995451, 0.1073969566,
0.0883024619, 0.2817188376, 0.6299787005
);
lms = pow(lms, vec3(1.0/3.0));
return lms * mat3(
0.2104542553, 0.7936177850, -0.0040720468,
1.9779984951, -2.4285922050, 0.4505937099,
0.0259040371, 0.7827717662, -0.8086757660
);
}
// Oklab to RGB
vec3 convert_oklab2rgb(vec3 lab) {
vec3 lms = lab * mat3(
1.0000000000, 0.3963377774, 0.2158037573,
1.0000000000, -0.1055613458, -0.0638541728,
1.0000000000, -0.0894841775, -1.2914855480
);
lms = lms * lms * lms;
return lms * mat3(
4.0767416621, -3.3077115913, 0.2309699292,
-1.2684380046, 2.6097574011, -0.3413193965,
-0.0041960863, -0.7034186147, 1.7076147010
);
}
#endif
uniform sampler2D image; // | RGB(A) image
uniform vec3 HSV; // 0.,1.,1.;-1;2;0.01 | Adjust the Hue, Saturation or Value
void mainImage(out vec4 fragColor, vec2 fragCoord) {
vec2 uv = fragCoord.xy / iResolution.xy;
vec4 color = texture(image, uv);
vec3 hsv = convert_rgb2hsv(color.rgb);
hsv.x = mod(hsv.x + HSV.x, 1.0);
hsv.y = clamp(hsv.y * HSV.y, 0.0, 1.0);
hsv.z = clamp(hsv.z * HSV.z, 0.0, 1.0);
fragColor = vec4(convert_hsv2rgb(hsv), color.a);
}►
CategoryJOV_GL 🌈/COLOR
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| imageopt | IMAGE | RGB(A) image | |
| HSVopt | VEC3 | 0,1,1 | Adjust the Hue, Saturation or Value |
| FRAGMENTopt | STRING | // name: HSV ADJUST // desc: Hue, Saturation and Value adjustment control. Maintains alpha/mask. // category: COLOR #ifndef LIB_CONVERT #define LIB_CONVERT //------------------------------------------------------------------------------ // COLOR //------------------------------------------------------------------------------ #ifndef LIB_CONST #define LIB_CONST //------------------------------------------------------------------------------ // CONSTANT //------------------------------------------------------------------------------ #define M_EPSILON 1.0e-10 // zero value for float comparisons #define M_DEG2RAD 0.017453292519943 // Degree to radian conversion factor #define M_RAD2DEG 57.29577951308232 // Radian to degree conversion factor #define M_TAU 6.283185307179586 // TAU (2 * π) #define M_TAU_INV 0.159154943091895 // TAU Inverse (1 / TAU) #define M_PI 3.141592653589793 // π #define M_PI_INV 0.318309886183790 // π Inverse (1 / π) #define M_PI_2 1.570796326794896 // π divided by 2 (π / 2) #define M_PI_4 0.785398163397448 // π divided by 4 (π / 4) #define M_3PI_4 2.356194490192345 // 3 * π divided by 4 (3π / 4) #define M_PHI 1.618033988749895 // Golden ratio (φ) #define M_PHI_INV 0.618033988749895 // Inverse of golden ratio (1 / φ) #define M_PHI_SQ 2.618033988749895 // Square of the golden ratio (φ^2) #define M_PHI_SQRT5 0.723606797749979 // φ / √5 (useful for fibonacci spherical distribution) #define M_GOLD_ANG 2.399963229728653 // Golden angle in radians #define M_E 2.718281828459045 // Euler's number (base of natural logarithm) #define M_LOG2E 1.442695040888963 // Log base 2 of e #define M_LOG10E 0.434294481903252 // Log base 10 of e #define M_LN2 0.693147180559945 // Natural log of 2 #define M_LN10 2.302585092994046 // Natural log of 10 #define M_SQRT2 1.414213562373095 // Square root of 2 #define M_SQRT3 1.732050807568877 // Square root of 3 #define M_SQRT2_INV 0.707106781186547 // 1 divided by square root of 2 (1 / sqrt(2)) #define M_SQRT3_INV 0.577350269189626 // 1 divided by square root of 3 (1 / sqrt(3)) #define M_SQRT5 2.236067977499790 // Square root of 5 //------------------------------------------------------------------------------ // GENERAL //------------------------------------------------------------------------------ // useful for triangle interpolation vec3 barycentricCoords(vec2 p, vec2 a, vec2 b, vec2 c) { vec2 v0 = b - a; vec2 v1 = c - a; vec2 v2 = p - a; float d00 = dot(v0, v0); float d01 = dot(v0, v1); float d11 = dot(v1, v1); float d20 = dot(v2, v0); float d21 = dot(v2, v1); float denom = d00 * d11 - d01 * d01; vec3 result; result.y = (d11 * d20 - d01 * d21) / denom; result.z = (d00 * d21 - d01 * d20) / denom; result.x = 1.0 - result.y - result.z; return result; } #endif #define M_SRGB_ALPHA 0.055 #define M_SRGB_THRESH 0.04045 // LAB constants #define M_LAB_E 0.008856 // LAB epsilon #define M_LAB_K 903.3 // LAB kappa #define M_LAB_16_116 0.137931 // 16/116 // Additional illuminants #define M_D50 vec3(96.422, 100.0, 82.521) // D50 reference white #define M_D65 vec3(95.047, 100.0, 108.883) // D65 reference white #define M_D75 vec3(94.972, 100.0, 122.638) // D75 reference white // ============================================================================= // PROTOTYPES // ============================================================================= vec3 convert_rgb2hsv(vec3 rgb); vec3 convert_rgb2lab(vec3 rgb); vec3 convert_rgb2xyz(vec3 rgb); vec3 convert_hsv2rgb(vec3 hsv); vec3 convert_hsv2lab(vec3 hsv); vec3 convert_hsv2xyz(vec3 hsv); vec3 convert_lab2rgb(vec3 lab); vec3 convert_lab2hsv(vec3 lab); vec3 convert_lab2xyz(vec3 lab); vec3 convert_xyz2rgb(vec3 xyz); vec3 convert_xyz2hsv(vec3 xyz); vec3 convert_xyz2lab(vec3 xyz); vec3 convert_rgb2oklab(vec3 rgb); vec3 convert_oklab2rgb(vec3 lab); //------------------------------------------------------------------------------ // RGB //------------------------------------------------------------------------------ vec3 convert_rgb2hsv(vec3 rgb) { vec4 K = vec4(0.0, -1.0 / 3.0, 2.0 / 3.0, -1.0); vec4 p = mix(vec4(rgb.bg, K.wz), vec4(rgb.gb, K.xy), step(rgb.b, rgb.g)); vec4 q = mix(vec4(p.xyw, rgb.r), vec4(rgb.r, p.yzx), step(p.x, rgb.r)); float d = q.x - min(q.w, q.y); return vec3(abs(q.z + (q.w - q.y) / (6.0 * d + M_EPSILON)), d / (q.x + M_EPSILON), q.x); } vec3 convert_rgb2lab(vec3 rgb) { vec3 xyz = convert_rgb2xyz(rgb); return convert_xyz2lab(xyz); } vec3 convert_rgb2xyz(vec3 rgb) { vec3 tmp; tmp.x = (rgb.r > 0.04045) ? pow((rgb.r + 0.055) / 1.055, 2.4) : rgb.r / 12.92; tmp.y = (rgb.g > 0.04045) ? pow((rgb.g + 0.055) / 1.055, 2.4) : rgb.g / 12.92; tmp.z = (rgb.b > 0.04045) ? pow((rgb.b + 0.055) / 1.055, 2.4) : rgb.b / 12.92; return 100.0 * tmp * mat3( 0.4124, 0.3576, 0.1805, 0.2126, 0.7152, 0.0722, 0.0193, 0.1192, 0.9505 ); } //------------------------------------------------------------------------------ // HSV //------------------------------------------------------------------------------ vec3 convert_hsv2rgb(vec3 hsv) { hsv = vec3(hsv.x, clamp(hsv.yz, 0.0, 1.0)); vec4 K = vec4(1.0, 2.0 / 3.0, 1.0 / 3.0, 3.0); vec3 p = abs(fract(hsv.xxx + K.xyz) * 6.0 - K.www); return hsv.z * mix(K.xxx, clamp(p - K.xxx, 0.0, 1.0), hsv.y); } vec3 convert_hsv2lab(vec3 hsv) { float H = hsv.x * 360.0; float S = hsv.y; float V = hsv.z; // Convert to LAB float L = V * 100.0; float C = S * L; float h = H * M_PI / 180.0; float a = C * cos(h); float b = C * sin(h); // Normalize LAB return vec3(L / 100.0, (a + 128.0) / 255.0, (b + 128.0) / 255.0); } vec3 convert_hsv2xyz(vec3 hsv) { vec3 rgb = convert_hsv2rgb(hsv); return convert_rgb2xyz(rgb); } //------------------------------------------------------------------------------ // LAB //------------------------------------------------------------------------------ vec3 convert_lab2rgb(vec3 lab) { vec3 xyz = convert_lab2xyz(lab); return convert_xyz2rgb(xyz); } vec3 convert_lab2hsv(vec3 lab) { vec3 rgb = convert_lab2rgb(lab); return convert_rgb2hsv(rgb); } vec3 convert_lab2xyz(vec3 lab) { float fy = (lab.x + 16.0) / 116.0; float fx = lab.y / 500.0 + fy; float fz = fy - lab.z / 200.0; vec3 f = vec3(fx, fy, fz); vec3 thresh = step(vec3(0.206897), f); vec3 xyz = mix( (f - vec3(16.0/116.0)) / 7.787, f * f * f, thresh ); return xyz * M_D65; } //------------------------------------------------------------------------------ // XYZ //------------------------------------------------------------------------------ vec3 convert_xyz2rgb(vec3 xyz) { vec3 v = xyz / M_D65; vec3 thresh = step(0.0031308, v); return mix( 12.92 * v, 1.055 * pow(v, vec3(1.0/2.4)) - 0.055, thresh ); } vec3 convert_xyz2hsv(vec3 xyz) { vec3 rgb = convert_xyz2rgb(xyz); return convert_rgb2hsv(rgb); } vec3 convert_xyz2lab(vec3 xyz) { vec3 n = xyz / M_D65; vec3 thresh = step(vec3(0.008856), n); vec3 v = mix( 7.787 * n + vec3(16.0/116.0), pow(n, vec3(1.0/3.0)), thresh ); return vec3( 116.0 * v.y - 16.0, 500.0 * (v.x - v.y), 200.0 * (v.y - v.z) ); } //------------------------------------------------------------------------------ // OKLAB //------------------------------------------------------------------------------ // RGB to Oklab (perceptually uniform color space) vec3 convert_rgb2oklab(vec3 rgb) { vec3 lms = rgb * mat3( 0.4122214708, 0.5363325363, 0.0514459929, 0.2119034982, 0.6806995451, 0.1073969566, 0.0883024619, 0.2817188376, 0.6299787005 ); lms = pow(lms, vec3(1.0/3.0)); return lms * mat3( 0.2104542553, 0.7936177850, -0.0040720468, 1.9779984951, -2.4285922050, 0.4505937099, 0.0259040371, 0.7827717662, -0.8086757660 ); } // Oklab to RGB vec3 convert_oklab2rgb(vec3 lab) { vec3 lms = lab * mat3( 1.0000000000, 0.3963377774, 0.2158037573, 1.0000000000, -0.1055613458, -0.0638541728, 1.0000000000, -0.0894841775, -1.2914855480 ); lms = lms * lms * lms; return lms * mat3( 4.0767416621, -3.3077115913, 0.2309699292, -1.2684380046, 2.6097574011, -0.3413193965, -0.0041960863, -0.7034186147, 1.7076147010 ); } #endif uniform sampler2D image; // | RGB(A) image uniform vec3 HSV; // 0.,1.,1.;-1;2;0.01 | Adjust the Hue, Saturation or Value void mainImage(out vec4 fragColor, vec2 fragCoord) { vec2 uv = fragCoord.xy / iResolution.xy; vec4 color = texture(image, uv); vec3 hsv = convert_rgb2hsv(color.rgb); hsv.x = mod(hsv.x + HSV.x, 1.0); hsv.y = clamp(hsv.y * HSV.y, 0.0, 1.0); hsv.z = clamp(hsv.z * HSV.z, 0.0, 1.0); fragColor = vec4(convert_hsv2rgb(hsv), color.a); } | — |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| RGBA | IMAGE | Full channel [RGBA] image. If there is an alpha, the image will be masked out with it when using this output. |
| RGB | IMAGE | Three channel [RGB] image. There will be no alpha. |
| MASK | MASK | Single channel mask output. |