Bug 254784

Summary: In single channel mode show L*a*b* channels as grayscale, not as RGB
Product: [Applications] krita Reporter: pAt <pat69>
Component: Color modelsAssignee: amyspark <amy>
Status: RESOLVED FIXED    
Severity: normal CC: amy, dimula73, griffinvalley, halla
Priority: NOR    
Version: git master (please specify the git hash!)   
Target Milestone: ---   
Platform: Unlisted Binaries   
OS: Linux   
Latest Commit: Version Fixed In:
Sentry Crash Report:
Attachments: Screenshots of Krita and Cinepaint with L*a*b* channels single selected

Description pAt 2010-10-20 20:02:40 UTC
Created attachment 52704 [details]
Screenshots of Krita and Cinepaint with L*a*b* channels single selected

Version:           svn trunk
OS:                Linux

Krita doesn't show an L*a*b* image in the right way when just one channel is selected. I attached some screenshots of Krita and Cinepaint showing each L*a*b* channel single. You can see in Cinepaint how it should look like and compare how it looks like in Krita.

Reproducible: Always

Steps to Reproduce:
Load an image, no matter if it is a jpg or tiff. Then convert it to a L*a*b* colour space. Select the properties of the layer, and deselect two layers.

Actual Results:  
I can't see a black and white image when the channels a and b are deselected. The channels a and b contain all colour information. Instead of a black and white image, you get a green/blue one. If you choose a or b single, you get just a black image.

Expected Results:  
See the screenshots of Cinepaint
Comment 1 Halla Rempt 2011-03-26 10:47:43 UTC
Thanks for your report. This is an artefact of the way we currently compose the displayed image when we enable/disable channels. It's not easy to fix, but I agree that the current view is not useful, so we need to think about it.
Comment 2 wolthera 2014-06-22 15:46:15 UTC
I thought this was fixed, I think I even mentioned it at the sprint?

Basically there's an option in configure Krita->Display that allows you to set whether you prefer colour channels, if there's only one of them, to be greyscale or in color.

Unless this person is reffering to the active channels(in properties), instead of enabled channels(in channel docker).
Comment 3 Halla Rempt 2014-12-29 11:35:01 UTC
I think the bug is still valid, right now, when I enable 'show channels in color', I will get a blue image for the L channel, not a gray one, and when I disable that option, I will get the orange/blue result Pat describes.

But I still don't know how to fix it...
Comment 4 Dmitry Kazakov 2015-06-21 10:20:44 UTC
Renamed the bug into something more understandable
Comment 5 wolthera 2019-10-12 14:32:35 UTC
Ah, I just looked at this a little, and understand half of the problem now:

In Lab, the assumption is that when a and b are inactive, they aren't black, but greyscale. (because they go from -0.5 to +0.5, so to speak.)

If you put a full mid-tone layer behind the image layer, and then disable the channels, everything looks correct.

(Except for the part where the 'show single channels as color' doesn't seem to make a difference...)
Comment 6 wolthera 2019-10-12 14:47:58 UTC
Ok, I am enclosing a pseudo-patch here, because I am not sure how to go about the stuff in the comments:


diff --git a/libs/ui/opengl/kis_texture_tile_update_info.h b/libs/ui/opengl/kis_texture_tile_update_info.h
index 60900c9d58..42cd777e13 100644
--- a/libs/ui/opengl/kis_texture_tile_update_info.h
+++ b/libs/ui/opengl/kis_texture_tile_update_info.h
@@ -161,6 +161,8 @@ public:
     void retrieveData(KisPaintDeviceSP projectionDevice, const QBitArray &channelFlags, bool onlyOneChannelSelected, int selectedChannelIndex)
     {
         m_patchColorSpace = projectionDevice->colorSpace();
+        //This seems like a dangerous thing to do at this place...?
+        bool isLab = m_patchColorSpace->colorModelId() == "LABA";
         m_patchPixels.allocate(m_patchColorSpace->pixelSize());
 
         projectionDevice->readBytes(m_patchPixels.data(),
@@ -185,6 +187,21 @@ public:
                     for (uint channelIndex = 0; channelIndex < m_patchColorSpace->channelCount(); ++channelIndex) {
 
                         if (channelInfo[channelIndex]->channelType() == KoChannelInfo::COLOR) {
+                            if (isLab) {
+                                //if we're in lab, only copy the data into the first color channel(l), and the others filled with gray.
+                                if (channelIndex==0) {
+                                    memcpy(conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize),
+                                           m_patchPixels.data() + (pixelIndex * pixelSize) + selectedChannelPos,
+                                           channelSize);
+                                } else {
+                                    //something that fills the section with lab (0.5, 0.5, 0.5)
+                                }
+
+                            } else {
+                                memcpy(conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize),
+                                       m_patchPixels.data() + (pixelIndex * pixelSize) + selectedChannelPos,
+                                       channelSize);
+                            }
                             memcpy(conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize),
                                    m_patchPixels.data() + (pixelIndex * pixelSize) + selectedChannelPos,
                                    channelSize);
@@ -204,6 +221,8 @@ public:
                             memcpy(conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize),
                                    m_patchPixels.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize),
                                    channelSize);
