forked from akkana/scripts
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxcfprobe.py
More file actions
executable file
·87 lines (65 loc) · 2.73 KB
/
xcfprobe.py
File metadata and controls
executable file
·87 lines (65 loc) · 2.73 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
#!/usr/bin/env python3
# This is a simple script that prints out the layers in a GIMP XCF file.
# Started from
# https://www.gimp-forum.net/Thread-List-layers-without-loading-image?pid=21911#pid21911
# then expanded after looking at the GIMP XCF code:
# https://gitlab.gnome.org/GNOME/gimp/-/blob/gimp-2-10/app/xcf/xcf-load.c#L1147
# https://gitlab.gnome.org/GNOME/gimp/-/blob/gimp-2-10/app/xcf/xcf-private.h
# which you'll need if you want to expand this beyond just layer names
# and visibility.
# The XCF spec is at
# https://gitlab.gnome.org/GNOME/gimp/-/blob/gimp-2-10/devel-docs/xcf.txt
#
# This is a simple demo that only works with some XCF versions.
import sys
# The layer property types needed to show visibility and which layer is active:
PROP_END = 0
PROP_ACTIVE_LAYER = 2
PROP_VISIBLE = 8
def probe_xcf(filename):
# open the file in readonly binary mode
with open(filename, 'rb') as f:
print("\n===", filename)
# go to the 30th byte
f.seek(30, 0)
# read image 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 == 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)
namelen = int.from_bytes(f.read(4), "big")
# namelen may include a null terminating character,
# (see line L226 of the XCF spec)
# which Python doesn't use, so strip it off:
name = f.read(namelen).decode("utf-8").replace('\0', '')
print('\nLayer "%s"' % name, end='')
while True:
prop_type = int.from_bytes(f.read(4), "big")
prop_size = int(int.from_bytes(f.read(4), "big") / 4)
# print(prop_type, "size", prop_size)
# The size says how many additional bytes need to be read.
# Read them now, saving only the last one.
for i in range(prop_size):
lastint = int.from_bytes(f.read(4), "big")
if prop_type == PROP_VISIBLE:
if lastint:
print(" Visible", end='')
else:
print(" Invisible", end='')
break
elif prop_type == PROP_ACTIVE_LAYER:
print(" Active", end='')
f.seek(saved_pos, 0)
print()
if __name__ == "__main__":
for f in sys.argv[1:]:
probe_xcf(f)