Gimp 3.0 Python plugin noob needs help

Initially I thought this is going to be a minor task and maybe could have been done with a macro but since Gimp doesn’t really have something like macros I asked ChatGPT, it proposed to implement it in a Python plugin for Gimp 3.0. This then spiraled down into a 3 days back and forth process with ChatGPT, which I now want to break out of.

With the helpf of ChatGPT I already got pretty far turning this into a Python plugin but now I’m stuck.

The plugin is supposed to take a 128x128 image and offset its rows of 128x16 alternatingly to the right side and basically turn:

row1
row2
row3
row4
row5
row6
row7
row8

into

row1,row2
row3.row4
row5,row6
row7,row8

This is the code:

#!/usr/bin/env python3

import gi
gi.require_version('Gimp', '3.0')
from gi.repository import Gimp
gi.require_version('Gegl', '0.4')
from gi.repository import Gegl
from gi.repository import GObject
from gi.repository import GLib
from gi.repository import Gio
import sys

class RearrangeTileLayout(Gimp.PlugIn):

	def do_query_procedures(self):
		return ['python-fu-rearrange-tile-layout']

	def do_create_procedure(self, name):
		if name == 'python-fu-rearrange-tile-layout':
			procedure = Gimp.Procedure.new(
				self,
				name,
				Gimp.PDBProcType.PLUGIN,
				self.rearrange_tile_layout,
				None,
				None
			)

			procedure.set_menu_label("Rearrange Tile Layout (128×128 → 256×64)")
			procedure.set_documentation(
				"Rearranges 128x16 tile rows from a 128x128 image into a 256x64 layout",
				"Converts 8 rows of 128×16 into a 2-column, 4-row 256×64 layout",
				name
			)
			procedure.set_attribution(
				"Your Name",
				"Your Name",
				"2025"
			)
			procedure.add_menu_path("<Image>/Filters/Custom")
			procedure.add_enum_argument("run-mode", "Run mode", "How the plugin was invoked", Gimp.RunMode, Gimp.RunMode.INTERACTIVE, GObject.ParamFlags.READWRITE)
			procedure.add_image_argument("image", "Image", "The image to process", True, GObject.ParamFlags.READWRITE)
			procedure.add_drawable_argument("drawable", "Drawable", "The drawable (layer) to process", True, GObject.ParamFlags.READWRITE)

			return procedure
		
	def rearrange_tile_layout(self, procedure, run_mode, *args):
		image = args[0]
		drawable = args[1]
		return self.do_run(procedure, run_mode, image, drawable, args, None)
	
	def do_run(self, procedure, run_mode, image, drawable, args, run_data):
		# Original buffer (read from)
		src_buffer = drawable.get_buffer()
		src_format = drawable.get_format()

		# Create new image and layer
		new_image = Gimp.Image.new(256, 64, image.get_base_type())
		new_layer = Gimp.Layer.new(
			new_image,
			"Rearranged",
			256,
			64,
			src_format,
			100,
			Gimp.LayerMode.NORMAL
		)
		new_image.insert_layer(new_layer, None, -1)

		# Destination buffer (write to)
		dest_buffer = new_layer.get_buffer()

		# Rearranging loop
		for i in range(4):
			y1 = i * 32       # source row 1 (0, 32, 64, 96)
			y2 = y1 + 16       # source row 2
			dest_y = i * 16    # destination y (0, 16, 32, 48)

			# Copy row 1 to left column (x=0)
			pixels1 = src_buffer.get(Gegl.Rectangle(0, y1, 128, 16))
			dest_buffer.set(Gegl.Rectangle(0, dest_y, 128, 16), pixels1)

			# Copy row 2 to right column (x=128)
			pixels2 = src_buffer.get(Gegl.Rectangle(0, y2, 128, 16))
			dest_buffer.set(Gegl.Rectangle(128, dest_y, 128, 16), pixels2)

		# Display result
		Gimp.Display.new(new_image)
		return procedure.new_return_values(Gimp.PDBStatusType.SUCCESS, GLib.Error())

Gimp.main(RearrangeTileLayout.__gtype__, sys.argv)

I start Gimp with

flatpak run org.gimp.GIMP --verbose

When I run the plugin inside gimp, in the terminal I get the error message

Traceback (most recent call last):
  File "/home/foo/.config/GIMP/3.0/plug-ins/rearrange_tile_layout/rearrange_tile_layout.py", line 52, in rearrange_tile_layout
    return self.do_run(procedure, run_mode, image, drawable, args, None)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/home/foo/.config/GIMP/3.0/plug-ins/rearrange_tile_layout/rearrange_tile_layout.py", line 56, in do_run
    src_buffer = drawable.get_buffer()
                 ^^^^^^^^^^^^^^^^^^^
AttributeError: 'NoneType' object has no attribute 'get_buffer'

Since this is the result of about 3 days ChatGPTing there might be a couple of issues with the script but I’m a complete noob in Gimp plugin development and have no idea how get this done.
But it feels as if this is too close to just discard it by now.

Any ideas how to fix this?

This topic was automatically closed 45 days after the last reply. New replies are no longer allowed.