Posts: 93
Threads: 5
Joined: Jun 2019
Reputation:
20
Gimp version:
Operating system(s): Linux
(03-03-2025, 10:42 AM)alvk Wrote: Hello!
I have trouble with porting a script written in Script-Fu from Gimp2 to Gimp3. I managed to run the script, but when script execution finished, I've got the following error: argument 1 must be: number. Unfortunately, I cannot understand why this error occurs. Could anyone review my code and help me to make the script working. The script is below:
Code:
#!/usr/bin/env gimp-script-fu-interpreter-3.0
; Adds labels to a layer
; Works with Gimp v.3
(define (script-fu-add-labels image drawables user-text font font-size
font-color x y outline-toggle outline-color
outline-thickness)
(let* ((current-layer (vector-ref drawables 0))
(off-x (car (gimp-drawable-get-offsets current-layer)))
(off-y (cadr (gimp-drawable-get-offsets current-layer)))
(text-layer)
(text-layer-position-x (+ off-x x))
(text-layer-position-y (+ off-y y))
(text-layer-outline)
(text-layer-vectors)
(text-layer-group)
(text-layer-group-name)
(text-foreground-color-old)
(parent-layer-type 0)
(parent-layer-name)
(parent-layer-group (car (gimp-item-get-parent current-layer)))
(old-background (car (gimp-context-get-background))))
(cond ((= #t (car (gimp-item-id-is-channel current-layer))) (set! layer-type 1))
((= #t (car (gimp-item-is-group current-layer))) (set! layer-type 1))
((= #t (car (gimp-item-id-is-layer-mask current-layer))) (set! layer-type 1))
((= #t (car (gimp-item-id-is-selection current-layer))) (set! layer-type 1))
((= #t (car (gimp-item-id-is-text-layer current-layer))) (set! layer-type 1)))
(gimp-image-undo-group-start image)
(if (= 1 parent-layer-type)
(begin
(set! parent-layer-name (car (gimp-item-get-name current-layer)))
(gimp-message
(string-append "Cannont add the label to the layer " parent-layer-name)))
(begin
(set! text-layer (car (gimp-text-font image -1 text-layer-position-x
text-layer-position-y user-text 2 #t
font-size POINTS font)))
(gimp-text-layer-set-color text-layer font-color)
(when (= outline-toggle #t)
(set! text-layer-group (car (gimp-layer-group-new image)))
(set! text-layer-group-name
(string-append "Text_" (car (gimp-text-layer-get-text
text-layer))))
(set! text-layer-vectors (car (gimp-vectors-new-from-text-layer image
text-layer)))
(set! text-layer-outline (car (gimp-layer-copy text-layer #t)))
(set! text-foreground-color-old (car (gimp-context-get-foreground)))
(gimp-item-set-name text-layer-group text-layer-group-name)
(gimp-image-insert-layer image text-layer-group 0 0)
(gimp-image-insert-vectors image text-layer-vectors 0 -1)
(gimp-image-reorder-item image text-layer text-layer-group 0)
(gimp-image-insert-layer image text-layer-outline text-layer-group -1)
(gimp-context-set-foreground outline-color)
(gimp-context-set-stroke-method 0)
(gimp-context-set-line-width outline-thickness)
(gimp-drawable-edit-stroke-item text-layer-outline text-layer-vectors)
(gimp-context-set-foreground text-foreground-color-old)
(gimp-item-set-expanded text-layer-group #f)
(gimp-item-set-lock-position text-layer-outline #t))
(gimp-item-set-lock-position text-layer #t)))
(gimp-displays-flush)
(gimp-image-undo-group-end image)))
(script-fu-register-filter "script-fu-add-labels"
_"Add labels"
_""
""
""
""
"*"
SF-ONE-OR-MORE-DRAWABLE
SF-STRING _"Label" "A"
SF-FONT _"Font" "Arial Bold"
SF-ADJUSTMENT _"Font size" (list 50 5 100 1 10 0 1)
SF-COLOR _"Font color" (list 0 0 0)
SF-ADJUSTMENT _"Offset X" (list 6 0 500 1 10 0 1)
SF-ADJUSTMENT _"Offset Y" (list 6 0 500 1 10 0 1)
SF-TOGGLE _"Outline" #f
SF-COLOR _"Outline color" (list 255 255 255)
SF-ADJUSTMENT _"Outline thickness" (list 1 0 5 1 1 0 1)
)
(script-fu-menu-register "script-fu-add-labels"
"<Image>/Figures")
Your cond statement doesn't make much sense but seeing as that's what you are doing:
The function = does not take #t and #f. It can take numbers. Gimp provided TRUE and FALSE which are 1 and 0 so if they are still in gimp 3 you could use them in your cond statement instead of the #t.
The whole thread is pretty muddled and there isn't enough context to see what your working baseline was and how the changes you've made fit in. For example you already had current-layer setup at the start of your let statement:
Code:
(let* ((current-layer (vector-ref drawables 0))
...
So why aren't you using current-layer in the code snippets in other posts when you want the first layer instead of repeating (vector-ref drawables 0).
Posts: 14
Threads: 2
Joined: Nov 2022
Reputation:
2
Gimp version:
Operating system(s): Linux
(03-07-2025, 10:53 AM)teapot Wrote: Your cond statement doesn't make much sense but seeing as that's what you are doing:
The function = does not take #t and #f. It can take numbers. Gimp provided TRUE and FALSE which are 1 and 0 so if they are still in gimp 3 you could use them in your cond statement instead of the #t.
According to this link
https://developer.gimp.org/resource/scri...ng-boolean
I was incorrect in my conditional code. In v3 dialect, the correct code differs from that in v2. Why I choose to deal with v3 dialect? The Gimp developers wrote: You should plan on porting existing scripts to the v3 dialect, since eventually ScriptFu may obolete the v2 dialect. This is a citation from the link above. Hence, for me, it is easier to rewrite a few of my scripts now, when I have some time to deal with it.
It was not trivial for me, having little programming background, to find a solution. However, finally I rewrite the script into v3 dialect of ScriptFu. It is much shorter since I've decided to remove some code. The script aimed to add user defined text with user specified x and y offsets with relation to the upper left corner of the currently selected layer. Here is the code:
Code:
#!/usr/bin/env gimp-script-fu-interpreter-3.0
(define (script-fu-add-labels image drawables user-text font font-size font-color x y)
(script-fu-use-v3)
(let* ((current-layer (vector-ref drawables 0))
(off-x (car (gimp-drawable-get-offsets current-layer)))
(off-y (cadr (gimp-drawable-get-offsets current-layer)))
(text-layer)
(text-layer-position-x (+ off-x x))
(text-layer-position-y (+ off-y y))
(text-foreground-color-old)
(layer-type 0))
(gimp-image-undo-group-start image)
(cond
((gimp-item-id-is-channel current-layer) (set! layer-type 1))
((gimp-item-id-is-group-layer current-layer) (set! layer-type 1))
((gimp-item-id-is-layer-mask current-layer) (set! layer-type 1))
((gimp-item-id-is-path current-layer) (set! layer-type 1))
((gimp-item-id-is-text-layer current-layer) (set! layer-type 1))
((gimp-item-id-is-selection current-layer) (set! layer-type 1))
)
(if (< 1 layer-type)
(begin (gimp-message "Cannot add the label to the selected layer"))
(begin (set! text-layer (gimp-text-font image -1 text-layer-position-x
text-layer-position-y user-text 0 #t
font-size font))
(gimp-text-layer-set-color text-layer font-color)
(gimp-item-set-lock-position text-layer #t)))
(gimp-displays-flush)
(gimp-image-undo-group-end image)))
(script-fu-register-filter "script-fu-add-labels"
_"Add label..."
_"Adds a label to currently selected layer"
"alvk"
""
""
"*"
SF-ONE-DRAWABLE
SF-STRING _"Label" "A"
SF-FONT _"Font" "Arial Bold"
SF-ADJUSTMENT _"Font size" (list 50 5 100 1 10 0 1)
SF-COLOR _"Font color" (list 0 0 0)
SF-ADJUSTMENT _"Offset X" (list 6 0 500 1 10 0 1)
SF-ADJUSTMENT _"Offset Y" (list 6 0 500 1 10 0 1)
)
(script-fu-menu-register "script-fu-add-labels"
"<Image>/Figures")
The code of course could be better, but it works for me and it is okay. But anyway, thank you, teapot, for your comment. You point on my mistake with current-layer variable
Posts: 7,352
Threads: 157
Joined: Oct 2016
Reputation:
1,028
Gimp version:
Operating system(s): Linux
Thank all of you. I have even less programming experience, Long ago as a student, Fortran, then bits of BASIC on home computers.
I would like to see a proper Gimp MACRO but that is not going to happen any time soon. I might have to over-ride my total dislike of script-fu and your script - works fine here: kubuntu 24.04 Gimp 3.0RC3 appimage and it gives something to start from.
Posts: 6,596
Threads: 286
Joined: Oct 2016
Reputation:
579
Gimp version:
Operating system(s): Linux
(03-08-2025, 10:30 AM)rich2005 Wrote: I might have to over-ride my total dislike of script-fu and your script - works fine here: kubuntu 24.04 Gimp 3.0RC3 appimage and it gives something to start from.
In 3.00, no reason to not go with Python.
Posts: 93
Threads: 5
Joined: Jun 2019
Reputation:
20
Gimp version:
Operating system(s): Linux
03-08-2025, 05:14 PM
(This post was last modified: 03-08-2025, 05:19 PM by teapot.)
alvk, Thank you for your updated code and explanation, it's going to be a useful template.
Have you tried running it on, for example, a layer group to check you're getting your cannot add label message. I think the (< 1 layer-type) is never true. You checked for = 1 before.
(03-08-2025, 10:14 AM)alvk Wrote:
Code:
(if (< 1 layer-type)
(begin (gimp-message "Cannot add the label to the selected layer"))
(begin (set! text-layer (gimp-text-font image -1 text-layer-position-x
text-layer-position-y user-text 0 #t
font-size font))
(gimp-text-layer-set-color text-layer font-color)
(gimp-item-set-lock-position text-layer #t)))
Posts: 14
Threads: 2
Joined: Nov 2022
Reputation:
2
Gimp version:
Operating system(s): Linux
(03-08-2025, 05:14 PM)teapot Wrote: alvk, Thank you for your updated code and explanation, it's going to be a useful template.
Have you tried running it on, for example, a layer group to check you're getting your cannot add label message. I think the (< 1 layer-type) is never true. You checked for = 1 before.
(03-08-2025, 10:14 AM)alvk Wrote:
Code:
(if (< 1 layer-type)
(begin (gimp-message "Cannot add the label to the selected layer"))
(begin (set! text-layer (gimp-text-font image -1 text-layer-position-x
text-layer-position-y user-text 0 #t
font-size font))
(gimp-text-layer-set-color text-layer font-color)
(gimp-item-set-lock-position text-layer #t)))
Yes, I did. It works as expected. Well, almost as I expect. I just check it and found that if a layer has a mask and the mask is selected, i.e., the border around the layer is green, the script actually inserts the text into the mask. Probably I misunderstand what a layer mask is and how to work with them. I need to read about this. Other types of drawables, i.e., text layer, layer group, path, and selection works as expected.
The idea behind (< 1 layer-type) is to extend the script messaging by providing different messages depending on the selected type of drawable. This is a kind of preliminary code to be extended later. But even in its current form, it works.
Posts: 93
Threads: 5
Joined: Jun 2019
Reputation:
20
Gimp version:
Operating system(s): Linux
(03-09-2025, 01:02 AM)alvk Wrote: Yes, I did. It works as expected. Well, almost as I expect. I just check it and found that if a layer has a mask and the mask is selected, i.e., the border around the layer is green, the script actually inserts the text into the mask. Probably I misunderstand what a layer mask is and how to work with them. I need to read about this. Other types of drawables, i.e., text layer, layer group, path, and selection works as expected.
The idea behind (< 1 layer-type) is to extend the script messaging by providing different messages depending on the selected type of drawable. This is a kind of preliminary code to be extended later. But even in its current form, it works.
Interesting. From your version in post #12, layer-type is initialised to 0 and set to 1 if current-layer meets your criteria. In gimp's scheme console:
Code:
> (< 1 0)
#f
> (< 1 1)
#f
So I would have expected (< 1 layer-type) to be false in both cases thus would not expect the "Cannot add the label to the selected layer" message to occur.
Posts: 14
Threads: 2
Joined: Nov 2022
Reputation:
2
Gimp version:
Operating system(s): Linux
(03-09-2025, 03:44 AM)teapot Wrote: (03-09-2025, 01:02 AM)alvk Wrote: Yes, I did. It works as expected. Well, almost as I expect. I just check it and found that if a layer has a mask and the mask is selected, i.e., the border around the layer is green, the script actually inserts the text into the mask. Probably I misunderstand what a layer mask is and how to work with them. I need to read about this. Other types of drawables, i.e., text layer, layer group, path, and selection works as expected.
The idea behind (< 1 layer-type) is to extend the script messaging by providing different messages depending on the selected type of drawable. This is a kind of preliminary code to be extended later. But even in its current form, it works.
Interesting. From your version in post #12, layer-type is initialised to 0 and set to 1 if current-layer meets your criteria. In gimp's scheme console:
Code:
> (< 1 0)
#f
> (< 1 1)
#f
So I would have expected (< 1 layer-type) to be false in both cases thus would not expect the "Cannot add the label to the selected layer" message to occur.
Hm... you are right. I don't understand why it works, as was I expecting when writing the script.
Posts: 6,596
Threads: 286
Joined: Oct 2016
Reputation:
579
Gimp version:
Operating system(s): Linux
A few quick comments:
- Instead of saving the foreground color, you should save and restore the whole context (because there are other parts of the context that you are changing, such as the path stroke method). This is done with (gimp-context-push) at the beginning of the code, and (gimp-context-pop) at the end.
- You can make the whole script undone by a single Control-Z by making it run as as an undo group with (gimp-image-undo-group-start image) at the beginning and (gimp-image-undo-group-end image) at the end.
- You can avoid having to deal with channels, masks and selection by enabling the script for RGB* instead of *. I recently learned that this applies to the target drawables and not to the image itself.
Posts: 14
Threads: 2
Joined: Nov 2022
Reputation:
2
Gimp version:
Operating system(s): Linux
(03-09-2025, 08:26 AM)Ofnuts Wrote: A few quick comments:
- Instead of saving the foreground color, you should save and restore the whole context (because there are other parts of the context that you are changing, such as the path stroke method). This is done with (gimp-context-push) at the beginning of the code, and (gimp-context-pop) at the end.
- You can make the whole script undone by a single Control-Z by making it run as as an undo group with (gimp-image-undo-group-start image) at the beginning and (gimp-image-undo-group-end image) at the end.
- You can avoid having to deal with channels, masks and selection by enabling the script for RGB* instead of *. I recently learned that this applies to the target drawables and not to the image itself.
Thank you!
|