Bug 432226

Summary: Calling setVisible() on a node's color channels does not behave as expected.
Product: [Applications] krita Reporter: chris.venter
Component: ScriptingAssignee: Krita Bugs <krita-bugs-null>
Status: RESOLVED FIXED    
Severity: minor    
Priority: NOR    
Version: 4.4.2   
Target Milestone: ---   
Platform: macOS (DMG)   
OS: macOS   
Latest Commit: Version Fixed In:
Sentry Crash Report:

Description chris.venter 2021-01-28 04:55:35 UTC
SUMMARY

The python Channel.setVisible() scripting call does not behave as expected.
Rather than individually addressing the specified channel's visibility, it affects all other channels' visibilities too.

STEPS TO REPRODUCE
1. Start Krita
2. Create a new blank document
3. Open the Tools->Scripts->Scripter
4. Run the following script in the scripter:

    from krita import *
    activeView = Krita.instance().activeWindow().activeView()
    activeDocument = activeView.document()
    activeNode = activeDocument.activeNode()
    for i in range(4):
        activeNode.channels()[i].setVisible(False)

5. Open the layer's properties dialog
6. Observe the active channel status

OBSERVED RESULT

All three color channels are active (ticked), only the alpha channel is inactive (unticked)

EXPECTED RESULT

All four channels should be inactive (unticked)


SOFTWARE/OS VERSIONS
Windows: Not tested
macOS: Catalina 10.15.6: Tested, bug is always reproducible
Linux/KDE Plasma: Not tested
(available in About System)
KDE Plasma Version: NA
KDE Frameworks Version: NA
Qt Version: NA

ADDITIONAL INFORMATION

Further testing shows that whenever a setVisible(X) call is made on a channel, all other channel visibilities are reset to true,
and only the last channel's visibility is correctly set.
Comment 1 chris.venter 2021-01-28 05:02:09 UTC
Proposed cause of bug:

The code in the setVisible method in libs/libKis/Channel.cpp looks as follows:

    void Channel::setVisible(bool value)
    {
        if (!d->node || !d->channel) return;
        if (!d->node->inherits("KisLayer")) return;

        for (uint i = 0; i < d->node->colorSpace()->channelCount(); ++i) {
            if (d->node->colorSpace()->channels()[i] == d->channel) {
                QBitArray flags = d->node->colorSpace()->channelFlags(true, true);
                flags.setBit(i, value);
                KisLayerSP layer = qobject_cast<KisLayer*>(d->node.data());
                layer->setChannelFlags(flags);
                break;
            }
        }

    }

From a look into the call

    QBitArray flags = d->node->colorSpace()->channelFlags(true, true);

it appears that this does not return the current status (active/inactive) of the layer's channels, rather it simply returns the "kind" of each channel in the colorspace, ie. whether it is a color channel or an alpha channel.

Rather, the flags should be fetched using

    QBitArray flags = layer->channelFlags();


Modifying the code in setVisible() to read

     void Channel::setVisible(bool value)
     {
         if (!d->node || !d->channel) return;
         if (!d->node->inherits("KisLayer")) return;
 
    +    KisLayerSP layer = qobject_cast<KisLayer*>(d->node.data());
    +    QBitArray flags = layer->channelFlags();
    +    if (flags.isEmpty()) {
    +        flags.fill(1, d->node->colorSpace()->channelCount());
    +    }
    +
         for (uint i = 0; i < d->node->colorSpace()->channelCount(); ++i) {
             if (d->node->colorSpace()->channels()[i] == d->channel) {
    -            QBitArray flags = d->node->colorSpace()->channelFlags(true, true);
                 flags.setBit(i, value);
    -            KisLayerSP layer = qobject_cast<KisLayer*>(d->node.data());
                 layer->setChannelFlags(flags);
                 break;
             }
         }
 
     }

has the desired outcome of *only* affecting the channel in question.
The python code in the original bug post now works as intended.
Comment 2 Halla Rempt 2021-01-28 13:22:37 UTC
Git commit 74f77fc01cefed9261b59cc827927f11e36b2aae by Halla Rempt, on behalf of Chris Venter.
Committed on 28/01/2021 at 13:22.
Pushed by rempt into branch 'master'.

Use layer->channelFlags in libkis Channel.cpp to correctly retrieve the current channel visibility

M  +6    -2    libs/libkis/Channel.cpp

https://invent.kde.org/graphics/krita/commit/74f77fc01cefed9261b59cc827927f11e36b2aae
Comment 3 Halla Rempt 2021-01-28 13:24:32 UTC
Git commit 1d22acfd3cacb3ee7717dc4958295aeba0cfe09c by Halla Rempt, on behalf of Chris Venter.
Committed on 28/01/2021 at 13:24.
Pushed by rempt into branch 'krita/4.3'.

Use layer->channelFlags in libkis Channel.cpp to correctly retrieve the current channel visibility
(cherry picked from commit 74f77fc01cefed9261b59cc827927f11e36b2aae)

M  +6    -2    libs/libkis/Channel.cpp

https://invent.kde.org/graphics/krita/commit/1d22acfd3cacb3ee7717dc4958295aeba0cfe09c