+                        } else if (isLab) {
+                            // fill the section with lab (0.5, 0.5, 0.5)
                         }
                         else {
                             memset(conversionCache.data() + (pixelIndex * pixelSize) + (channelIndex * channelSize), 0, channelSize);
Comment 7 wolthera 2019-10-12 16:01:23 UTC
ok, my previous comment is incorrect: this code is only relevant for the channels docker. -_-

I don't know where the paintdevices' channel compositing is happening, but what does happen there is that it should have the deactivated channels treated as lab(128, 128, 128) for 8bit and lab(50, 0, 0) for the rest... Or single channels get depicted as greyscale, always, lik dmitry suggested.
Comment 8 wolthera 2019-10-12 16:07:45 UTC
(In reply to wolthera from comment #7)
> ok, my previous comment is incorrect: this code is only relevant for the
> channels docker. -_-
> 
> I don't know where the paintdevices' channel compositing is happening, but
> what does happen there is that it should have the deactivated channels
> treated as lab(128, 128, 128) for 8bit and lab(50, 0, 0) for the rest... Or
> single channels get depicted as greyscale, always, lik dmitry suggested.

Actually, testing now, this section should probably be edited for the same reasons as well, I just can't figure out how to do it without crashing everything.
Comment 9 amyspark 2020-02-19 20:06:28 UTC
Assigning to myself (https://invent.kde.org/kde/krita/merge_requests/251).
Comment 10 amyspark 2020-03-03 16:10:50 UTC
Git commit 0a8a1c69059a0977cad5610d0b791165231a6cda by L. E. Segovia.
Committed on 03/03/2020 at 14:30.
Pushed by lsegovia into branch 'amyspark/254784-fix-lab-channel-canvas'.

Fix display of Lab channels

This is a horrible hack to manually set channel values when they are
disabled. Usually, they are left to 0, but Lab requires them to be set
to the corresponding halfValue.

Thanks to Wolthera for the initial pseudopatch -- the missing part was
the canvas code.

M  +136  -5    libs/ui/canvas/kis_image_pyramid.cpp
M  +147  -8    libs/ui/opengl/kis_texture_tile_update_info.h

https://invent.kde.org/kde/krita/commit/0a8a1c69059a0977cad5610d0b791165231a6cda
Comment 11 amyspark 2020-03-03 16:14:36 UTC
Pushed to the wrong repository, the MR still needs to be merged.
Comment 12 amyspark 2020-03-05 01:34:36 UTC
Git commit 7261d7bd192bcd0b555a0f5d2db1e10c760cc9a9 by L. E. Segovia.
Committed on 05/03/2020 at 01:30.
Pushed by lsegovia into branch 'master'.

Fix Lab channel render in canvas and Channels docker

This moves the channel rendering code to a KoColorSpace function
named convertChannelToVisualRepresentation, implemented in
KoColorSpaceAbstract and overriden in Lab colorspaces.

This function now handles copying channel values and, where necessary,
renormalizes it so as to fit the valid channel range (as with Lab).

As a bonus, I also fixed scaleToU8 in Lab because it needed
the same renormalization procedure.

Thanks to Wolthera for the initial pseudopatch -- the missing part was
the canvas code.

M  +28   -0    libs/pigment/KoColorSpace.h
M  +31   -0    libs/pigment/KoColorSpaceAbstract.h
M  +3    -0    libs/pigment/KoColorSpaceTraits.h
M  +88   -0    libs/pigment/colorspaces/KoLabColorSpace.cpp
M  +3    -0    libs/pigment/colorspaces/KoLabColorSpace.h
M  +2    -32   libs/ui/canvas/kis_image_pyramid.cpp
M  +8    -38   libs/ui/opengl/kis_texture_tile_update_info.h
M  +88   -0    plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp
M  +3    -0    plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.h
M  +88   -0    plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.cpp
M  +3    -0    plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.h
M  +88   -0    plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.cpp
M  +3    -0    plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.h

https://invent.kde.org/kde/krita/commit/7261d7bd192bcd0b555a0f5d2db1e10c760cc9a9
Comment 13 amyspark 2020-03-05 15:10:44 UTC
Git commit effe8431cdb0c08618ddce879740f7f6abd1e9e3 by L. E. Segovia.
Committed on 05/03/2020 at 13:37.
Pushed by lsegovia into branch 'krita/4.2'.

Fix Lab channel render in canvas and Channels docker

This moves the channel rendering code to a KoColorSpace function
named convertChannelToVisualRepresentation, implemented in
KoColorSpaceAbstract and overriden in Lab colorspaces.

This function now handles copying channel values and, where necessary,
renormalizes it so as to fit the valid channel range (as with Lab).

As a bonus, I also fixed scaleToU8 in Lab because it needed
the same renormalization procedure.

Thanks to Wolthera for the initial pseudopatch -- the missing part was
the canvas code.

M  +28   -0    libs/pigment/KoColorSpace.h
M  +31   -0    libs/pigment/KoColorSpaceAbstract.h
M  +3    -0    libs/pigment/KoColorSpaceTraits.h
M  +88   -0    libs/pigment/colorspaces/KoLabColorSpace.cpp
M  +3    -0    libs/pigment/colorspaces/KoLabColorSpace.h
M  +2    -32   libs/ui/canvas/kis_image_pyramid.cpp
M  +8    -38   libs/ui/opengl/kis_texture_tile_update_info.h
M  +88   -0    plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.cpp
M  +3    -0    plugins/color/lcms2engine/colorspaces/lab_f32/LabF32ColorSpace.h
M  +88   -0    plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.cpp
M  +3    -0    plugins/color/lcms2engine/colorspaces/lab_u16/LabColorSpace.h
M  +88   -0    plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.cpp
M  +3    -0    plugins/color/lcms2engine/colorspaces/lab_u8/LabU8ColorSpace.h

https://invent.kde.org/kde/krita/commit/effe8431cdb0c08618ddce879740f7f6abd1e9e3