10. Scripting

mtPaint is totally scriptable. Everything you can do (except tweaking the GUI) you can also do from a script.

You can run scripts in one of four ways.

First is direct execution. Select 'Image->Scripts->Configure' menu option, choose a free script slot in the list on top, enter the commands in the window below, press "Execute", and it will happen. If there is an error in your script, execution will stop on it and the problem will be reported.

Second is the 'Image->Scripts' submenu. If in the example above you fill the "Action" entry, above the commands window, with something not totally commented out (first non-whitespace character not "#", that is), enter the commands and press "OK", the action will appear in said submenu. Note that menu slots are rigidly mapped to the script list's rows; only the first 10 rows can appear in the menu, and whether a row's action is commented out or empty, its menu slot still belongs to it.

Third is an extension of the second; in 'Help->Keyboard Shortcuts...' you assign a key to 'Image->Scripts->1'...'10', and then use that key to run your script that is sitting in the submenu.

And last but certainly not least, you can use the commandline mode. If the first option on the commandline is "--cmd", everything else after it is treated as script commands, and the GUI is not fired up at all. Any changes done to persistent settings and preferences while in commandline mode, are not written back into the inifile either.

Note that when a script is executing, all confirmation requests are automatically answered in the positive, or not asked at all. You will have no chance to change your mind at the last moment; it is assumed that you did your thinking before activating the script.

10.1 Script Commands

The commands are every bit as stable as menu structure and dialog items' naming is. Because the "commands" are the very same names - or, any prefix of any word in them that does still match uniquely. This self-naming and self-documenting is part of the reason why scripting is implemented through the V-code.

A script is commands with their parameters. Commands are prefixed with "-" and match to menu items; parameters are followed by "=" and a value, and match to dialog items. If a command itself is followed by "=" and value, that matches the unnamed item in the dialog. But such an unnamed option can just stand alone: "-file/as=zad" is fully equivalent to "-file/as =zad".

The entire name of a menu option, including spaces, is the canonical name of its matching command - with shell quoting used to protect the spaces. Like this:

mtpaint --cmd -file/'save as ...'=zad

It is safe to shorten the "save as ..." to just "as", because no word in other items' names in the same submenu starts with "as". And so it is done in the examples. But "save" on its own is a match for another item in the same submenu: "File->Save", which stands before "File->Save as".

Parts separated by "/" are matched to corresponding menu levels in order. So to call up "Effects->Isometric transformation->Top side right", you can write a command "-eff/iso/top". Or more verbosely, "-effect/isometric/top".

Same thing about parameters. You can write:

mtpaint --cmd -file/'save as' =zad 'file format'=png 'transparency index'=0 'png compression'=9

But it is just as unambiguous in this case to write this instead:

mtpaint --cmd -file/as=zad f=png t=0 p=9

Still, for the sake of understandability it's better to use some more chars per option. Say, like this:

mtpaint --cmd -file/as=zad format=png trans=0 png=9

But it is not unambiguous to use "c=9", "comp=9" or even "compression=9", because there also exist "JPEG2000 compression" and "TGA RLE compression" in this same dialog (visible to user for different filetypes, but V-code sees them all at once).

So "-effect/unsharp r=1 am=0.4" in the example means the same as "-effects/'unsharp mask' radius=1 amount=0.4" would.

The unnamed parameter matches to the unnamed control in a dialog - usually it is the top one, but not always. For fileselector, it is filename; for most filters, it is value spinbutton; but for image scale, you can see it is filter name - everything above their list has names; for image resize - tiling mode, for the same reason. So you see "-image/scale=nearest" and "-image/resize=mirror" in the examples.

To select options from lists, such as filter names or file formats, values are matched to option names just the same way as parameters are matched to dialog items, and commands to menu items. So "image/scale=near" will select you the "Nearest neighbour" scaling method.

In a list with named columns, each name refers to a list of that column's values; like in "-edit/freetype font=Arial filename=arial.ttf face=0".

The matching rule for string values:

To check a checkbutton or toggle a togglebutton on, you assign to it some true value, or omit the assignment and just mention the name. Same thing to press a button (if it is scriptable). Like this: "-image/resize w=x2 fix centre". Unchecking or toggling off always requires an explicit assignment of a false value. The check menuitems work the same way; "-channels/couple" enables the 'Couple RGBA Operations', "-channels/couple=0" disables it.

If you aren't sure whether a parameter would be present in the dialog at all (it is one such as might get disabled) but want to set it in case it's present, you prefix its name with "." Say, to scale an image of unknown type in a nearest neighbor mode, it's safe to write "-image/scale .=near", but "-image/scale=near" will fail to match in case the image turns out to be a GIF or other indexed format.

Note that parameters that are merely conditionally hidden, stay readily accessible from a script despite that; for example, you can set PNG compression level for the file you're about to save, even before selecting the PNG format: "-file/as=zad png=9 form=png". The same rule applies to content of 'Settings' pages of dialogs such as 'Convert to Indexed' and 'Scale Canvas'.

For ease of use, the "Width" and "Height" fields in "Scale canvas" and "Resize canvas" dialogs are made to understand a couple formats that a regular spinbutton wouldn't. Like this:

"w=x1.5" - multiplies the original value by 1.5;
"w=33%" - 33% of the original value.

