Posts: 61
Threads: 16
Joined: Apr 2020
Reputation:
1
Operating system(s):
Gimp version: 2.10
Using python-fu, is there a way to list the layer names of an xcf file without loading the whole file?
Right now I list them like this:
Code:
image = pdb.gimp_file_load(some_filepath,same_filepath)
for l in image.layers :
print(l.name)
gimp.delete(image)
The problem is that I use it on many very heavy xcfs and the listing can take a few minutes, which I feel could be improved.
I can find the layer names in the gibberish of the xcf when I open it with a text editor (Atom) but don't see a recurring pattern around so not sure this can be exploited by a direct text search in the file.
Any chance of there being an efficient solution?
Posts: 65
Threads: 11
Joined: Nov 2020
Reputation:
3
Operating system(s):
- Windows Vista or 7, 8, 10 (64-bit)
Gimp version: 2.10
You could try using pdb.gimp_xcf_load(0, path, path) instead of file_load?
Example here: https://gist.github.com/rgl/8212019
- E
Posts: 6,365
Threads: 276
Joined: Oct 2016
Reputation:
565
Operating system(s):
Gimp version: 3.00RC1
(02-06-2021, 11:06 PM)eepjr24 Wrote: You could try using pdb.gimp_xcf_load(0, path, path) instead of file_load?
Example here: https://gist.github.com/rgl/8212019
- E
file_load() is a "thin" layer that tries to guess the type and most of the processing is with the actual loading,so there won't be much difference.
Posts: 6,365
Threads: 276
Joined: Oct 2016
Reputation:
565
Operating system(s):
Gimp version: 3.00RC1
(02-06-2021, 03:48 PM)ChameleonScales Wrote: Using python-fu, is there a way to list the layer names of an xcf file without loading the whole file?
Right now I list them like this:
Code:
image = pdb.gimp_file_load(some_filepath,same_filepath)
for l in image.layers :
print(l.name)
gimp.delete(image)
The problem is that I use it on many very heavy xcfs and the listing can take a few minutes, which I feel could be improved.
I can find the layer names in the gibberish of the xcf when I open it with a text editor (Atom) but don't see a recurring pattern around so not sure this can be exploited by a direct text search in the file.
Any chance of there being an efficient solution?
None I know of. And your code doesn't handle layer groups . Do you start a Gimp instance for each image or is it the same Gimp instance that processes them all?
Posts: 61
Threads: 16
Joined: Apr 2020
Reputation:
1
Operating system(s):
Gimp version: 2.10
02-07-2021, 03:05 PM
(This post was last modified: 02-07-2021, 04:24 PM by ChameleonScales.)
One instance (I process on average ~50 xcfs at once) but I was actually wondering how to multithread the process. Do you know if that's possible through python-fu?
Although, thinking of it this might be pointless because the files are on a dard drive, so multithreading this might just make the reading head go all over the place and not any faster.
About group layers, I don't handle them because for my use I don't need to, but it would be a good thing for when I publish the plug-in, thanks for pointing that out.
Posts: 149
Threads: 2
Joined: Mar 2019
Reputation:
56
Operating system(s):
Gimp version: 3.0
02-07-2021, 07:49 PM
(This post was last modified: 02-07-2021, 07:50 PM by tmanni.)
This quick done and dirty piece of python3 code should work...
Replace "test.xcf" by the path to your file and run it from a terminal
Code:
#!/usr/bin/env python3
if __name__ == "__main__":
filename = "test.xcf"
# open the file in readonly binary mode
with open(filename, 'rb') as f:
# go to the 30th bytes
f.seek(30, 0)
# read properties
while True:
prop_type = int.from_bytes(f.read(4), "big")
prop_size = int.from_bytes(f.read(4), "big")
f.read(prop_size)
if prop_type == 0: #PROP_END
break;
# read layers
while True:
next_layer_offset = int.from_bytes(f.read(8), "big")
if not next_layer_offset: #end of layers offsets
break;
saved_pos = f.tell()
f.seek(next_layer_offset + 12, 0)
tmp = int.from_bytes(f.read(4), "big")
name = f.read(tmp).decode("utf-8")
print(name)
f.seek(saved_pos, 0)
Posts: 61
Threads: 16
Joined: Apr 2020
Reputation:
1
Operating system(s):
Gimp version: 2.10
02-07-2021, 08:42 PM
(This post was last modified: 02-07-2021, 08:43 PM by ChameleonScales.)
Wow, that's intantaneous on a 2.2 GB xcf!
Reading your code it's clearly beyond my knowledge but I can certainly make use of it anyway, so thank you very much for your help.
Posts: 149
Threads: 2
Joined: Mar 2019
Reputation:
56
Operating system(s):
Gimp version: 3.0
02-08-2021, 12:29 AM
(This post was last modified: 02-08-2021, 12:31 AM by tmanni.)
The script I post is fast because it does not use the gimp api.
It simply open the xcf file and find relevant informations in it (the list of layers and its names in this case).
It would have the same speed even with a 200 GB xfc file...
If you describe IN DETAILS what you are exactly doing with your plugin, people here could suggest more appropriate solutions to improve/speed up your workflow.
Posts: 61
Threads: 16
Joined: Apr 2020
Reputation:
1
Operating system(s):
Gimp version: 2.10
02-08-2021, 03:24 AM
(This post was last modified: 02-08-2021, 03:32 AM by ChameleonScales.)
Sure, what my plug-in does is from a given root directory and with a given maximum search depth, it finds all the xcfs and lists them in a csv table where each row is an xcf and each column is one of its layers (except the first column which is the url of the xcf).
Additionally, each "layer cell" of the csv contains the visibility state of the layer (whether the eye is open or closed) by inserting an identifiable string at the start of the cell.
Right now it works by using the Gimp api and I've started making a GTK dialog to make your "super-fast" version work outside of Gimp with the same functionalities.
I actually forgot to mention that "visibility" part, sorry about that (*∩▂∩). So right now I'm missing that from your version.
If it even is possible, do you perhaps know how to do that? (º̩̩́⌣º̩̩̀ʃƪ)
Posts: 65
Threads: 11
Joined: Nov 2020
Reputation:
3
Operating system(s):
- Windows Vista or 7, 8, 10 (64-bit)
Gimp version: 2.10
(02-08-2021, 03:24 AM)ChameleonScales Wrote: Sure, what my plug-in does is from a given root directory and with a given maximum search depth, it finds all the xcfs and lists them in a csv table where each row is an xcf and each column is one of its layers (except the first column which is the url of the xcf).
Additionally, each "layer cell" of the csv contains the visibility state of the layer (whether the eye is open or closed) by inserting an identifiable string at the start of the cell.
Right now it works by using the Gimp api and I've started making a GTK dialog to make your "super-fast" version work outside of Gimp with the same functionalities.
I actually forgot to mention that "visibility" part, sorry about that (*∩▂∩). So right now I'm missing that from your version.
If it even is possible, do you perhaps know how to do that? (º̩̩́⌣º̩̩̀ʃƪ)
Consider my answer just a pointer in the right direction until tmanni or someone else who knows the xcf format can chime in. I think what you are looking for is:
PROP_VISIBLE (essential)
uint32 8 The type number for PROP_VISIBLE is 8
uint32 4 Four bytes of payload
uint32 b 1 if the layer/channel is visible; 0 if not
I pulled this from HERE, which is a partial XCF specification that will probably come in handy for the type of work you look to be doing. I only dabble in Python, so I'm not going to attempt to give a code example, but you are reading the layer name and the property list follows it immediately in the file:
string name The name of the layer
property-list Layer properties (details below)
That means from the name you should be able to seek N bytes forward in the file (where N is the sum of the bytes of the properties until the PROP_VISIBLE flag) and read / convert it (I think bitstring would be okay for this). Again, this is just to help you along in the mean time, I am no expert.
- E
|