Switch to full style
Post all Gimp scripts and script writing questions here
Post a reply

Change all layer modes from Legacy to Default

Tue Jul 23, 2019 11:31 pm

Hey,

Disclaimer: You can say that I have OCD, but I don't care. I have a situation where I have XCF files that are still using the legacy layer modes, some even have mixed Default/Legacy.

I am looking for a quick and dirty way in Script-Fu to change all existing layers in a file/image from Legacy Normal to Default Normal blend mode.

So far, I have found out that gimp-layer-set-mode is the command that I probably want. I have done programming before, and I know the concepts of it, and I have also seen how to do loops in Scheme, but the big issue is that I have no idea how to actually get the layer ID from existing layers. And I also don't know how I would stop the loop on the last layer, and start it on the first. I would have to imagine using a loop that checks the condition of gimp-item-is-layer until it is false, probably.

It seems like it is easy to do that once you create a new layer, but I can't find any info on looping through existing layer IDs.

So that's basically all I want to do. If it can work as a batch command (on a batch of files) that would be even better! Right now, I am okay using a Script-Fu command on the currently open file.

Perhaps something smarter, and something that more people would want, is a way to change all legacy layer modes to default modes, no matter what the layer effect is. In other words, it would match each legacy layer effect to the same effect in the default mode. That sounds pretty useful.

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 2:15 am

Why script-fu? In the Python console:
Code:
image=gimp.image_list()[0] # assumes only one images opened in Gimp
for l in image.layers: l.mode=LAYER_MODE_NORMAL

(strike [Enter] twice)

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 2:58 am

Welcome to gimpchat RubisDrake. I like your honesty. Looks like those legacy layers have been sorted out by ofnuts.

Image

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 3:47 am

RubisDrake wrote:I have no idea how to actually get the layer ID from existing layers.


AFAIK in script-fu you don't deal with objects. All you have are their ids, and all the API really takes (and returns) are these IDs. So gimp-image-get-layers returns an array of layer IDs, and that is all you need to interact with these layers. The Python support hides this a bit by building Python objects that contain that ID, and have attribute access methods which under the hoods are using the PDB calls to get/set the attributes: for instance image.layers() is a shortcut to pdb.gimp_image_get_layers(image). In the Python API you usually pass these objects instead of IDs.

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 4:43 am

ofnuts wrote:
RubisDrake wrote:I have no idea how to actually get the layer ID from existing layers.


AFAIK in script-fu you don't deal with objects. All you have are their ids, and all the API really takes (and returns) are these IDs. So gimp-image-get-layers returns an array of layer IDs, and that is all you need to interact with these layers. The Python support hides this a bit by building Python objects that contain that ID, and have attribute access methods which under the hoods are using the PDB calls to get/set the attributes: for instance image.layers() is a shortcut to pdb.gimp_image_get_layers(image). In the Python API you usually pass these objects instead of IDs.


Man, I really have realized how difficult it is to (unsuccessfully) learn a new programming language like Scheme in a day, and take for granted how simple it is to do a loop in Python. I really hope they deprecate the Script-Fu implementation at some point, and just stick with Python-Fu. The fact that a simple indexed loop requires more than 3 lines of code is absolutely ridiculous. A Scheme script feels a lot more GIMP specific, but that can be either a good thing, or a bad thing.

I'll just install "gimp-python" since that's not installed by default with my Debian system, and I'll roll with that solution for now.

Thank you very much!

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 5:14 am

Actually, there is a problem with it. It doesn't support layers in layer groups. Hmm....

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 5:51 am

There is a python plugin that does similar to your requirements here:

https://gimplearn.net/viewtopic.php/GIM ... f=3&t=1649

Might be worth looking at the code.

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 7:10 am

RubisDrake wrote:Actually, there is a problem with it. It doesn't support layers in layer groups. Hmm....


A recursive function that handles groups:
Code:
def process(parent):
    for layerOrGroup in enumerate(parent.layers):
        layerOrGroup.mode=LAYER_MODE_NORMAL
        if isinstance(layerOrGroup,gimp.GroupLayer):
            process(layerOrGroup)


That you start with "process(image)".

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 3:49 pm

Hey, thanks a lot for your help, ofnuts!

I figured out that it worked without enumerate(), probably because layerOrGroup.mode is expecting a tuple instead of an enum object? I'm no Python wizard, but maybe.

The error was this:
Code:
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 3, in process
AttributeError: 'tuple' object has no attribute 'mode'


Anyway, final solution here that worked for me, thanks to ofnuts:

Code:
def process(parent):
    for layerOrGroup in parent.layers:
        layerOrGroup.mode=LAYER_MODE_NORMAL
        if isinstance(layerOrGroup,gimp.GroupLayer):
            process(layerOrGroup)

image=gimp.image_list()[0]
process(image)


Again, you could probably loop through gimp.image_list()[n] using index n, but this works great for now!

Re: Change all layer modes from Legacy to Default

Wed Jul 24, 2019 7:07 pm

RubisDrake wrote:Hey, thanks a lot for your help, ofnuts!

I figured out that it worked without enumerate(), probably because layerOrGroup.mode is expecting a tuple instead of an enum object? I'm no Python wizard, but maybe.

The error was this:
Code:
Traceback (most recent call last):
  File "<input>", line 1, in <module>
  File "<input>", line 3, in process
AttributeError: 'tuple' object has no attribute 'mode'


Anyway, final solution here that worked for me, thanks to ofnuts:

Code:
def process(parent):
    for layerOrGroup in parent.layers:
        layerOrGroup.mode=LAYER_MODE_NORMAL
        if isinstance(layerOrGroup,gimp.GroupLayer):
            process(layerOrGroup)

image=gimp.image_list()[0]
process(image)


Again, you could probably loop through gimp.image_list()[n] using index n, but this works great for now!


Yes, sorry I left the enumerate in from the code I copied.

This is pythin you don't need to iterate list using the index, to iterate the images you just do:

Code:
for image in gimp.image_list():
    .. do whatever


and in fact if you need the image index, you use enumerate():

Code:
for index,image in enumerate(gimp.image_list()):
    .. do whatever with index


... because in Python accessing an arbitrary element in a list (list[n]) is more expensive than from an element to the next (in python, arrays are simulated with lists when in other languages, lists are implemented with arrays under the hood). enumerate() also lets you set a an origin, so you can enumerate from 0 or from 1 (or from 58...).
Post a reply