Bug 400353 - All channels pixelData is Blue channel
Summary: All channels pixelData is Blue channel
Status: RESOLVED FIXED
Alias: None
Product: krita
Classification: Applications
Component: Scripting (show other bugs)
Version: 4.1.5
Platform: Microsoft Windows Microsoft Windows
: NOR normal
Target Milestone: ---
Assignee: Halla Rempt
URL:
Keywords: triaged
Depends on:
Blocks:
 
Reported: 2018-10-26 23:38 UTC by Bob
Modified: 2018-11-20 08:57 UTC (History)
1 user (show)

See Also:
Latest Commit:
Version Fixed In:
Sentry Crash Report:


Attachments
Copying blue channel from this image (8.57 KB, image/png)
2018-11-08 05:38 UTC, Bob
Details

Note You need to log in before you can comment on or make changes to this bug.
Description Bob 2018-10-26 23:38:37 UTC
Can only read and write to Blue channel from Node::channels() list, no matter which channel is accessed (Channel::name() works correctly however).


STEPS TO REPRODUCE
1. Create new document (something small, say 2x2 pixels)
2. Fill with yellow (255, 255, 0)
3. Run the following script:

from krita import *
from PyQt5.QtCore import QByteArray, QRect

doc = Krita.instance().activeDocument()
layers = doc.rootNode().childNodes()
channels = layers[0].channels()

greenChan = channels[1]
print(greenChan.name()) # Prints 'Green'
rect = greenChan.bounds()

# Print out 1
for chan in channels:
    print("Channel: " + chan.name())
    px = chan.pixelData(rect)
    print(px)
    
val = int(128)
pxData = greenChan.pixelData(rect)

pxData.fill(val.to_bytes(1, byteorder='little'))
greenChan.setPixelData(pxData, rect)

# Print out 2
for chan in channels:
    print("Channel: " + chan.name())
    px = chan.pixelData(rect)
    print(px)
doc.refreshProjection()

OBSERVED RESULT
Print out 1 in above script prints all \x00s for all channels
Print out 2 in above script prints all \x80s for all channels
Image is pale yellow (255, 255, 128)

EXPECTED RESULT
Print out 1 should print \x00 for Blue channel and \xFF for other channels
Print out 2 should print \x00 for Blue, \x80 for Green and \xFF for Red/Alpha
Image should be orange (255, 128, 0)

SOFTWARE VERSIONS
(available in About System)
Krita
  Version: 4.1.5

Qt
  Version (compiled): 5.9.3
  Version (loaded): 5.9.3

OS Information
  Build ABI: x86_64-little_endian-llp64
  Build CPU: x86_64
  CPU: x86_64
  Kernel Type: winnt
  Kernel Version: 6.1.7601
  Pretty Productname: Windows 7 SP 1 (6.1)
  Product Type: windows
  Product Version: 7sp1

OpenGL Info
  **OpenGL not initialized**

ADDITIONAL INFORMATION
Same behaviour occurs in Krita 4.1.3.
Same behaviour occurs no matter which channel is accessed
Comment 1 wolthera 2018-10-27 16:25:27 UTC
Yes, this is caused by the following code in Channel.cpp ln 163:

stream << (quint8) *srcIt.rawDataConst();

Basically it is taking the pixel data, which is a list of quint 8 and only returning the first channel. So for 8 and 16 int that is the blue channel, and for 16 and 32 float that is the red channel.

Similarly, setPixelData needs to be looked at as well, as it sets the whole pixel to the pixeldata value.

boud, I am assigning this to you because I am still kinda bad with bytearrays :D
Comment 2 Halla Rempt 2018-10-30 13:40:22 UTC
Git commit e039f03926694fbca5efd75b76c71af5dfaefadf by Boudewijn Rempt.
Committed on 30/10/2018 at 13:39.
Pushed by rempt into branch 'master'.

Fix reading and writing Channels from Python

M  +8    -8    libs/libkis/Channel.cpp

https://commits.kde.org/krita/e039f03926694fbca5efd75b76c71af5dfaefadf
Comment 3 Halla Rempt 2018-10-30 13:52:59 UTC
Git commit 96977605adddf0e7a91a07a0d0dfc0c0224d857e by Boudewijn Rempt.
Committed on 30/10/2018 at 13:52.
Pushed by rempt into branch 'master'.

Add a unittest for the channel conversion

M  +24   -1    libs/libkis/tests/TestChannel.cpp
M  +1    -0    libs/libkis/tests/TestChannel.h

https://commits.kde.org/krita/96977605adddf0e7a91a07a0d0dfc0c0224d857e
Comment 4 Bob 2018-11-08 05:36:56 UTC
I've downloaded the nightly build that contains the above commits, and while it works for the provided example, it fails on others, especially on straight copying one channel to another. Channel pixelData now appears to be four times longer than needed (A 2x2 image will now return a QByteArray with 16 bytes rather than 4). 

Channel data for non-blue channels seems to be offsets of blue channel as well: A 2x2 image will print out (for each channel)
Blue: b'\x00\x00\x00\xYY\x00\x00\x00\xYY\x00\x00\x00\xYY\x00\x00\x00\xYY'
Green: b'\x00\x00\x00\xYY+1\x00\x00\x00\xYY+1\x00\x00\x00\xYY+1\x00\x00\x00\xYY+1'
Red: b'\x00\x00\x00\xYY+2\x00\x00\x00\xYY+2\x00\x00\x00\xYY+2\x00\x00\x00\xYY+2'
Alpha: b'\x00\x00\x00\xYY+3\x00\x00\x00\xYY+3\x00\x00\x00\xYY+3\x00\x00\x00\xYY+3'
where YY+Z can overflow into the byte before it. e.g., If the image has xFF blue, the alpha channel will be four copies of \x00\x00\x01\x02

This overflowing also affects the filling. If we have a white 2x2 image, and just simply copy the blue channel to the red with
rect = QRect(0,0,doc.width(),doc.height())
channels[2].setPixelData(channels[0].pixelData(rect), rect)
the image should stay white but becomes three teal pixels and a white pixel.

It also appears can't retrieve channel data for any channel but blue.

Also, while I believe it's just a manifestation of the above overflowing, copying the blue channel into another channel on a larger image causes an odd stretching and wrapping effect (see attachments)
Comment 5 Bob 2018-11-08 05:38:43 UTC
Created attachment 116176 [details]
Copying blue channel from this image
Comment 6 Bob 2018-11-08 05:49:47 UTC
I don't seem to be able to upload a picture (Keeping getting a server error), so here is an imgur link https://i.imgur.com/Q5a5mg7.png
Comment 7 Halla Rempt 2018-11-20 08:57:24 UTC
Git commit f8d86fc35bdf94ed7a78b023125e9f1e13f1b990 by Boudewijn Rempt.
Committed on 20/11/2018 at 08:25.
Pushed by rempt into branch 'krita/4.1'.

Fix reading and writing Channels from Python

M  +8    -8    libs/libkis/Channel.cpp

https://commits.kde.org/krita/f8d86fc35bdf94ed7a78b023125e9f1e13f1b990