(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à!