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
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
|
# File 'lib/ruby_spriter/cell_cleanup_gimp_script.rb', line 3
def self.generate_cleanup_script(input_path, output_path, dominant_colors)
input_normalized = Utils::PathHelper.normalize_for_python(input_path)
output_normalized = Utils::PathHelper.normalize_for_python(output_path)
colors_py = dominant_colors.map do |color_str|
match = color_str.match(/rgb\((\d+),(\d+),(\d+)\)/)
r = match[1].to_i
g = match[2].to_i
b = match[3].to_i
"{'r': #{r}, 'g': #{g}, 'b': #{b}}"
end.join(', ')
<<~PYTHON
import sys
import gc
from gi.repository import Gimp, Gio, Gegl
img = None
layer = None
try:
print("Loading image...")
img = Gimp.file_load(Gimp.RunMode.NONINTERACTIVE,
Gio.File.new_for_path(r'#{input_normalized}'))
w = img.get_width()
h = img.get_height()
print(f"Image size: {w}x{h}")
layers = img.get_layers()
if not layers or len(layers) == 0:
raise Exception("No layers found")
layer = layers[0]
# Add alpha channel if needed
if not layer.has_alpha():
layer.add_alpha()
print("Added alpha channel")
pdb = Gimp.get_pdb()
# Select dominant colors for removal
print("Selecting dominant colors...")
select_proc = pdb.lookup_procedure('gimp-image-select-color')
if not select_proc:
raise Exception("Could not find gimp-image-select-color procedure")
for i, color_dict in enumerate([#{colors_py}]):
r, g, b = color_dict['r'], color_dict['g'], color_dict['b']
print(f" Selecting color {i+1}: RGB({r}, {g}, {b})")
# Create Gegl.Color from normalized RGB values
color = Gegl.Color.new(f"rgb({r/255.0}, {g/255.0}, {b/255.0})")
config = select_proc.create_config()
config.set_property('image', img)
# Use REPLACE for first color, ADD for subsequent colors
if i == 0:
config.set_property('operation', Gimp.ChannelOps.REPLACE)
else:
config.set_property('operation', Gimp.ChannelOps.ADD)
config.set_property('drawable', layer)
config.set_property('color', color)
select_proc.run(config)
print("Colors selected")
# Delete selection (make transparent)
print("Removing selected colors...")
edit_clear = pdb.lookup_procedure('gimp-drawable-edit-clear')
if edit_clear:
config = edit_clear.create_config()
config.set_property('drawable', layer)
edit_clear.run(config)
print("Selection cleared")
# Deselect
print("Deselecting...")
select_none = pdb.lookup_procedure('gimp-selection-none')
if select_none:
config = select_none.create_config()
config.set_property('image', img)
select_none.run(config)
# Export
print("Exporting...")
export_proc = pdb.lookup_procedure('file-png-export')
if export_proc:
config = export_proc.create_config()
config.set_property('image', img)
config.set_property('file', Gio.File.new_for_path(r'#{output_normalized}'))
export_proc.run(config)
print("SUCCESS - Cell cleanup complete!")
else:
raise Exception("Could not find file-png-export procedure")
except Exception as e:
print(f"ERROR: {e}")
import traceback
traceback.print_exc()
sys.exit(1)
finally:
# Explicit cleanup to minimize GEGL warnings
try:
if layer is not None:
layer = None
if img is not None:
gc.collect() # Force garbage collection
img.delete()
img = None
gc.collect() # Force again after deletion
except Exception as cleanup_error:
print(f"Cleanup warning: {cleanup_error}")
pass
PYTHON
end
|