Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Add text with script fu
#1
Hello from France,
I have been using Gimp for a long time, having been using GNU/Linux for 20 years.
I'm working on a poster without date. I need, from this file, make 30 similar posters, just adding a different date to each one.
Last year I did it by changing the date by hand.
I wonder if it would not be possible with a Fu script.
- Added slap
- add the text field to the right place and the right size
- choice of the police, size, color, alignment
- adding text (if possible with a dialog box)
- record new file ?

I do not know fu scripts yet but I have programming basics. That does not put me off.
Nevertheless, I just read a lot of pages and I found no example to add a simple text on an image.

So if you could tell me if it's possible and give me some leads, it would be great.

Thank you all in advance,
Carl
Reply
#2
It might be possible with script-fu or python-fu, an expert might look in soon.

However, my first thought was not Gimp but ImageMagick. That should be in your linux repository.

If I create a text file for each date, 01.poster 02.poster ....30.poster then for a single file

Code:
magick poster.jpg -font Futura-Bold.ttf  -pointsize 24 -fill red -annotate +420+1030  @01.poster  01-poster.jpg

writes the content of 01.poster text at the given offset.

For 30 new images then something like a bash file
Code:
#!/bin/bash

find . -name "*.poster" | while read fname ; do
     echo "Doing:  $fname"
     magick poster.jpg -font Futura-Bold.ttf  -pointsize 24 -fill red -annotate +420+1030  @$fname  $fname.jpg
done

creates a new image for each text file and names them 01.poster.jpg 02.poster.jpg ....

As a note I am using kubuntu 18.04 which comes with ImageMagick (IM) 6.9.7 That would use the convert in place of the magick command. For some reason convert throws up errors.
My compiled IM 7.0.8 and magick works fine. If you go down this route and have problems ask on the IM forum https://www.imagemagick.org/discourse-server/ In the Users section.

(edit: The not working convert problem is due to the IM6 security policy held in a policy.xml file. Disabled that and IM6 convert works fine )
Reply
#3
Doable with script-fu, or python-fu, but this is really best done outside of Gimp with a shell script that uses ImageMagick.
Reply
#4
Thank a lot for these answer. 
I didn't think about Imagemagick I use for other think.
Is a good idea.
I'll try that.
Reply
#5
Rainbow 
Hello Carlbcx,

Carlbcx Wrote:I'm working on a poster without date. I need, from this file, make 30 similar posters, just adding a different date to each one.

Chapter 1: Learning basic string operations in Script-Fu
  1. Run Gimp
  2. Gimp menu Filters > Scrip-Fu > Console
  3. Copy in the clipboard the following Script-Fu expression:
Code:
(string-append "C:\\Tool\\Gimp\\forum\\gimp-forum.net\\WriteDate" DIR-SEPARATOR "template" ".png")
  • Paste the content of the clipboard in the input area of the Script-Fu console.
  • Validate by ENTER.
;-> the result should be, in Windows, the full path of your poster:
"C:\\Tool\\Gimp\\forum\\gimp-forum.net\\WriteDate\\template.png"

In Linux, adapt the following path "/home/Tool/Gimp/gimp-forum.net/WriteDate" to your needs:
  • DIR-SEPARATOR is "\\" in Windows
  • DIR-SEPARATOR is "/" in Linux

Consider that the path-in parameter is the root folder of the project called WriteDate.
path-in contains template.png that is to say the poster of reference.

The goal is to generate the dated posters in the subfolder target.
According to your operating system, you must create manually the target folder under path-in.

path-in  = C:\\Tool\\Gimp\\forum\\gimp-forum.net\\WriteDate
path-out = C:\\Tool\\Gimp\\forum\\gimp-forum.net\\WriteDate\\target

We generate the dated posters in the subfolder target in order to remove quickly its content before running again the script.

Regards.

Chapter 2: Defining and running your first Script-Fu function

