hsluv / hsluv-c

C99 implementation of HSLuv (revision 4)
https://www.hsluv.org/
MIT License
90 stars 7 forks source link

Saturation Range for HPLuv is not 0...100 #6

Closed rof-ableton closed 11 months ago

rof-ableton commented 4 years ago

In src/hsluv.h the documentation says for rgb2hpluv: @param[out] ps Saturation. Between 0.0 and 100.0. but I think this is incorrect.

When passing the RGB values 1,1,0 (yellow) the returned Saturation is 1784.236 and for other colors it is also bigger then 100. The values are not wrong according to the CIELUV color space, only the documentation states it incorrectly.

The result from rgb2hpluv also correctly converts back to the original color when using hpluv2rgb.

The problem with Saturation values higher than 100 is that hpluv2rgb might return invalid RGB values. Only combinations of HPL values within 0...360, 0...100, 0...100 are always valid. But a user of the function can distinguish this by checking that the returned RGB values are in the range 0...100 and conclude otherwise that the HPL values were invalid.

I think it would be helpful to describe this in the documentation.

mity commented 4 years ago

Thanks for the report.

@boronine Alex, could you please put some light into this? What are the real bounds for the HPLuv colorspace? To be honest, to a substantial degree I worked on the C implementation in the monkey style: Just make sure it encodes the given math formulas without an actual understanding the background behind it (and then blindly verify the correctness by the tests using the data in snapshot-rev4.json).

And because I use just HSLuv (and not HPLuv) in my projects, it's quite possible I've created this issue by a mindless copy&pasting the doc comment from HSLuv counterparts, without having a chance to detect any such discrepancy.

(Actually, in an ideal case it would be great if we have sort of a canonical function description all the implementations could simply reuse for their documentation purposes. This should be more or less the same in all the implementations.)

hartwork commented 4 years ago

Related:

boronine commented 4 years ago

Thanks for reporting this. There is indeed a lack of documentation on this issue.

When passing the RGB values 1,1,0 (yellow) the returned Saturation is 1784.236 and for other colors it is also bigger then 100. The values are not wrong according to the CIELUV color space, only the documentation states it incorrectly.

Both HSLuv and HPLuv are bounded in [0-360] [0-100] [0-100]. So the example above is an invalid HPLuv color. Actually the whole point of the project is to produce a version of CIELUV with strictly bounded components. So @mity's documentation is correct, but perhaps incomplete.

At least one implementation provides clarification for this issue: "Note that HPLuv does not contain all the colors of RGB, so converting arbitrary RGB to it may generate invalid HPLuv colors." Source: https://github.com/hsluv/hsluv/tree/master/javascript

I'd suggest adding this sentence to this repo. I agree with @mity that a reusable documentation would be great. I made an issue on the main repo to track this: https://github.com/hsluv/hsluv/issues/74

mity commented 4 years ago

@boronine Can the application reasonably verify whether the RGB triplet falls into the valid subspace, either before the call or after it, e.g. by checking the resulted HPLuv triplet falls into the expected ranges?

boronine commented 4 years ago

checking the resulted HPLuv triplet falls into the expected ranges

That will work. I don't think there is a way to check without performing the transformation since the space is defined by the transformation.

mity commented 4 years ago

@boronine And what can app do if the transformation fails?

I mean, if the caller "rounds" the saturation outside the range to 0 or 100, whatever is closer, is it a complete nonsense or does it produce "the closest color available in the HPLuv space", in any reasonable sense?

Consider for example the RGB triplet may be very tightly off the allowed domain, e.g. due some floating point math rounding. Also I can imagine some apps would prefer to get "a color as close as possible" for any RGB triplet rather then just fail miserably without any way to recover. (If it's as simple as the clamping of the saturation, documenting it is likely good enough.)

mity commented 4 years ago

For now, I've added the note. But I'll keep this issue open as it is imho still sub-optimal, as commented in https://github.com/hsluv/hsluv/issues/74.

Most importantly, the expression "may generate invalid HPLuv colors" (emphasis mine) strictly speaking allows the function to return a valid HPLuv color even for an invalid input. I.e. it actually says there is an undefined return value for an invalid input.

But if the function defines what's valid or invalid input, it must be guaranteed the output does not look as a successful transformation and this has to be reflected in the documentation.