template python plugin
This discussion is connected to the gimp-developer-list.gnome.org mailing list which is provided by the GIMP developers and not related to gimpusers.com.
This is a read-only list on gimpusers.com so this discussion thread is read-only, too.
template python plugin | Greg MacDonald | 29 Sep 02:15 |
template python plugin | Sven Neumann | 29 Sep 11:03 |
template python plugin | Greg MacDonald | 29 Sep 12:04 |
template python plugin | Sven Neumann | 29 Sep 12:37 |
template python plugin | Greg MacDonald | 01 Oct 05:59 |
template python plugin | Sven Neumann | 01 Oct 08:37 |
template python plugin
Hi Everyone,
I've been fiddling around with writing gimp-python plugins and ended up creating a template for myself. It took me a day to put together so I was thinking I might post it. It demonstrates a few things like logging exceptions to a file for gui debugging (print statements and exceptions don't seem to display in gui mode for some reason) and running a plugin from the console which I've found useful for quick debug iterations. And it also shows how to use a file chooser dialog to prompt the user for a file. Hope you like it.
-Greg
#!/usr/bin/env python
# 9/14/2008 - Greg MacDonald
# This is an example gimp python plugin template. It demonstrates how to
# create two different types of plugins; an image plugin, and a toolbox
# plugin. The toolbox plugin only takes a run_mode parameter, while
# the image plugin takes a run_mode parameter as well as an image and
# drawable paramter.
#
# The example also shows how to use logging. This is useful for "printf"
# debugging when running in interactive mode as print statements don't seem to
# output to the console. They do however in batch mode.
#
# Batch mode is also demonstrated with a mechanism to run a command in batch
# mode if this file is run from the command line: "python gimp_plugin_template.py".
#
# If an exception occurs during plugin execution, a stack trace is sent to the log.
try:
import gimp
except:
if __name__ == '__main__':
import os
cmd = 'gimp-2.4 --console-messages --verbose --no-data --batch-interpreter python-fu-eval --no-interface --batch "pdb.toolbox_go(RUN_NONINTERACTIVE)" --batch "pdb.gimp_quit(0)"'
os.sys.exit(os.system(cmd))
else:
raise
import gimpplugin
from gimpenums import *
pdb = gimp.pdb
import logging
FORMAT = '%(lineno)d:%(levelname)s %(asctime)s : %(message)s'
# Other logging format options:
# %(name)s Name of the logger (logging channel).
# %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
# %(levelname)s Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
# %(pathname)s Full pathname of the source file where the logging call was issued (if available).
# %(filename)s Filename portion of pathname.
# %(module)s Module (name portion of filename).
# %(funcName)s Name of function containing the logging call.
# %(lineno)d Source line number where the logging call was issued (if available).
# %(created)f Time when the LogRecord was created (as returned by time.time()).
# %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
# %(asctime)s Human-readable time when the LogRecord was created. By default this is of the form ``2003-07-08 16:49:45,896'' (the numbers after the comma are millisecond portion of the time).
# %(msecs)d Millisecond portion of the time when the LogRecord was created.
# %(thread)d Thread ID (if available).
# %(threadName)s Thread name (if available).
# %(process)d Process ID (if available).
# %(message)s The logged message, computed as msg % args.
logging.basicConfig(filename=r'c:\gimp_plugin.log', level=logging.INFO, format=FORMAT)
import gtk
class MyPlugin(gimpplugin.plugin):
def __init__(self):
self.log = logging.getLogger('MyPlugin')
def start(self):
self.log.info('start')
gimp.main(self.init, self.quit, self.query, self._run)
def init(self):
self.log.info('init')
def quit(self):
self.log.info('quit')
def query(self):
self.log.info('query')
authorname = "My Name"
copyrightname = "My Name"
date = "2008"
menupath = "/My _Plugin/_Go"
toolbox_go_description = "An example of a toolbox plugin."
toolbox_go_help = "An example of a toolbox plugin."
toolbox_go_params = [(PDB_INT32, "run_mode", "Run mode")]
gimp.install_procedure("toolbox_go",
toolbox_go_description,
toolbox_go_help,
authorname,
copyrightname,
date,
menupath,
"*",
PLUGIN,
toolbox_go_params,
[])
menupath = "/My _Plugin/_Go"
image_go_description = "An example of an image plugin."
image_go_help = "An example of an image plugin."
image_go_params = [(PDB_INT32, "run_mode", "Run mode"),
(PDB_IMAGE, "image", "Input image"),
(PDB_DRAWABLE, "drawable", "Input drawable")]
gimp.install_procedure("image_go",
image_go_description,
image_go_help,
authorname,
copyrightname,
date,
menupath,
"*",
PLUGIN,
image_go_params,
[])
def __del__(self):
logging.shutdown()
def toolbox_go(self, run_mode):
try:
# RUN_WITH_LAST_VALS
self.log.info('toolbox_go')
self.log_interaction_mode(run_mode)
if run_mode != RUN_INTERACTIVE:
return
# Example file chooser.
chooser = gtk.FileChooserDialog(title='Choose a file.',action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
chooser.set_current_folder('.')
# Repeat this block for additional file filter.
filter = gtk.FileFilter()
filter.set_name("All Files")
filter.add_pattern("*.*")
chooser.add_filter(filter)
response = chooser.run()
if response == gtk.RESPONSE_OK:
path = chooser.get_filename()
self.log.info('Chose File: %s', path)
elif response == gtk.RESPONSE_CANCEL:
self.log.info('User cancelled choosing a file.')
return
chooser.destroy()
except:
import traceback
self.log.error("%s", traceback.format_exc())
raise
def log_interaction_mode(self, run_mode):
if run_mode == RUN_INTERACTIVE:
self.log.debug('run_mode=INTERACTIVE')
elif run_mode == RUN_NONINTERACTIVE:
self.log.debug('run_mode=RUN_NONINTERACTIVE')
elif run_mode == RUN_WITH_LAST_VALS:
self.log.debug('run_mode=RUN_WITH_LAST_VALS')
else:
self.log.error('run_mode=UNKNOWN')
def image_go(self, run_mode, image, drawable):
try:
self.log.info('image_go')
self.log_interaction_mode(run_mode)
# Do something here.
except:
import traceback
self.log.error("%s", traceback.format_exc())
raise
if __name__ == '__main__':
MyPlugin().start()
template python plugin
Hi,
On Sun, 2008-09-28 at 17:15 -0700, Greg MacDonald wrote:
I've been fiddling around with writing gimp-python plugins and ended up creating a template for myself. It took me a day to put together so I was thinking I might post it.
This is interesting. Is there a particular reason that your plug-in template is not using gimpfu, the convenience layer that the Python binding offers for making it easier to write simple plug-ins?
Sven
template python plugin
Hi Sven,
No reason really. But now that you bring it up, I wonder if gimpfu might be more useful to people. If I had needed to setup a gui, I probably would've stuck with gimpfu for it's auto gui generation features. I think I may have gone with gimpplugin too because it just felt familiar to me; reminded me of other sorts of plugins I've written.
Would you like me to switch it over?
-Greg
On Mon, Sep 29, 2008 at 2:03 AM, Sven Neumann wrote:
Hi,
On Sun, 2008-09-28 at 17:15 -0700, Greg MacDonald wrote:
I've been fiddling around with writing gimp-python plugins and ended up creating a template for myself. It took me a day to put together so I was thinking I might post it.
This is interesting. Is there a particular reason that your plug-in template is not using gimpfu, the convenience layer that the Python binding offers for making it easier to write simple plug-ins?
Sven
template python plugin
Hi,
I would very much welcome if you could change the call to gimp.install_procedure() to not pass the full menu path. The procedure is supposed to be passed the menu label only. There's a seperate procedure to register the menu entry: gimp.menu_register().
Sven
template python plugin
Revised version attached.
On Mon, Sep 29, 2008 at 3:37 AM, Sven Neumann wrote:
Hi,
I would very much welcome if you could change the call to gimp.install_procedure() to not pass the full menu path. The procedure is supposed to be passed the menu label only. There's a seperate procedure to register the menu entry: gimp.menu_register().
Sven
#!/usr/bin/env python
# 9/14/2008 - Greg MacDonald
# This is an example gimp python plugin template. It demonstrates how to
# create two different types of plugins; an image plugin, and a toolbox
# plugin. The toolbox plugin only takes a run_mode parameter, while
# the image plugin takes a run_mode parameter as well as an image and
# drawable paramter.
#
# The example also shows how to use logging. This is useful for "printf"
# debugging when running in interactive mode as print statements don't seem to
# output to the console. They do however in batch mode.
#
# Batch mode is also demonstrated with a mechanism to run a command in batch
# mode if this file is run from the command line: "python gimp_plugin_template.py".
#
# If an exception occurs during plugin execution, a stack trace is sent to the log.
try:
import gimp
except:
if __name__ == '__main__':
import os
cmd = 'gimp-2.4 --console-messages --verbose --no-data --batch-interpreter python-fu-eval --no-interface --batch "pdb.toolbox_go(RUN_NONINTERACTIVE)" --batch "pdb.gimp_quit(0)"'
os.sys.exit(os.system(cmd))
else:
raise
import gimpplugin
from gimpenums import *
pdb = gimp.pdb
import logging
FORMAT = '%(lineno)d:%(levelname)s %(asctime)s : %(message)s'
# Other logging format options:
# %(name)s Name of the logger (logging channel).
# %(levelno)s Numeric logging level for the message (DEBUG, INFO, WARNING, ERROR, CRITICAL).
# %(levelname)s Text logging level for the message ('DEBUG', 'INFO', 'WARNING', 'ERROR', 'CRITICAL').
# %(pathname)s Full pathname of the source file where the logging call was issued (if available).
# %(filename)s Filename portion of pathname.
# %(module)s Module (name portion of filename).
# %(funcName)s Name of function containing the logging call.
# %(lineno)d Source line number where the logging call was issued (if available).
# %(created)f Time when the LogRecord was created (as returned by time.time()).
# %(relativeCreated)d Time in milliseconds when the LogRecord was created, relative to the time the logging module was loaded.
# %(asctime)s Human-readable time when the LogRecord was created. By default this is of the form ``2003-07-08 16:49:45,896'' (the numbers after the comma are millisecond portion of the time).
# %(msecs)d Millisecond portion of the time when the LogRecord was created.
# %(thread)d Thread ID (if available).
# %(threadName)s Thread name (if available).
# %(process)d Process ID (if available).
# %(message)s The logged message, computed as msg % args.
logging.basicConfig(filename=r'c:\gimp_plugin.log', level=logging.INFO, format=FORMAT)
import gtk
class MyPlugin(gimpplugin.plugin):
def __init__(self):
self.log = logging.getLogger('MyPlugin')
def start(self):
self.log.info('start')
gimp.main(self.init, self.quit, self.query, self._run)
def init(self):
self.log.info('init')
def quit(self):
self.log.info('quit')
def query(self):
self.log.info('query')
authorname = "My Name"
copyrightname = "My Name"
date = "2008"
menulabel = "_Go"
toolbox_go_description = "An example of a toolbox plugin."
toolbox_go_help = "An example of a toolbox plugin."
toolbox_go_params = [(PDB_INT32, "run_mode", "Run mode")]
gimp.install_procedure("toolbox_go",
toolbox_go_description,
toolbox_go_help,
authorname,
copyrightname,
date,
menulabel,
"*",
PLUGIN,
toolbox_go_params,
[])
menupath = "/My _Plugin/"
gimp.menu_register("toolbox_go", menupath)
menulabel = "_Go"
image_go_description = "An example of an image plugin."
image_go_help = "An example of an image plugin."
image_go_params = [(PDB_INT32, "run_mode", "Run mode"),
(PDB_IMAGE, "image", "Input image"),
(PDB_DRAWABLE, "drawable", "Input drawable")]
gimp.install_procedure("image_go",
image_go_description,
image_go_help,
authorname,
copyrightname,
date,
menulabel,
"*",
PLUGIN,
image_go_params,
[])
menupath = "/My _Plugin/"
gimp.menu_register("image_go", menupath)
def __del__(self):
logging.shutdown()
def toolbox_go(self, run_mode):
try:
# RUN_WITH_LAST_VALS
self.log.info('toolbox_go')
self.log_interaction_mode(run_mode)
if run_mode != RUN_INTERACTIVE:
return
# Example file chooser.
chooser = gtk.FileChooserDialog(title='Choose a file.',action=gtk.FILE_CHOOSER_ACTION_OPEN, buttons=(gtk.STOCK_CANCEL,gtk.RESPONSE_CANCEL,gtk.STOCK_OPEN,gtk.RESPONSE_OK))
chooser.set_current_folder('.')
# Repeat this block for additional file filter.
filter = gtk.FileFilter()
filter.set_name("All Files")
filter.add_pattern("*.*")
chooser.add_filter(filter)
response = chooser.run()
if response == gtk.RESPONSE_OK:
path = chooser.get_filename()
self.log.info('Chose File: %s', path)
elif response == gtk.RESPONSE_CANCEL:
self.log.info('User cancelled choosing a file.')
return
chooser.destroy()
except:
import traceback
self.log.error("%s", traceback.format_exc())
raise
def log_interaction_mode(self, run_mode):
if run_mode == RUN_INTERACTIVE:
self.log.debug('run_mode=INTERACTIVE')
elif run_mode == RUN_NONINTERACTIVE:
self.log.debug('run_mode=RUN_NONINTERACTIVE')
elif run_mode == RUN_WITH_LAST_VALS:
self.log.debug('run_mode=RUN_WITH_LAST_VALS')
else:
self.log.error('run_mode=UNKNOWN')
def image_go(self, run_mode, image, drawable):
try:
self.log.info('image_go')
self.log_interaction_mode(run_mode)
# Do something here.
except:
import traceback
self.log.error("%s", traceback.format_exc())
raise
if __name__ == '__main__':
MyPlugin().start()
template python plugin
Hi,
On Tue, 2008-09-30 at 20:59 -0700, Greg MacDonald wrote:
Revised version attached.
Another question: why does your plug-in register image and drawable input parameters? It doesn't seem to use these at all.
Sven