Define your first Script-Fu function called GenFileOut.
let* introduces the initialization of local variables such as filePoster until file-out.
As usual, copy in the clipboard the following code and paste it in the Script-Fu console:
Code:
(define (GenFileOut path-in template ext date counter)
    (let*    (    (filePoster    (string-append path-in DIR-SEPARATOR template ext))
                (strIdx (number->string counter))
                (strZidx (if (< counter 10) (string-append "0" strIdx) strIdx))
                (path-out (string-append path-in DIR-SEPARATOR "target" DIR-SEPARATOR))
                (file-out (string-append path-out template strZidx ext))
            )
        (display "filePoster: ")    (displayln filePoster)        
        (display "strIdx: ")        (displayln strIdx)        
        (display "strZidx: ")        (displayln strZidx)        
        (display "path-out: ")        (displayln path-out)        
        (display "file-out: ")        (displayln file-out)
)    )
;-> the result of the Script-Fu console should be:
GenFileOut
meaning that your definition is ok. The aligned parenthesis are well balanced.

Run your first function.
We split the full path of the poster of reference as several parameters in order to avoid scanning and parsing the path.
Code:
(GenFileOut "C:\\Tool\\Gimp\\forum\\gimp-forum.net\\WriteDate" "template" ".png" "10/15/2021" 0)
;-> the result of the Script-Fu console should be:
Code:
filePoster: C:\Tool\Gimp\forum\gimp-forum.net\WriteDate\template.png
strIdx: 0
strZidx: 00
path-out: C:\Tool\Gimp\forum\gimp-forum.net\WriteDate\target\
file-out: C:\Tool\Gimp\forum\gimp-forum.net\WriteDate\target\template00.png#t
The return code #t of the function GenFileOut is concatenated with the file-out full path.

If displayln is unknown, it is normally defined in C:\Program Files\GIMP 2\share\gimp\2.0\scripts\palette-export.scm by:
Code:
(define displayln (lambda (obj) (display obj) (display "\n")))

The if instruction is followed by the condition, "Then" part and "Else" part.
In Pascal or Basic-like:
Code:
If counter < 10 then strZidx = "0" + strIdx Else strZidx = strIdx 
However the keywords "Then" and "Else" are implicit in Script-Fu:
Code:
(if (closure? GenFileOut)(display "GenFileOut is a known function")(display "GenFileOut is UNknown"))
;-> GenFileOut is a known function#t

