[ANNOUNCE] node-red-contrib-chroma

This is a follow-up node to the iro.js color picker. The iro.js color picker supports many common color formats. As the iro.js is a ui-widget only there might be a need of a color conversion node.

A while ago I discovered chroma.js when I was looking for good way to generate color scales for data visualization in another project. Beside of great color scales chroma.js do a great job converting color formats. I added RGBW and CIExyz and CIExy as this formats are often used in color illumination.

chroma.js is a small-ish zero-dependency JavaScript library (13.5kB) for all kinds of color conversions and color scales

Examples how to use this node are available. Please take a look into the interactive documentation of chroma.js to find out more about api calls.

Even if working with color is a niche task I'm more than happy to receive your valuable input. Especially I'm interested if the way I tried to make the chroma.js api available is any good or if there might be a better way?

5 Likes

Hello @Christian-Me
I had missed the appearance of the Chroma node. Since I use deconz with the CIExy format and the other color converters do not support this format, I tried your node.

What I noticed, it doesn't apply gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device.

There is a script here that takes gamma corrections into account. I use this in a function node if necessary.

For comparison two photos of my kitchen lamp with the color "Aquamarine". The first shows the result with the script and the second shows the color output of the Chroma node.

IMG_20211024_143509
IMG_20211024_143522

[{"id":"aedc8dc1bb0a4216","type":"inject","z":"e6bdcf44.09a93","name":"aquamarine","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"aquamarine","payload":"aquamarine","payloadType":"str","x":2010,"y":3980,"wires":[["e2c8f9a0f25e112e"]]},{"id":"48fa3a9691147a97","type":"inject","z":"e6bdcf44.09a93","name":"orange","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"orange","payload":"orange","payloadType":"str","x":2030,"y":4020,"wires":[["e2c8f9a0f25e112e"]]},{"id":"c33d35f907e37390","type":"inject","z":"e6bdcf44.09a93","name":"aquamarine","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"aquamarine","payload":"aquamarine","payloadType":"str","x":2010,"y":4080,"wires":[["7f73d562ae464bd4"]]},{"id":"f8ec4f03112c1e26","type":"inject","z":"e6bdcf44.09a93","name":"orange","props":[{"p":"payload"},{"p":"topic","vt":"str"}],"repeat":"","crontab":"","once":false,"onceDelay":"","topic":"orange","payload":"orange","payloadType":"str","x":2030,"y":4120,"wires":[["7f73d562ae464bd4"]]},{"id":"7f73d562ae464bd4","type":"chroma","z":"e6bdcf44.09a93","name":"RGB object","outFormat":"rgb","array2object":true,"floatOutput":true,"inputRelativeValues":"percent","outputRelativeValues":"percent","x":2350,"y":4100,"wires":[["43ed3cf5c3fd815c"]]},{"id":"e2c8f9a0f25e112e","type":"chroma","z":"e6bdcf44.09a93","name":"CIExy object","outFormat":"CIExy","array2object":true,"floatOutput":true,"inputRelativeValues":"percent","outputRelativeValues":"percent","x":2350,"y":4020,"wires":[["0009377fdcfa91dc"]]},{"id":"0009377fdcfa91dc","type":"function","z":"e6bdcf44.09a93","name":"","func":"var x = msg.payload.x;\nvar y = msg.payload.y;\nmsg.payload = [x, y];\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2520,"y":4020,"wires":[["c185eba5a4089bde"]]},{"id":"43ed3cf5c3fd815c","type":"function","z":"e6bdcf44.09a93","name":"RGB_CIE","func":"// @ts-nocheck\nfunction rgb_to_cie(red, green, blue)\n{\n\t//Apply a gamma correction to the RGB values, which makes the color more vivid and more the like the color displayed on the screen of your device\n\tvar red \t= (red > 0.04045) ? Math.pow((red + 0.055) / (1.0 + 0.055), 2.4) : (red / 12.92);\n\tvar green \t= (green > 0.04045) ? Math.pow((green + 0.055) / (1.0 + 0.055), 2.4) : (green / 12.92);\n\tvar blue \t= (blue > 0.04045) ? Math.pow((blue + 0.055) / (1.0 + 0.055), 2.4) : (blue / 12.92); \n\n\t//RGB values to XYZ using the Wide RGB D65 conversion formula\n\tvar X \t\t= red * 0.664511 + green * 0.154324 + blue * 0.162028;\n\tvar Y \t\t= red * 0.283881 + green * 0.668433 + blue * 0.047685;\n\tvar Z \t\t= red * 0.000088 + green * 0.072310 + blue * 0.986039;\n\n\t//Calculate the xy values from the XYZ values\n\tvar x \t\t= (X / (X + Y + Z));\n\tvar y \t\t= (Y / (X + Y + Z));\n\t\n\t//var z = Z;\n\n\tif (isNaN(x))\n\t\tx = 0;\n\tif (isNaN(y))\n\t\ty = 0;\t \n\t//return [x, y, z];\n\treturn [x, y];\n}\nmsg.payload = rgb_to_cie(msg.payload.r, msg.payload.g, msg.payload.b);\nconsole.log(msg.payload);\nreturn msg;","outputs":1,"noerr":0,"initialize":"","finalize":"","libs":[],"x":2520,"y":4100,"wires":[["c185eba5a4089bde"]]},{"id":"c185eba5a4089bde","type":"debug","z":"e6bdcf44.09a93","name":"","active":true,"tosidebar":true,"console":false,"tostatus":false,"complete":"false","statusVal":"","statusType":"auto","x":2690,"y":4060,"wires":[]}]

Maybe you could support gamma correction in a future update for the CIExy format.

Thanks a lot!

1 Like

Hi!
Thank you for the request to improve the node. Will implement it soon. I also will implement some code for converting CIExy to rgb someone else pointed me to. Certainly not precise as information is missing (as far as I know) but a compromise for people only getting CIExy out of their devices.
Chris

1 Like

And if you have time please raise an issue on GitHub that I won’t forget to do so. Referring to you post here is enough.

Done :+1:

1 Like