Closed ut4 closed 1 month ago
That is an effect of the rounding of the alpha value (see issue https://github.com/mdbassit/Coloris/issues/134), which means that it is not possible to get the color value #000000d7
with the UI of the color picker. I will look into preserving the original value that's entered by a user though when it's a valid color.
I believe this is due to the a * 255 | 0 conversion in the RGBAToHex function. Is this conversion necessary, or could it be removed?
The line a * 255 | 0
is equivalent to Math.floor(a * 255)
in this case.
Here is a proposed fix that addresses the issue:
Your code is actually just substituting one rounding method with another, and you still won't be able to obtain the full 0 to 255 alpha values. For example, with your code, it's not possible to pick #000000d6
.
It appears that information is being lost twice: first in strToRGBA()
(via ctx.fillStyle
), and second in RGBAToHex()
, as I reported in my initial post. For example, when pasting #000000d6
or rgba(0,0,0,0.839)
(which are the same color) into the picker, ctx.fillStyle converts it to rgba(0,0,0,0.84)
, which then translates to #000000d7
in hex. Based on my experience, this bug requires two fixes: the first one is already provided in the initial post, and the second one needs to address strToRGBA()
. Could we add a special handling for HEXA, RGBA, and maybe HSLA formats, for example, like this?
@@ -867,10 +867,13 @@
* Parse a string to RGBA.
* @param {string} str String representing a color.
* @return {object} Red, green, blue and alpha values.
*/
function strToRGBA(str) {
+ const rgba = tryToParseRGBASpecial(str);
+ if (rgba) return rgba;
+
const regex = /^((rgba)|rgb)[\D]+([\d.]+)[\D]+([\d.]+)[\D]+([\d.]+)[\D]*?([\d.]+|$)/i;
let match, rgba;
// Default to black for invalid color strings
ctx.fillStyle = '#000';
Could we add a special handling for HEXA, RGBA, and maybe HSLA formats, for example, like this?
That is what I meant in my previous comment when I said that I will look into preserving the original value that's entered by a user when it's a valid color.
Alright, I looked into this, and doing it properly will add unnecessary complexity to account for all the possible syntax variations of rgb
and hsl
, and when the gain is a virtually imperceivable alpha channel fidelity, I don't think it's worth the effort.
What if the solution handled only HEXA colors? This shouldn't introduce too much complexity but would solve the core issue. Here's a proposal:
function tryToParseRGBASpecial(str) {
const match = /^#([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})([\dA-Fa-f]{2})$/i.exec(str);
if (!match)
return null;
return {
r: parseInt(match[1], 16),
g: parseInt(match[2], 16),
b: parseInt(match[3], 16),
a: parseInt(match[4], 16) / 255 // 0 - 255 -> 0 - 1
};
}
When pasting a transparent color into the picker, such as
#000000d7
, it gets converted to#000000d6
(another example is#00000022 -> #00000021
). I believe this is due to thea * 255 | 0
conversion in theRGBAToHex
function. Is this conversion necessary, or could it be removed? Here is a proposed fix that addresses the issue:Alternatively:
Feel free to adjust the code and comments as necessary.