This forum has been archived. All content is frozen. Please use KDE Discuss instead.

Python: Node.mergeDown() problems.

Tags: None
(comma "," separated)
saedjubarin
Registered Member
Posts
58
Karma
0

Python: Node.mergeDown() problems.

Mon Mar 18, 2019 12:22 pm
I have 3 layers and I need to merge them down in the following order to reproduce wanted effect.

First step: (layers are listed as in layer docker, A is the topmost layer)
A <--- I want to merge this with B
B
C

Second step:
B <--- I want to merge this with C
C

Resulting in C having all of the merged information.

Let's say I have made the layers with the following piece of code:
Code: Select all
app = Krita.instance()
doc = app.activeDocument()
active = doc.activeNode
root = doc.rootNode()
add = root.addChildNode
C = doc.activeNode()
C.setName("C")

add(C.duplicate(), C)
B = active()
B.setName("B")

add(C.duplicate, B)
A = active()
A.setName("A")

And now I want to merge them down together.

So I start with:
Code: Select all
A.mergeDown()

But when I do:
Code: Select all
B.mergeDown()

Nothing happens. It seems like A and B have gone to heaven and I have a new fellow here that looks just like B, but when I do:
Code: Select all
print(active().name())

It claims to be A

What's the intended (or working) procedure to merging down the layers?

