Bug 343864 - Implement dithering/adaptive supersampling/high channel depth gradients
Summary: Implement dithering/adaptive supersampling/high channel depth gradients
Status: RESOLVED FIXED
Alias: None
Product: krita
Classification: Applications
Component: Color models (show other bugs)
Version: 2.9 Beta
Platform: Other Linux
: NOR wishlist
Target Milestone: ---
Assignee: Krita Bugs
URL:
Keywords:
: 344128 386492 402834 (view as bug list)
Depends on:
Blocks: 392252
  Show dependency treegraph
 
Reported: 2015-02-06 17:16 UTC by wolthera
Modified: 2021-02-19 16:46 UTC (History)
5 users (show)

See Also:
Latest Commit:
Version Fixed In:


Attachments
The kra file for poking at. (867.60 KB, application/x-krita)
2015-02-06 17:16 UTC, wolthera
Details
png screenshot for easy viewing. (266.98 KB, image/png)
2015-02-06 17:25 UTC, wolthera
Details
Gradient generated by Krita (notice non-smooth transition) (39.01 KB, image/png)
2020-05-15 11:23 UTC, Konstantin Dmitriev
Details
Gradient generated by Gimp (525.70 KB, image/png)
2020-05-15 11:24 UTC, Konstantin Dmitriev
Details

Note You need to log in before you can comment on or make changes to this bug.
Description wolthera 2015-02-06 17:16:05 UTC
I will be attaching some examples, but the lowdown is that gradients seem to be blending in sRGB only. This is sad.

Reproducible: Always
Comment 1 wolthera 2015-02-06 17:16:40 UTC
Created attachment 90948 [details]
The kra file for poking at.
Comment 2 wolthera 2015-02-06 17:25:18 UTC
Created attachment 90949 [details]
png screenshot for easy viewing.

