Module: RubySpriter::CellCleanupGimpScript

Defined in:
lib/ruby_spriter/cell_cleanup_gimp_script.rb

Class Method Summary collapse

Class Method Details

.generate_cleanup_script(input_path, output_path, dominant_colors) ⇒ Object



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)
  # Normalize paths for Python
  input_normalized = Utils::PathHelper.normalize_for_python(input_path)
  output_normalized = Utils::PathHelper.normalize_for_python(output_path)

  # Convert RGB strings to Python color strings
  colors_py = dominant_colors.map do |color_str|
    # Parse "rgb(255,0,0)" format
    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