If you put this in ' Tools > Scripter ' it should reproduce the situation (AKA here's the full code):
Code: Select all
app = Krita.instance()
doc = app.activeDocument()
active = doc.activeNode
root = doc.rootNode()
add = root.addChildNode
C = doc.activeNode()
C.setName("C")

add(C.duplicate(), C)
B = active()
B.setName("B")

add(C.duplicate(), B)
A = active()
A.setName("A")

A.mergeDown()
B.mergeDown()
print(active().name())
saedjubarin
Registered Member
Posts
58
Karma
0
Further research highlights my trouble.
Code: Select all
app = Krita.instance()
doc = app.activeDocument()
active = doc.activeNode
set_active = doc.setActiveNode
root = doc.rootNode()
add = root.addChildNode
C = doc.activeNode()
C.setName("C")

add(C.duplicate(), C)
B = active()
B.setName("B")

add(C.duplicate(), B)
A = active()
A.setName("A")

D = A.mergeDown()

# Node.mergeDown() indeed returns a Node
print(D)

# But it has no name.
print("D name is",D.name())

# I can merge it down
D.mergeDown()

# ... set a name
D.setName("D")

# and add it to the rood node just above C
add(D,C)

# but it doesn't save the name
print("D name is still",D.name())

# and it doesn't get attached anywhere.
# while A and B are attached to an unnamed node,
# D isn't attached to anything.
for node in [A, B, C, D]:
    print(node.name(), node == active(), node.parentNode().name())

Outputs:
Code: Select all
======================================
<PyKrita.krita.Node object at 0x7fcb081285e8>
D name is
D name is still
A True
B False
C False root

**********************
AttributeError: 'NoneType' object has no attribute 'name'

In file: /home/saed/krita/test.py
In function: <module> at line: 87. Line with error:
print(node.name(), node == active(), node.parentNode().name())
**********************
saedjubarin
Registered Member
Posts
58
Karma
0
Further research elaborates the problem. Notice how A and B in the example above don't have a named parent node. Well look at this: it seems to be in the same address than the root node. How is that happening?
Code: Select all
app = Krita.instance()
doc = app.activeDocument()
top = doc.topLevelNodes
active = doc.activeNode
set_active = doc.setActiveNode
root = doc.rootNode()
add = root.addChildNode

# I start with the topmost node active:
set_active(top()[-1])

# Let's call it C
C = doc.activeNode()
C.setName("C")

# For easier testing you can set it to 50% opacity and move
# the layers around to see if anything has actually merged.
C.setOpacity(128)

# Let's duplicate it to make B and A
add(C.duplicate(), C)
B = active()
B.setName("B")

add(C.duplicate(), B)
A = active()
A.setName("A")

# and start merging
D = A.mergeDown()

# Node.mergeDown() indeed returns a Node
print(D)

# But it has no name.
print("D name is",D.name())

# I can merge it down
D.mergeDown()

# ... set a name
D.setName("D")

# and add it to the rood node just above C
add(D,C)

# but it doesn't save the name
print("D name is still",D.name())

# and it doesn't get attached anywhere.
# while A and B are attached to an unnamed node,
# D isn't attached to anything.
for node in [A, B, C, D]:
    print(node.name(),"== active()?", node == active(), "|| Is child of:", node.parentNode())

# While you would think that the topmost layer in Layers Docker
# is the active node, just because it seems to be selected in
# Krita, that's not the case.
print(active().name(), "==", top()[-1].name(), "?", active() == top()[-1])

# At this point I have B and C in Layers Docker visible, but if I
# move them around I notice B is just like C, not a merged version,
# just the original duplicate.

# So, Ok, no point in having A as the active node,
# since it's nowhere and at the root node at the same time.
# Let's test if B is the Krita.instance().activeDocument().topLevelNodes()[-1] like I assume.
print(top()[-1].name())

# Ok, it's B, but is it the same B?
print(B.name(), "==", top()[-1].name(), "?", B == top()[-1])

# Nope, not the same B. So let's make B active.
set_active(B)

# And try this.
E = B.mergeDown()

# But nothing happens. Well what if I just make the topmost node active
# and merge that?
set_active(top()[-1])
#F = active().mergeDown() # But you can't, Krita would crash.

# So let's assign it first.
#F = active() # No, still crashing!

# I can do this though!
top()[-1].mergeDown()


Outputs:

Code: Select all
<PyKrita.krita.Node object at 0x7f6c103048b8>
D name is
D name is still
A == active()? True || Is child of: <PyKrita.krita.Node object at 0x7f6c103049d8>
B == active()? False || Is child of: <PyKrita.krita.Node object at 0x7f6c103049d8>
C == active()? False || Is child of: <PyKrita.krita.Node object at 0x7f6c103049d8>
 == active()? False || Is child of: None
A == B ? False
B
B == B ? False


Somehow it almost looks like I merged the layers. It's still 50% opaque, which is not the desired effect. It looks like I merged pixeldata instead of the layers. But while testing out this thing, I noticed that if I select two layers from Layers Docker, and use "Merge with layer below" I end up with 100% opaque layer with transparency saved in the pixeldata. That's how I thought merge always works. But if I select only the top layer and use the exact same "Merge with layer below", it does the same thing as this little snippet, it merges the pixeldata and keeps the layer data intact. I'd really love an explanation.

Summary of 'so far': I've managed to merge the layers, but not the way I need to.
saedjubarin
Registered Member
Posts
58
Karma
0
Code: Select all
Krita.instance().action('duplicatelayer').trigger()
Krita.instance().activeDocument().waitForDone()

Krita.instance().action('duplicatelayer').trigger()
Krita.instance().activeDocument().waitForDone()

Krita.instance().action('select_visible_layers').trigger()
Krita.instance().activeDocument().waitForDone()

Krita.instance().action('merge_layer').trigger()
Krita.instance().activeDocument().refreshProjection()


this manages to duplicate the layers and then merge them together, but I will have to implement this into my script to see if it actually manages to do the job...

Last edited by saedjubarin on Mon Mar 18, 2019 7:17 pm, edited 1 time in total.
User avatar
TheraHedwig
KDE Developer
Posts
1794
Karma
10
OS
saedjubarin
Registered Member
Posts
58
Karma
0
Would be nice to be able to merge multiple nodes in one go with just a list or something. Like Krita.instance().activeDocument().mergeNodes([node, node, node, ...]) and it would just merge them from top to bottom as if they were adjacent, resulting in the bottom-most node having the merged result.


Bookmarks



Who is online

Registered users: Bing [Bot], claydoh, Evergrowing, Google [Bot], rblackwell