4 min read

Making use of GIMP plugins

Table of Contents

(or how to draw an arrow with an outline)

As part of a project that I’m working on, I found myself drawing lots of red arrows with yellow outlines. To do this I was using the GIMP image editor.

This was tedious. I would draw a yellow arrow for the outline, then draw a red arrow slightly smaller, then merge down so I had one layer. I started wondering about scripting it.

First I started by just calling the FU_arrow.scm script with my values. It wasn’t hard to write a script that did that. In my case, I did:

    (FU-arrow image drawable
            80.0
            25
            TRUE
            75
            500 ; brush thickness
            FALSE ; use forst point as head
            FALSE ; delete path after arrow was drawn
            TRUE ; use new layer for arrow
            FALSE ; draw double headed arrow
            FALSE ; useless
            )

In other words, my plugin just called the FU-arrow plugin. Next I added a little bit of code around that:

    (gimp-image-undo-group-start image)
    (gimp-context-push)
    (gimp-palette-set-foreground '(255 255 0)) ; yellow
    (FU_arrow image drawable 80.0 ...) ; draw outer (bottom) layer
    (gimp-palette-set-foreground '(255 0 0)) ; red
    (FU_arrow image drawable 80.0 ...) ; draw inner (top) layer
    (gimp-context-pop)
    (gimp-image-undo-group-end image)

This saved the state and set the foreground colours appropriately so I didn’t have to, and also made it easy to undo in a single action.

You can see that I called FU_arrow twice. Next I needed to merge them down. For that, I used the facility in the arrow plugin that lets you create the arrow as a new layer. New layers are added at the top of the layer stack, so it’s fairly easy to grab that and work with it. The interesting code is:

    (set! current-layers (cadr (gimp-image-get-layers image)))
    (set! arrow-foreground-layer
      (vector-ref current-layers 0))

Once I have a handle on the foreground layer, I can use gimp-image-merge-down with CLIP-TO-BOTTOM-LAYER to merge the two layers:

(gimp-image-merge-down image arrow-foreground-layer CLIP-TO-BOTTOM-LAYER)

Because I know nobody else created a layer between the two layers I created, it’s easy to get a handle on the new layers the FU-arrow plugin made.

On Gimp 2.10, I noticed that the thickness of my arrow was tracking the thickness of the currently-selected paintbrush. To fix that, I chose the brush width explicitly using:

(gimp-context-set-brush-size 30)
(gimp-context-set-brush-hardness 1.00)

for the outer brush, and 20 for the inner brush.

My total plugin is:

(define
  (script-fu-quick-arrow image drawable)
  (let *
       (
       (arrow-background-layer -1)
       (arrow-foreground-layer -1)
       (current-layers -1)
       )
    (gimp-image-undo-group-start image)
    (gimp-context-push)
    (gimp-context-set-brush-size 30)
    (gimp-context-set-brush-hardness 1.00)
    (gimp-palette-set-foreground '(255 255 0))
    (FU-arrow image drawable
			80.0
			25
			TRUE
			75
			500 ; brush thickness
			FALSE ; use forst point as head
			FALSE ; delete path after arrow was drawn
			TRUE ; use new layer for arrow
			FALSE ; draw double headed arrow
			FALSE ; useless
			)
    (set! current-layers (cadr (gimp-image-get-layers image)))
    (set! arrow-background-layer
	  (vector-ref current-layers 0))
    (gimp-context-set-brush-size 20)
    (gimp-palette-set-foreground '(255 0 0))
    (FU-arrow image drawable
			80.0
			25
			TRUE
			75
			1 ; brush thickness
			FALSE ; use first path as head
			TRUE ; delete path after arrow was drawn
			TRUE ; use new layer for arrow
			FALSE ; draw double headed arrow
			FALSE ; useless
			) ;script-fu-draw-arrow function call
    (set! current-layers (cadr (gimp-image-get-layers image)))
    (set! arrow-foreground-layer
	  (vector-ref current-layers 0))

    (if (= -1 arrow-foreground-layer) (gimp-message "Foreground is -1"))
    (if (= -1 arrow-background-layer) (gimp-message "Background is -1"))
    (gimp-image-merge-down image arrow-foreground-layer
         CLIP-TO-BOTTOM-LAYER )
    (gimp-context-pop)
    (gimp-image-undo-group-end image)
    ) ; let
  ) ;define

; Register with GIMP:

(script-fu-register "script-fu-quick-arrow"
  _"Quick Arrow"
  _"Draw a nearly arbitrary arrow in your image in red with a yellow outline. Arrow will be created in a separate layer. Needs FU_arrow.scm"
  "Andrew"
  "2016, Andrew"
  "2016-09-01"
  "*"
  SF-IMAGE       "The image"   0
  SF-DRAWABLE    "The drawable"   0
)

(script-fu-menu-register "script-fu-quick-arrow" "/Script-Fu/")

Quick edit: to install the script, copy it to the scripts directory. You can find that with Edit -> Preferences -> Folders -> Scripts (I used the user folder rather than the system folder). Then Filters -> Script-Fu -> Refresh Scripts. Et voilà!