Vertical:
Gradient 1: 12,13 hdr red over 29.86 blue as a foreground-color-to-transparent. These values are out of range for me, so the blending is extreme, but it's still correct for a linear space. Note the purple. ( :) )
Gradient 2: 12.13 red with 29.86 blue as foreground-to-background-color: These values are still out of range, but instead they have been converted to 1.0 red to 1.0 blue, and are mixed with a non-linear gamma. ( :( )
Gradient 3: Also a foreground-to-background-color gradient with 12.13 red and 16.0 green. Again converted, again wrong mixing. ( :( )

Horizontal:
Gradient 1:  1.0 red over 1.0 blue as a foreground-color-to-transparent. The blending is linear and nice ( :) )
Gradient 2:  1.0 white to 0.0 black as a foreground-color-to background-color-gradient. The mixing is non-linear, as evidenced by the middlish color being 0.28 grey. ( :( )
Gradient 3:  1.0 white over 0.0 black as a foreground-color-to-transparent. The blending is linear as evidenced by the middlish colour being 0.55 grey  ( :) )

My rendering conversion is set to "Relative Colorimetric" btw, but that should not effect the bad blending of the gradients.
Comment 3 wolthera 2015-02-06 20:22:35 UTC
Also, Krita clips gradient-colors at 1.0.
Comment 4 wolthera 2015-02-20 22:02:21 UTC
*** Bug 344128 has been marked as a duplicate of this bug. ***
Comment 5 Halla Rempt 2017-11-08 10:50:14 UTC
*** Bug 386492 has been marked as a duplicate of this bug. ***
Comment 6 wolthera 2017-11-08 11:24:37 UTC
regarding the dithering, there was a brnach that worked on it: https://phabricator.kde.org/source/krita/history/akapustin%252Fdithering2/
Comment 7 Halla Rempt 2020-05-15 10:48:15 UTC
*** Bug 402834 has been marked as a duplicate of this bug. ***
Comment 8 Konstantin Dmitriev 2020-05-15 11:22:45 UTC
In Morevna Project we also had much problems with gradients when used Krita.

Example:

Gradient from #353e66 to #2d0000

In Krita it gives non-uniform (non-smooth) gradient.
In Gimp with the same colors the result  is smooth. 

Does this bug covers described problem?
Comment 9 Konstantin Dmitriev 2020-05-15 11:23:27 UTC
Created attachment 128472 [details]
Gradient generated by Krita (notice non-smooth transition)
Comment 10 Konstantin Dmitriev 2020-05-15 11:24:05 UTC
Created attachment 128473 [details]
Gradient generated by Gimp
Comment 11 Halla Rempt 2020-05-15 12:02:43 UTC
Yes, that basically the issue in this feature request.
Comment 12 Bug Janitor Service 2021-01-26 00:27:42 UTC
A possibly relevant merge request was started @ https://invent.kde.org/graphics/krita/-/merge_requests/668
Comment 13 amyspark 2021-02-10 18:57:43 UTC
Git commit 4cfda40a29f9ee7548ab5d2f7320f2fca8674f65 by L. E. Segovia.
Committed on 10/02/2021 at 18:50.
Pushed by lsegovia into branch 'master'.

Feature: HDR gradients

This commit adds suport in Krita for rendering of HDR, high-bit-depth
gradients, and dithering for all output bit depths.

Firstly, all gradient operations are now upgraded; this includes color
mixing ops (step values, upgraded to 16-bit signed integer), and
gradients' default bit depth, which was upgraded to 16-bit integer
or the image's bit depth, whichever is higher.

Secondly, this commit implements a fully SSE+ vectorizable dithering
operator, based on the Pixman low-level graphics library's
implementation (MIT-licensed) available at the following commits:

https://gitlab.freedesktop.org/pixman/pixman/-/commit/ddcc41b999562efdd9f88daa51ffbf39782748b5
https://gitlab.freedesktop.org/pixman/pixman/-/commit/98b5ec74ca14448349ef6a33a663ad19d446ed6b
https://gitlab.freedesktop.org/pixman/pixman/-/commit/cb2ec4268fbde0df3b588ce5cbe2e43e0465452

This version follows closely the original paper of Ulichney's:

Robert A. Ulichney. "Void-and-cluster method for dither array
generation", Proc. SPIE 1913, Human Vision, Visual Processing, and
Digital Display IV, (8 September 1993); doi:10.1117/12.152707

Based on Pixman's work, there are two available options
(but three in code, see below):

- a no-op downsampler

- blue-noise Ulichney's dithering, 64x64, which is the default when
enabled

- Bayer's ordered dithering, 8x8, which has been left as a backup.

The dither operator works by upcasting the pixel to normalized,
floating point color space; applying modulated noise with scale
1 / 2^bit_depth, and then downcasting the pixel to the destination
depth. For obvious reasons, the first step is skipped if the source
is already floating point, and the two latter are no-ops if the
destination's floating point.

The implementation in this commit is structured in a two-level
abstract pattern:

- KisDitherOp is the interface that all operators
expose to dither a single pixel. They are implemented as instances of
KisDitherOpImpl<srcCSTraits, dstCSTraits, DitherType>.

- KisDitherOpImpl is the template class that does the hard work
described above.

Instances of the dither operator are inserted on each colorspace
through a templated, inlined factory function,
addStandardDitherOps<srcCSTraits>(KoColorSpace *). Given the
source bit depth and all known possible destination depths,
this template calls another templated function, addDitherOpsByDepth<
srcCSTraits, dstCSTraits, DitherType>(KoColorSpace *). Each call
to this function creates a KisDitherOpImpl instance corresponding
to each triplet of bit depths and dither implementation, and inserts it
in the given colorspace.

Since this operator needs both source and destination
colorspaces' traits, I check at compilation time that all known traits
have been considered at op creation.

The vectorization properties have been tested with Xcode 11 on macOS,
dumping kritalcmsengine.so with objdump, and checking disassembly
manually.

There are two ways to use this dither operator, once a copy has been
obtained:

- Use dither(const quint8* src, quint8* dst, int x, int y) to dither
a single pixel.

- Use dither(const quint8* src, int srcRowStride, quint8* dst,
int dstRowStride, int x, int y, int columns, int rows) to dither a
whole tile at once. This is the pattern that's used in
KisGradientPainter.

Additionally to Pixman's implementation, and the optimizations already
provided by KoColorSpaceTraits, an optimized version has been
made for the case of pass-through dither and no downcasting, where a
memcpy call suffices.

Finally, this implementation has been made available as a checkbox in:

- the Gradient tool

- Layer / Layer Styles / Gradient overlay

- Fill Layers / Gradient generator

Support has also been included for Photoshop's dithered gradients,
when importing and exporting PSDs. As with the rest of Krita,
they map to blue-noise dithering.

Thanks to Wolthera van Hövell, Dmitry Kazakov, and Mathias Wein for
their review.
CCMAIL: kimageshop@kde.org

M  +10   -7    libs/global/kis_global.h
M  +5    -6    libs/image/kis_asl_layer_style_serializer.cpp
M  +73   -20   libs/image/kis_gradient_painter.cc
M  +6    -2    libs/image/kis_gradient_painter.h
M  +3    -1    libs/image/layerstyles/kis_ls_utils.cpp
A  +203  -0    libs/pigment/KisDitherMaths.h     [License: MIT]
A  +52   -0    libs/pigment/KisDitherOp.h     [License: GPL(v2.0+)]
A  +194  -0    libs/pigment/KisDitherOpImpl.h     [License: GPL(v2.0+)]
M  +40   -3    libs/pigment/KoColorSpace.cpp
M  +11   -3    libs/pigment/KoColorSpace.h
M  +2    -2    libs/pigment/KoColorSpaceAbstract.h
M  +5    -1    libs/pigment/KoColorSpace_p.h
M  +3    -1    libs/pigment/colorspaces/KoLabColorSpace.cpp
M  +4    -1    libs/pigment/colorspaces/KoRgbU16ColorSpace.cpp
M  +3    -2    libs/pigment/colorspaces/KoRgbU8ColorSpace.cpp
A  +26   -0    libs/pigment/dithering/KisCmykDitherOpFactory.h     [License: GPL(v2.0+)]
A  +26   -0    libs/pigment/dithering/KisGrayDitherOpFactory.h     [License: GPL(v2.0+)]
A  +26   -0    libs/pigment/dithering/KisLabDitherOpFactory.h     [License: GPL(v2.0+)]
A  +27   -0    libs/pigment/dithering/KisRgbDitherOpFactory.h     [License: GPL(v2.0+)]
A  +26   -0    libs/pigment/dithering/KisXyzDitherOpFactory.h     [License: GPL(v2.0+)]
A  +26   -0    libs/pigment/dithering/KisYCbCrDitherOpFactory.h     [License: GPL(v2.0+)]
M  +40   -67   libs/pigment/resources/KoSegmentGradient.cpp
M  +17   -32   libs/pigment/resources/KoStopGradient.cpp
M  +11   -0    libs/psd/psd.h
M  +3    -0    libs/ui/dialogs/kis_dlg_layer_style.cpp
M  +34   -15   libs/ui/layerstyles/WdgGradientOverlay.ui
M  +3    -1    plugins/color/lcms2engine/colorspaces/cmyk_f32/CmykF32ColorSpace.cpp
M  +16   -13   plugins/color/lcms2engine/colorspaces/cmyk_u16/CmykU16ColorSpace.cpp
M  +1    -3    plugins/color/lcms2engine/colorspaces/cmyk_u16/CmykU16ColorSpace.h
M  +16   -13   plugins/color/lcms2engine/colorspaces/cmyk_u8/CmykU8ColorSpace.cpp
M  +1    -3    plugins/color/lcms2engine/colorspaces/cmyk_u8/CmykU8ColorSpace.h
M  +3    -0    plugins/color/lcms2engine/colorspaces/gray_f16/GrayF16ColorSpace.cpp
M  +3    -0    plugins/color/lcms2engine/colorspaces/gray_f32/GrayF32ColorSpace.cpp
M  +9    -6    plugins/color/lcms2engine/colorspaces/gray_u16/GrayU16ColorSpace.cpp
M  +1    -3    plugins/color/lcms2engine/colorspaces/gray_u16/GrayU16ColorSpace.h
M  +9    -6    plugins/color/lcms2engine/colorspaces/gray_u8/GrayU8ColorSpace.cpp
M  +1    -3    plugins/color/lcms2engine/colorspaces/gray_u8/GrayU8ColorSpace.h
M  +3    -1    plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/rgb_f16/RgbF16ColorSpace.cpp
M  +5    -3    plugins/color/lcms2engine/colorspaces/rgb_f32/RgbF32ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/rgb_u16/RgbU16ColorSpace.cpp
M  +7    -4    plugins/color/lcms2engine/colorspaces/rgb_u8/RgbU8ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/xyz_f16/XyzF16ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/xyz_f32/XyzF32ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/xyz_u16/XyzU16ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/xyz_u8/XyzU8ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/ycbcr_f32/YCbCrF32ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/ycbcr_u16/YCbCrU16ColorSpace.cpp
M  +4    -1    plugins/color/lcms2engine/colorspaces/ycbcr_u8/YCbCrU8ColorSpace.cpp
M  +3    -1    plugins/generators/gradient/KisGradientGenerator.cpp
M  +4    -0    plugins/generators/gradient/KisGradientGeneratorConfigWidget.cpp
M  +14   -0    plugins/generators/gradient/KisGradientGeneratorConfigWidget.ui
M  +12   -1    plugins/generators/gradient/KisGradientGeneratorConfiguration.cpp
M  +8    -0    plugins/generators/gradient/KisGradientGeneratorConfiguration.h
M  +17   -2    plugins/tools/basictools/kis_tool_gradient.cc
M  +4    -0    plugins/tools/basictools/kis_tool_gradient.h

https://invent.kde.org/graphics/krita/commit/4cfda40a29f9ee7548ab5d2f7320f2fca8674f65
Comment 14 amyspark 2021-02-11 14:52:26 UTC
Git commit 76f54aa2e76684399280f116f5ea9d9e322c749e by L. E. Segovia.
Committed on 11/02/2021 at 14:47.
Pushed by lsegovia into branch 'master'.

Fix same-depth dithering op skipping pixels
Related: bug 432758

M  +1    -1    libs/pigment/KisDitherOpImpl.h

https://invent.kde.org/graphics/krita/commit/76f54aa2e76684399280f116f5ea9d9e322c749e
Comment 15 amyspark 2021-02-11 14:52:42 UTC
Git commit a4ac9f32c2531df412daa4bb3775af960644b718 by L. E. Segovia.
Committed on 11/02/2021 at 14:47.
Pushed by lsegovia into branch 'master'.

Fix typo in dither ops for 16-bit integer CMYK
Related: bug 432758

M  +1    -1    plugins/color/lcms2engine/colorspaces/cmyk_u16/CmykU16ColorSpace.cpp

https://invent.kde.org/graphics/krita/commit/a4ac9f32c2531df412daa4bb3775af960644b718
Comment 16 amyspark 2021-02-11 14:52:50 UTC
Git commit 688e896fb35107100c66a1069a05be1ee4ddb566 by L. E. Segovia.
Committed on 11/02/2021 at 14:47.
Pushed by lsegovia into branch 'master'.

Subclass the dither operator for CMYK color spaces

Floating point CMYK colorspaces have different normalization factors
for color and alpha channels.
Related: bug 432758

M  +222  -4    libs/pigment/dithering/KisCmykDitherOpFactory.h

https://invent.kde.org/graphics/krita/commit/688e896fb35107100c66a1069a05be1ee4ddb566