This MR tries to solve bug 463585: some noticeable banding appears when using the gradient map filter.
There was two issues:
There was some banding in 8 bits. For example, if we made a black to white gradient on a layer and then we applied the gradient map with the same black to white gradient to that layer, every gray color on the layer should be mapped to the same gray color on the gradient (kind of an identity function since the black to white gradient was used). But there was some banding. This was due to the
intensity8function needing rounding.
I changed the implementation of that function to use an integer version that is also more accurate, due to floating point errors on the old implementation. For example, if we had some rgb color like (255, 253, 243) then the formula:
255 * 0.30 + 253 * 0.59 + 243 * 0.11gives
252.4999999999...when it should be
252.5. Even when adding 0.5 to round (
qRound), the result is
252.999999..., which gets floored to 252 when casting to int. The result should be 253. The integer version does not have those errors. It is
(p->red * 30 + p->green * 59 + p->blue * 11 + 50) / 100. The
+ 50is there for rounding. What I don't know is whether that's less performant, since it uses a division.
The other issue which produced banding was present when the image had a higher depth. This time the previous issue is still relevant, but even when it was fixed the banding persisted. It was due to the
intensity8function using the
toQColorfunction to get a rgb color and then converting that to grayscale.
toQColorconverts the original color to 8 bit rgb. So when that was used to generate the intensity value, there was no enough range, and the banding appeared. So I implemented a new
intensityFfunction which returns a double in the range [0, 1]. This uses a new
toQColor16function that converts the original color to a 16 bit rgb
QColoruses 16 bits internally, so that is perfectly fine. with a 16 bit
redFhave more precision, so we can generate an intensity value that also has more precision to avoid the banding. I had to add some things to
LcmsColorSpace. Let me know if they are ok because I'm not confident enough touching such files.
I confirmed this builds.
I confirmed Krita ran and the relevant functions work.
I tested the relevant unit tests and can confirm they are not broken. (If not possible, don't hesitate to ask for help!)
I made sure my commits build individually and have good descriptions as per KDE guidelines.
I made sure my code conforms to the standards set in the HACKING file.
I can confirm the code is licensed and attributed appropriately, and that unattributed code is mine, as per KDE Licensing Policy.