If "Fix aspect ratio" is toggled on ("fix=1" if you aren't sure it is) then setting the width will correspondingly modify the height, or vice versa. But only the first time; so you can write "w=200% h=x1" to make the image twice wider, and not bother with "Fix aspect ratio" setting.

This is how it works.

10.1.1 Groups

There are places where items with same or similar names sit in one dialog. They are disambiguated with named groups (in V-code, it is the GROUPN command). Similarly to menu path in a command, parts of a parameter name separated by "/" are matched first to groups, and then to items in a group. Like this:

-image/skew horizontal/offset=10 vertical/offset=20

See section 10.5 for full list of those places and the group names.

10.1.2 Flattening

An option menu or a radiobutton pack can be made to present its list of choices to scripts as if they are separate dialog items (in V-code, it is the FLATTEN command). For example, you can do "-edit/paste left" instead of wordier "-edit/paste align=left".

The places where that is done, are listed in section 10.5.

10.2 Quoting and Comments

Quoting and word-splitting in scripts works the same as in Bourne shell. Words (i.e. commands) are split on unquoted whitespace. For quoting, you can use double quotes, single quotes, and backslashes.

A comment in a script is everything from an unquoted "#" to the end of line (again, same as in Bourne shell).

  # This is an example
  -e/freetype text="One \"Example text\" "\ 'in
  two lines' # now is on clipboard
  -e\
  /paste=(100,100) # now is on canvas

10.3 Lists

Some dialogs, for ease of use, have controls (usually their unnamed one) accepting lists of values. (On V-code level, it is the EVENT(MULTI, handler) command.)

A list is one or more whitespace-separated groups of comma-separated values, put in parentheses. When assigning to the unnamed control, the "=" is optional. Like in the example below:

-select/all (11,22 95,55 11,166) # Select a triangle

10.4 Toolbars

Tools toolbar, settings toolbar, and layers toolbar and window are accessed through the Edit menu: "-edit/tools", "-edit/settings", "-edit/layers".

In place of a right click on a button, to open its configuration dialog, you add ":" to its name; a freestanding ":" closes the dialog and returns you to the toolbar. Like this: "-edit/settings blend: =value : blend" first configures the blend mode to the Value blend, and then enables it.

To use a drawing tool, you enable it and then assign its path as a list, to the toolbar's unnamed control:

-edit/tool paint (10,10 20,10 20,20 30,20)

If you want to simulate a pressure-enabled tool, such as a tablet, add a third value (between 0 and 1) for pressure:

-edit/tool paint (10,10,0.5 20,10,0.7 20,20,0.8 30,20,1)

Without that third value pressure is set to 1, same as when you use a mouse.

10.5 Irregularities

While for the most part, mtPaint's scripting capabilities are self-documenting, there also exists the other part.

While all of that can be found out from reading the code, the sections below list such invisible features for each location in the interface that has them.

10.5.1 The File Menu

File actions and recent files are invisible to scripts.

10.5.2 The Edit Menu

'Import Clipboard from System' and 'Export Clipboard to System' are invisible to scripts.

10.5.3 The View Menu

Only 'Snap To Tile Grid' is visible to scripts.

10.5.4 The Image Menu

Nesting of scripts (through "-i/script=file" and/or "-i/scripts/1" etc.) is limited to 16 (the MAX_NESTING constant in mainwindow.c).

10.5.5 The Selection Menu

10.5.6 The Palette Menu

10.5.7 The Effects Menu

10.5.8 The Channels Menu

'Hide Image', 'View Alpha as an Overlay' and 'Configure Overlays ...' are invisible to scripts.

10.5.9 The Layers Menu

Animation features are invisible to scripts: 'Configure Animation ...', 'Preview Animation ...' 'Set Key Frame ...', 'Remove All Key Frames ...'.

10.5.10 The Tools Toolbar

'Paste Text' is invisible to scripts; do it through the Edit menu instead.

10.5.10.1 The Edit Gradient Dialog

This is how you set a custom gradient from script: "-e/tool grad: grad/edit =0 col=red type=hsv =1 col=blue : grad=custom".

10.5.11 The Settings Toolbar

10.5.12 The Layers Window

'Close Layers Window' and 'Show all layers in main window' are invisible to scripts.

10.6 Examples

- "Value Invert" filter

See https://docs.gimp.org/en/gimp-filter-invert-value.html
  -e/set blend: =val rev : blend
  -pal/edit=a c=#FFFFFF
  -s/all -s/fill -ef/inv -e/copy -e/undo -e/undo
  -e/set blend: rev=0 -e/paste

- Aura

Considering colour B the background, draw a one pixel wide contour of colour A around everything on it.
  # Copy image to clipboard
  -s/all -e/copy
  # Put colors A & B onto canvas
  -s/all=(0,0) -s/fill -p/swap -s/all=(1,0) -s/fill
  # Make colors A & B both be the original B, and mask clipboard with that
  -e/col b=(1,0) -s/mask
  # Restore color A and restore canvas to original
  -e/col a=(0,0) -e/undo=2
  # Reinit canvas from clipboard, now clipboard mask is the selection channel
  -f/new=clip
  # Create mask from selection
  -c/new=mask init=sel
  # Fill by color A outside mask, and delete the mask
  -s/all -s/fill -c/del mask
  # Dilate selection and copy the image; selection becomes clipboard mask
  -c/sel -ef/dilate -c/image -e/copy
  # Restore canvas again
  -e/undo=5
  # Paste over
  -e/paste -s/none