Code:
(if (closure? 'rascalFiloute)(display "rascalFiloute is a known function")(display "rascalFiloute is UNknown"))
;-> will fail: rascalFiloute  Wink is UNknown#t

Chapter 3: WriteDate from template.png

Ofnuts Wrote:Doable with script-fu

We are ready to experiment our new function WriteDate.
Before running WriteDate, prepare with Gimp an empty square image 500 x 500 pixels of yellow color RGB ffff00
Gimp menu File> Export as "template.png" in your working folder "C:\\Tool\\Gimp\\forum\\gimp-forum.net\\WriteDate".

Code:
(define (WriteDate path-in template ext date counter)
    (let*    (    (filePoster    (string-append path-in DIR-SEPARATOR template ext))
                (strIdx (number->string counter))
                (strZidx (if (< counter 10) (string-append "0" strIdx) strIdx))
                (path-out (string-append path-in DIR-SEPARATOR "target" DIR-SEPARATOR))
                (file-out (string-append path-out template strZidx ext))
                (posX 100) (posY 100)
                (imgDat        (car (gimp-image-new 1 1 RGB))) ; Empty poster
                (layerDat     (car (gimp-layer-new imgDat 1 1 RGB-IMAGE "layer_date" 100 LAYER-MODE-NORMAL-LEGACY)))
            )
        (gimp-image-insert-layer imgDat layerDat 0 0)
        (gimp-context-set-foreground '(0 0 0)) ; black
        (gimp-context-set-background '(255 255 255)) ; white
        (gimp-drawable-fill layerDat BACKGROUND-FILL) ; Empty white poster
        (let* ((layerPoster (car (gimp-file-load-layer 1 imgDat filePoster)))) ; load template
            (gimp-image-insert-layer imgDat layerPoster 0 0) ; as a layer to the empty poster
            (script-fu-util-image-resize-from-layer imgDat layerPoster) ; same size than the template
            (gimp-layer-resize-to-image-size layerDat)
            (display "file-out: ") (display file-out) (display " date: ") (displayln date)
            ; Write the date in posX, posY Sans font (private joke)
            (let* ((layerTxt (car (gimp-text-fontname imgDat layerPoster posX posY date 0 TRUE 18 POINTS "Sans"))))
                (gimp-floating-sel-anchor layerTxt)
        )    ) ; Anchor the floating selection to its associated drawable
        (let* ((layerSav (car (gimp-image-flatten imgDat)))) ; Save the dated poster
            (gimp-displays-flush)
            (gimp-file-save RUN-NONINTERACTIVE imgDat layerSav file-out file-out)
            (gimp-image-delete imgDat)        
)    )    )
;-> the result of the Script-Fu console should be:
WriteDate

Code:
(WriteDate "C:\\Tool\\Gimp\\forum\\gimp-forum.net\\WriteDate" "template" ".png" "10/15/2021" 0)
;-> the result of execution should be:
file-out: C:\Tool\Gimp\forum\gimp-forum.net\WriteDate\target\template00.png date: 10/15/2021
(#t)

template00.png has been SUCCESSFULLY generated in the target folder.
We recognize the yellow square of template.png but with the written date "10/15/2021"!

Chapter 4: Basic iterator WriteDates

We wish to call WriteDate for each date of the given list: '("10/15/2021" "10/11/2021")
To get the first date:  Shy
Code:
(car '("10/15/2021" "10/11/2021"))
;-> "10/15/2021"

To get the remaining dates in a list:
Code:
(cdr '("10/15/2021" "10/11/2021"))
;-> ("10/11/2021")

car and cdr are the basic extractors of a Script-Fu list.

WriteDates is a basic iterator based on let loop that increments counter from idxStart = 0.

Note that we save the Gimp context by gimp-context-push because we change the fore and background colors.
We restore this context before the end by gimp-context-pop.

Before running WriteDates, remove manually all previously generated *.png from the target folder.
Code:
; Main iterator
(define (WriteDates path-in template ext lstDate idxStart)
    (gimp-context-push)
    (displayln "") (displayln "WriteDates is running...")
    (let loop ((lstStr lstDate) (counter idxStart))
        (if (pair? lstStr)
            (begin    (WriteDate path-in template ext (car lstStr) counter)
                    (loop (cdr lstStr) (+ counter 1))
            )
            (begin    (display  counter)
                    (displayln " posters have been SUCCESSFULLY generated!")
    )    )    )
    (gimp-context-pop)
)
;-> WriteDates

Let us generate two posters dated from the list of dates '("10/15/2021" "10/11/2021")

Code:
(WriteDates "C:\\Tool\\Gimp\\forum\\gimp-forum.net\\WriteDate" "template" ".png" '("10/15/2021" "10/11/2021") 0)
;-> generates template00.png dated "10/15/2021" and template01.png dated "11/10/2021" in the target folder.
WriteDates is running...
file-out: C:\Tool\Gimp\forum\gimp-forum.net\WriteDate\target\template00.png date: 10/15/2021
file-out: C:\Tool\Gimp\forum\gimp-forum.net\WriteDate\target\template01.png date: 10/11/2021
2 posters have been SUCCESSFULLY generated!
(#t)

Take in consideration that, in the if that checks if the list of dates is not empty,
the Then and Else parts have more than one statement. We need to encapsulated them in begin.

If you read this thread until here, it will be a first step in the Script-Fu world of another era.
Would you also share your experimentation with ImageMagick according to the rich2005's bash file?
Regards.
Reply
#6
(10-15-2021, 08:53 PM)Gimphried Wrote:
  • DIR-SEPARATOR is "\\" in Windows
  • DIR-SEPARATOR is "/" in Linux

Not really. In Windows it is either, but 1) the console (.BAT) only accepts \, and the APIs return \, but APIs also accept / in their inputs. This avoids a lot of counting pairs of \\ (and on an AZERTY keyboard, the / is a lot easier to enter than the \).
Reply
#7
Hi Gimphried,
Like every year, I go back to my poster story. I actually didn't see your long answer last year.
So sorry for the delay and a big thank you for that!
And so I'll get right to it...
Best regard
Reply
#8
I test Imagemagick to but finaly I made with a script-fu and Gimphried help (thanks again).
Because I need reverse date format at begin of each file this is my final script.
So I change just size, font, color, position and output file name (remove the counter).
Perfect for me with an img2pdf script after to have both image and pdf files.

Code:
(define (WriteDate path-in template ext date counter)
   (let*    (    (filePoster    (string-append path-in DIR-SEPARATOR template ext))
               (strIdx (number->string counter))
               (strZidx (if (< counter 10) (string-append "0" strIdx) strIdx))
               (path-out (string-append path-in DIR-SEPARATOR "target" DIR-SEPARATOR))
               (file-out (string-append path-out strIdx "_" template ext))
               (posX 380) (posY 480)
               (imgDat        (car (gimp-image-new 1 1 RGB))) ; Empty poster
               (layerDat     (car (gimp-layer-new imgDat 1 1 RGB-IMAGE "layer_date" 100 LAYER-MODE-NORMAL-LEGACY)))
           )
       (gimp-image-insert-layer imgDat layerDat 0 0)
       (gimp-context-set-foreground '(255 255 255)) ; white
       (gimp-context-set-background '(255 255 255)) ; white
       (gimp-drawable-fill layerDat BACKGROUND-FILL) ; Empty white poster
       (let* ((layerPoster (car (gimp-file-load-layer 1 imgDat filePoster)))) ; load template
           (gimp-image-insert-layer imgDat layerPoster 0 0) ; as a layer to the empty poster
           (script-fu-util-image-resize-from-layer imgDat layerPoster) ; same size than the template
           (gimp-layer-resize-to-image-size layerDat)
           (display "file-out: ") (display file-out) (display " date: ") (displayln date)
           ; Write the date in posX, posY Sans font (private joke)
           (let* ((layerTxt (car (gimp-text-fontname imgDat layerPoster posX posY date 0 TRUE 40 POINTS "DejaVu Sans Bold"))))
               (gimp-floating-sel-anchor layerTxt)
       )    ) ; Anchor the floating selection to its associated drawable
       (let* ((layerSav (car (gimp-image-flatten imgDat)))) ; Save the dated poster
           (gimp-displays-flush)
           (gimp-file-save RUN-NONINTERACTIVE imgDat layerSav file-out file-out)
           (gimp-image-delete imgDat)        
)    )    )


(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "6 Oct. 2022" 20221006)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "20 Oct. 2022" 20221020)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "17 Nov. 2022" 20221117)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "1 Déc. 2022" 20221201)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "15 Déc. 2022" 20221215)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "12 Jan. 2023" 20230112)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "26 Jan. 2023" 20230126)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "9 Fév. 2023" 20230209)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "2 Mars 2023" 20230302)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "16 Mars 2023" 20230316)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "30 Mars 2023" 20230330)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "13 Avr. 2023" 20230413)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "4 Mai 2023" 20230504)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "25 Mai. 2023" 20230525)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "8 Juin 2023" 20230608)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "22 Juin 2023" 20230622)
(WriteDate "/home/carl/Images/Hibou/" "Jazz au Hibou" ".png" "6 Juil. 2023" 20230706)
Reply


Forum Jump: