Switch to full style
Post all Gimp scripts and script writing questions here
Post a reply

Difference between "Python-Fu" and "Python" plugin

Sun May 31, 2020 9:25 am

A year ago, when it came to writing GIMP plugins, I was a real "NEWBIE". In the meantime I have been working intensively on programming GIMP plugins with Python, C and C++. There is a lot of information on the Internet about GIMP, plugins and Python. These are so different and not always correct, so that a beginner easily loses interest to do plug-in programming. To prevent this from happening, I would like to help a little other newbies and beginners.

At the start of my plugin programming, I kept asking myself what is the difference between a Python-Fu and a "real" Python plugin. I would like to explain this below. By the way, the term "real Python plugin" does not come from me. I would rather say "Python-Fu" and "Python" plugin.

A "Python-Fu" plugin without GIMP functionality looks roughly as follows:
Code:
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
Purpose: Basic structure of a Python-Fu GIMP plugin.
Calling: <Image>/Filters/Shapes
Author:  Herbert Nemeczek
Version: 2020-05-10
"""

from gimpfu import *

##########################################################################################
# Plug-in class.
def plugin_main(fImage, fDrawable, fX1, fY1):
  return
   
##########################################################################################
# Registration of the Python-Fu plugin.
register(
  "HN_Gimp_Plugin_PythonFu",
  "Short description of the plugin.",
  "Detailed description of the plugin.",
  "Herbert Nemeczek (Herbert.Nemeczek@t-online.de)",
  "(c) Herbert Nemeczek",
  "2020-05-10",
  "<Image>/Filters/Shapes/HN: GIMP-Plugin (Python-Fu)...",
  "RGB*, GRAY*, INDEXED*",
  [ (PF_INT,    "x1",    "X-coordinate: x",    0),
    (PF_INT,    "y1",    "Y-coordinate: y",    0)
  ],
  [],
  plugin_main
)

main()
The "Python-Fu" plugin uses the "gimpfu" module, which greatly simplifies the writing of plugins. Instead of taking care of the entire user interaction, the "gimpfu" module does it for you. It offers a simple "register()" function, which registers your own plug-in and is called when necessary. "Gimpfu" also deals with the display of a user interface for editing the plugin parameters when the plugin is called up interactively. It also ensures that the ads are emptied upon completion.

A ("real") Python plugin without GIMP functionality roughly looks like this:
Code:
#!/usr/bin/python
# -*- coding: utf-8 -*-
"""
Purpose: Basic structure of a "real" Python GIMP plugin.
Calling:  <Image>/Filters/Shapes
Author:  Herbert Nemeczek
Version: 2020-05-10
"""

import gimp, gimpplugin
pdb = gimp.pdb
from gimpenums import *
#
import gimpui
import pygtk, gtk

##########################################################################################
# User interface class.
class winUserInterface(gtk.Window):
  #=======================================================================================
  # The constructor that creates the window.
  def __init__(self):
    #
    #-------------------------------------------------------------------------------------
    # Title, size, position, .. of the window.
    gtk.Window.__init__(self, gtk.WINDOW_TOPLEVEL)
    self.set_title('Example of a "real" Python GIMP plugin')
    self.winWidth = 500   ; self.winHeight = 300  # Definition of the minimum sizes
    self.set_default_size(self.winWidth, self.winHeight)
    self.set_position(gtk.WIN_POS_NONE)           # Also possible: gtk.WIN_POS_CENTER)
    self.set_border_width(10)
    self.set_resizable(True)
    #
    #-------------------------------------------------------------------------------------
    # Define container (table) for the widget elements.
    self.layTab = gtk.Table(rows=7, columns=3, homogeneous=True)
    self.layTab.set_border_width(5)
    self.layTab.set_col_spacings(10)
    self.layTab.set_row_spacings(10)
    self.add(self.layTab)
    #
    #-------------------------------------------------------------------------------------
    # Add button/key.
    self.okButton = gtk.Button("OK")
    self.okButton.set_relief(gtk.RELIEF_NORMAL)
    self.okButton.set_tooltip_text("Performs an activity and ends the plugin.")
    self.okButton.connect("clicked", self.winEvtExitClicked)
    #self.horBox.pack_start(self.okButton, True, True, 0)
    self.layTab.attach(self.okTaste, 1, 2, 6, 7, gtk.FILL | gtk.EXPAND, 0, 0, 0)
    #
    #-------------------------------------------------------------------------------------
    # Close the user interface with the X button.
    self.connect("destroy", self.winEvtExitClicked) 
  #
  #=======================================================================================
  # Method of displaying the window and staying in the event queue.
  def showInterface(self):
    self.show_all()    # Now display the window built in the constructor
    gtk.main()          # Event queue after displaying the main window
  #
  #=======================================================================================
  # Event in response to the key being pressed on "OK" or "X".
  def winEvtExitClicked(self, widget, data=None):
    gtk.main_quit()         # End of the event queue that started with "gtk.main()"

##########################################################################################
# Plugin class.
class plugin_main(gimpplugin.plugin):
  #
  #=======================================================================================
  # Usually you do not redefine the following three methods in your own plugin,
  # since these are already set appropriately in the upper class. But it works.
  def start(self) :
    gimp.main(self.init, self.quit, self.query, self._run)
  def init(self):
    pass
  def quit(self):
    pass
  #
  #=======================================================================================
  # Method "query(self)" is called when the plugin is recognized as new/changed.
  def query(self):
    pluginName = "HN_Gimp_Plugin_Python"
    gimp.install_procedure(
      pluginName,
      "Short description of the plugin.",
      "Detailed description of the plugin.",
      "Herbert Nemeczek (Herbert.Nemeczek@t-online.de)",
      "(c) Herbert Nemeczek",
      "2020-05-10",
      "HN: GIMP-Plugin (Python)...",
      "RGB*, GRAY*, INDEXED*",
      PLUGIN,
      [ ( # Run mode (32-bit Integer)
          PDB_INT32,        # A plugin can be started in the following modes:
          "run_mode",       #   RUN_INTERACTIVE (0), RUN_NONINTERACTIVE (1)
          "Run mode"        #   and RUN_WITH_LAST_VALS (2)
        ),
        ( # Picture/Image (Image ID)
          PDB_IMAGE,       # Every opened picture has a single active drawing area,
          "image",             # the "Drawable".
          "Input image"
        ),
        ( # Drawable (Drawable ID)
          PDB_DRAWABLE,  # A "Drawable" is a GIMP concept that contains layers,
          "drawable",          # but also various other objects such as channels,
          "Input drawable"  # layer masks and the selection mask.
        )
      ],
      []
    )
    gimp.menu_register(pluginName, "<Image>/Filters/Shapes")
  #
  #======================================================================================
  # The method "run(self)" realizes the actual plugin.
  def HN_Gimp_Plugin_Python(self, fRunMode, fImage, fDrawable):
    if (fRunMode == RUN_NONINTERACTIVE):
      return

    userInterface = winUserInterface()
    # GTK: Show surface and wait until "gtk_main_quit()" is called.
    userInterface.showInterface()
           
if (__name__ == '__main__'):
  plugin_main().start()
The "real" Python plugin uses the "gimpplugin" module to register and call up its own plugin. In my example I use the modules "gimpui", "pygtk" and "gtk" (PyGTK 2.0, see http://developer.gnome.org/pygtk/stable/) to build the user interface.
At first glance, you get the impression that everything is much more complicated. This may be the case initially, but the programmer has a lot more freedom in designing the surface.
I decided to use this variant.

For testing, creates the two plugins "HN-Gimp-Plugin-PythonFu.py" and "HN-Gimp-Plugin-Python.py" with the codes and copies them into the private "plug-ins" directory (under Windows "C:\Users\<user name>\AppData\Roaming\GIMP\2.10\plug-ins").
After starting GIMP and creating a new image with
File -> New...
you start both plugins one after the other using
Filters -> Shapes
Examines the content and functionality of the plugins. Especially look at the differences in the code.
If you call
Help -> Plug-in Browser
in GIMP, then type "HN" in the search field and select the displayed plugins one after the other, you should above all compare the TOP line in the right window of the plugin browser.

In the meantime, I have written my own module with many methods that make writing a Python and C++ plugin much easier.
If you wanted to examine a fully programmed "real" Python plugin, I recommend my "HN: Draw arrow" plugin (viewtopic.php?f=9&t=17084).

By the way: I create and test my Python plugins under "Windows 10" using the free development environment "Microsoft Visual Studio Community 2019, Version 16.5.4".

If you have any questions or need further help, I will be happy to assist you.

Greetings Tscheppo

Re: Difference between "Python-Fu" and "Python" plugin

Mon Jun 01, 2020 3:15 pm

Thanks Herbie!
As someone who has not ventured outside the Gimp plug-in safety net I found this very interesting.

Re: Difference between "Python-Fu" and "Python" plugin

Wed Jun 09, 2021 3:09 am

Hello。I would like to ask a few questions: 1, if the GIMP's Python plugin can be written in Python3. 2. I want to use Python's NumpY and CV2 in my plugin. If I can use, what should I use, how can I not, how do I make matrix operations in the plugin? Please,thank you

Re: Difference between "Python-Fu" and "Python" plugin

Wed Jun 09, 2021 11:15 am

With Gimp 2.10, this is Python2. Gimp v3 is moving to Python3.

You can use Numpy in Python v2, but you have to install it for the Python runtime used by Gimp, which can be a bit complicated if you are using Windows, or a flatpak/snap package on Linux.

See https://www.gimp-forum.net/Thread-Gimp-python-and-numpy

Re: Difference between "Python-Fu" and "Python" plugin

Wed Sep 29, 2021 6:48 pm

For the "Python" plugin, there is no reason that the code has to be started by GIMP. It should be possible to do it the other way around. I should be able to start the code with Pyscripter or the Wing debugger and start GIMP from the plug-in code. This would give me far better debugging capability, wouldn't it?

I see that there is an entire Python 2.7 in the Python directory. I should be able to place any python package in site-package and load it from the plug-in.

This is going to be fun!!! Using GIMP as a graphic editing package, much like matplotlib for python

Re: Difference between "Python-Fu" and "Python" plugin

Wed Sep 29, 2021 7:58 pm

ok. This is interesting:

https://stackoverflow.com/questions/819 ... o-it%20%29

Re: Difference between "Python-Fu" and "Python" plugin

Thu Sep 30, 2021 2:00 am

ecs1749 wrote:ok. This is interesting:

https://stackoverflow.com/questions/819 ... o-it%20%29


Also: https://stackoverflow.com/questions/444 ... 0#44435560
Post a reply