# Programa d'aprenentatge de l'Script-Fu

En aquest curs, començarem amb una introducció als fonaments de «Scheme» necessaris per a utilitzar l'Script-Fu. Llavors construirem un script pràctic que pugueu afegir a la caixa d'eines dels scripts. L'script requereix un text per a l'usuari, i es crea una imatge nova que s'adapta a la mida del text. Aleshores, es millora l'script afegint un marc al voltant del text. Es conclou amb maneres d'augmentar el vostre coneixement de l'Script-Fu.

Aquesta secció és una adaptació d'un programa d'aprenentatge escrit per Mike Terry per al GIMP 1 Manual d'usuari.

## Coneixent l'Scheme

### Inicia amb l'Scheme

L'esquema és un dialecte de la família Lisp de llenguatges de programació. El GIMP utilitza TinyScheme, que és un intèrpret lleuger d'un subconjunt de l'anomenat estàndard R5RS.

El primer que aprendrem és:

> Totes les declaracions en Scheme van entre parèntesis ().

La segona cosa que heu de saber és:

> El nom d'una funció/operador és sempre el primer element en el parèntesi, i la resta són paràmetres de la funció.

Tanmateix, no tot el que està tancat entre parèntesis és una funció — també poden ser articles d'una llista — es veurà més tard. Aquesta notació es refereix a la notació de prefix, ja que la funció hi és abans que tota la resta. Si esteu familiaritzats amb la notació de prefix, o teniu una calculadora que utilitza notació polonesa inversa (com moltes calculadores HP), no hauríeu de tenir problemes per a adaptar-vos a la formulació d'expressions en «Scheme».

La tercera cosa a entendre és:

> Els operadors matemàtics també es consideren funcions, i per tant apareixen en primer lloc quan s'escriuen les fórmules matemàtiques.

Això és conseqüència lògica de la notació de prefix.

### Exemples de notacions de prefix, infix i sufix

Alguns exemples ràpids que il·lustren les diferències entre notacions de prefix, infix, i sufix. Vam sumar 1 i 23 a la vegada:

- Notació de prefix: `+ 1 23` (Així és com ho vol l'Scheme)

- Notació de sufix: `1 + 23` (és la manera natural d'escriure)

- Notació de sufix: `1 23 +` (utilitzada per a moltes calculadores HP)

### Pràctiques de Scheme

En el GIMP seleccioneu Filtres Desenvolupament Script-Fu Consola Script-Fu des del menú principal. Això iniciarà la finestra de la consola Script-Fu, que permet treballar interactivament a Scheme.

### La finestra de la Consola de Script-Fu

En la part inferior d'aquesta finestra hi ha un camp d'entrada amb el títol Ordre actual. Ací podeu provar interactivament les ordres Scheme. Comenceu amb alguna cosa fàcil i hi afegiu alguns nombres:

    (+ 3 5)

Teclejant aquesta seqüència i prémer Retorn, s'obté el resultat esperat: 8, al centre de la finestra.

Ús de la consola Script-Fu.

La funció + pot prendre més arguments, de manera que podem afegir més d'un nombre:

    (+ 3 5 6)

I, com era d'esperar, s'obté 14.

Fins ací, tot bé — escrivim una instrucció Scheme i s'executa immediatament a la finestra de la consola Script-Fu. Ara avís de precaució…

### Aneu amb compte amb els parèntesis extres

Si sou com jo, estareu acostumats a utilitzar els parèntesis extres, com quan teclegeu una equació matemàtica complexa i en voleu separar les parts amb parèntesis, i així fer-la més clara. En l'Scheme, cal ser acurat i no inserir aquests parèntesis extres de manera incorrecta. Per exemple, dir que volem sumar 3 al resultat de sumar 5 més 6 i després sumar-hi 7:

    3 + (5 + 6) + 7 = ?

Sabent que l'operador `+` pot utilitzar una llista de nombres per a sumar, podríeu estar temptats a escriure:

    (+ 3 (5 6) 7)

Tanmateix, això és incorrecte. Recordeu que cada declaració en Scheme comença i acaba amb parèntesi, així que l'intèrpret Scheme pensarà que intenta cridar una funció anomenada 5 en el segon grup de parèntesi, en lloc de sumar aquests nombres abans de sumar-hi el 3.

La forma correcta d'escriure-la seria:

    (+ 3 (+ 5 6) 7)

### Assegureu-vos de tenir l'espai apropiat

Si esteu familiaritzats amb altres llenguatges de programació, com el C/C++, Perl o Java, se sap que no necessitareu espais blancs al voltant dels operadors matemàtics per a formar una expressió:

            3+5, 3 +5, 3+ 5

Aquestes formulacions són acceptades per C / C ++, Java o Perl. Però aquest no és el cas de l'Scheme, ja que per a ser correctament interpretat ha de tenir un espai després d'un operador matemàtic o qualsevol altra funció o operador.

Practiqueu una mica amb operacions matemàtiques simples en la consola de Script-Fu fins que estigueu còmodes amb aquests conceptes inicials.

## Variables i funcions

Ara que sabem que totes les declaracions en Scheme estan entre parèntesis, i que el nom de la funció o operador va primer, hem d'aprendre a crear i utilitzar variables, i com crear i utilitzar funcions. Començarem amb les variables.

### Declaració de variables

Encara que hi ha un parell de mètodes diferents per a declarar variables, el preferit és l'ús de l'estructura `let*`. Si esteu familiaritzats amb altres llenguatges de programació, aquesta construcció és equivalent a definir una llista de variables locals i una extensió en la qual estan actives. Com a exemple, per a declarar dues variables, a i b, inicialitzades respectivament a 1 i 2, escriviu:

            (let*
               (
                  (a 1)
                  (b 2)
               )
               (+ a b)
            )

o, en una línia:

    (let* ( (a 1) (b 2) ) (+ a b) )

Haureu de posar tot això en una línia si esteu utilitzant la finestra de la consola. Tanmateix, voldreu adoptar una pràctica similar de sagnat per a ajudar a fer els vostres scripts més llegibles. Parlarem una mica més d'això en la secció sobre l'espai blanc.

Això declara dues variables locals, a i b, inicialitzades, que mostren la suma de les dues variables.

### Què és una variable local?

Notareu que escrivim la suma `(+ a b)` dins el parèntesi de l'expressió `let*`, i no després d'ella.

Això es deu al fet que la declaració `let*` defineix una àrea en el vostre script on les variables són utilitzables; si teclegeu la declaració `(+ a b)` després de la declaració `(let* …)`, obtindreu un error, ja que les variables declarades són només vàlides en el context de la declaració `let*`. Això és el que els programadors en diuen variables locals.

### La sintaxi general del `let*`

La forma general d'una declaració `let*` és:

            (let* ( variables )
              expressions )

on les variables es declaren entre parèntesis, per exemple, `(a 2)`, i les expressions són qualsevol expressió vàlida de l'Scheme. Recordeu que les variables declarades són només vàlides dins la declaració `let*`, aquestes són variables locals.

### Espai blanc

Anteriorment hem esmentat que probablement vulgueu utilitzar el sagnat per a ajudar a aclarir i organitzar els vostres scripts. Això és una bona política a adoptar, i no és un problema per a l'Scheme, ja que l'intèrpret Scheme ignora l'espai en blanc, i es pot aplicar per a ajudar a aclarir i organitzar el codi dins un script. Però si esteu treballant en la finestra de la consola de Script-Fu, haureu d'introduir una expressió sencera en una línia, entre l'obertura i el tancament del parèntesi.

### Assigna un valor nou a una variable

Una vegada que heu iniciat una variable, podríeu necessitar canviar aquest valor més endavant en l'script. Utilitzeu la declaració `set!` per a canviar el valor de la variable:

            (let* ( (theNum 10) ) (set! theNum (+ theNum theNum)) )

Intenteu endevinar què farà la declaració, llavors, introduïu-la en la consola de Script-Fu.

### Funcions

Ara que entenem les variables, treballem amb algunes funcions. Declareu una funció amb la següent sintaxi:

            (define
               (
                  name
                  param-list
               )
               expressions
            )

on el nom és el nom assignat a aquesta funció, llista de paràmetres és una llista limitada de noms de paràmetres, i expressions és una sèrie d'expressions que la funció executa quan la crida. Per exemple:

    (defineix (AddXY inX inY) (+ inX inY) )

`AddXY` és el nom de la funció, `inX` i `inY` són les variables. Aquesta funció agafa els dos paràmetres i els suma.

Si heu programat en un altre llenguatge (com C/C++, Java, Pascal, etc.), haureu notat un parell de coses que no hi són en la definició d'aquesta funció en comparació amb altres llenguatges de programació.

- Primer, observeu que els paràmetres no tenen un tipus (és a dir, no es declaren com a cadenes, o enters, etc.). Scheme és un llenguatge sense tipus. Això és pràctic i permet una escriptura més ràpida dels scripts.

- Segon, no hem de preocupar-nos de com retornar els resultats de la nostra funció — l'última declaració és el valor retornat quan es crida la funció. Escriviu la definició de la funció en la consola, llavors intenteu alguna cosa com:

      (AddXY (AddXY 5 6) 4)

## Llistes, llistes i més llistes

Després de veure les variables i funcions, ara ve la difícil qüestió de les llistes Scheme.

### Definir una llista

Abans de parlar més sobre les llistes, heu de conèixer la diferència entre els valors atòmics i les llistes.

Ja heu vist els valors atòmics en inicialitzar les variables en la lliçó anterior. Un valor atòmic és un valor simple, és a dir, una variable amb un valor únic. Així, per exemple, es pot assignar a la variable `x` el valor simple de 8 a la següent declaració:

    (let* ( (x 8) ) x)

(Afegim l'expressió `x` al final per a mostrar el valor assignat a `x`, normalment no necessitareu fer això. Recordeu com opera el `let*` justament com una funció: el valor de l'última declaració és el valor retornat.)

Una variable també pot referir-se a una llista de valors, en lloc d'un valor simple. Per a assignar a la variable `x` la llista de valors 1, 3, 5, escrivim:

    (let* ( (x '(1 3 5))) x)

Intenteu teclejar ambdues declaracions en la consola de Script-Fu i veureu què passa. Quan teclegeu la primera declaració, respon amb el resultat:

    8

No obstant això, quan teclegeu l'altra declaració, respon amb el següent resultat:

    (1 3 5)

Quan respon amb el valor 8 vol dir que està informant que `x` conté el valor atòmic 8. Tanmateix, quan respon amb `(1 3 5)`, està informant que `x` no conté un valor simple, sinó una llista de valors. Recordeu que no hi ha cometes a la nostra declaració o en l'assignació de la llista, ni en el resultat mostrat.

La sintaxi per a definir una llista de valors és:

    '(a b c)

on `a`, `b`, i `c` són literals. Utilitzem l'apòstrof (`'`) per a indicar que el que segueix entre parèntesis és una llista de valors literals, en lloc d'una funció o expressió.

Una llista buida es pot definir com:

    '()

o simplement:

    ()

Les llistes poden contenir valors atòmics, així com altres llistes:

    (let*
       (
            (x
               '("GIMP" (1 2 3) ("is" ("great" () ) ) )
            )
        )
        x
    )

Recordeu que després del primer apòstrof, ja no cal utilitzar un apòstrof en la definició de les llistes internes. Proveu aquesta declaració en la consola de Script-Fu i mireu què retorna.

Notareu que el resultat retornat no és una llista de valors simples, sinó més aviat una llista d'un literal `("GIMP")`, d'una llista `(1 2 3)`, etc.

### Com es representen les llistes

És útil pensar que les llistes estan compostes d'un cap i d'una cua. El cap és el primer element de la llista i la resta és la cua. Veureu per què és important quan considerem com afegir llistes i com accedir als elements de la llista.

### Creació de llistes per concatenació (la funció Cons)

Una de les funcions que trobareu més sovint és la funció `cons`. Pren un valor i la situa al capdavant del segon element, una llista. En la secció prèvia, s'aconsella que imagineu les llistes com constituïdes d'un cap i d'una cua. Doncs bé, la funció `cons` afegeix un element al cap de la llista. Així podeu crear una llista de la següent manera:

    (cons 1 '(2 3 4) )

El resultat és la llista `(1 2 3 4)`.

També podreu crear una llista amb un element:

    (cons 1 () )

Podeu utilitzar variables prèviament declarades en lloc de literals.

### Definiu una llista amb la funció `list`

Per a definir una llista composta de literals o, prèviament, variables declarades, utilitzeu la funció `list`:

    (llista 5 4 3 a b c)

Això compondrà i retornarà una llista que conté els valors de les variables `a`, `b` i `c`. Per exemple:

            (let*  (
                      (a 1)
                      (b 2)
                      (c 3)
                   )

                   (list 5 4 3 a b c)
            )

Aquest codi crea la llista `(5 4 3 1 2 3)`.

### Accediu als valors d'una llista

Per a accedir als valors d'una llista, utilitzeu les funcions `car` i `cdr`, que retornen respectivament el primer element de la llista i la resta de la llista. Aquestes funcions trenquen l'estructura cap::cua que s'ha esmentat abans.

### La funció `car`

`car` retorna el primer element de la llista (el cap de la llista). La llista ha de ser no nul·la (no buida). Així, el següent retorna el primer element de la llista:

    (car '("first" 2 "third"))

que és:

    "primer"

### La funció `cdr`

`cdr` retorna la resta de la llista després del primer element (la cua de la llista). Si només hi ha un element de la llista, retorna una llista buida.

    (cdr '("first" 2 "third"))

retorna:

    (2 "third")

mentre que la següent:

    (cdr '("one and only"))

retorna:

    ()

### Accediu a altres elements d'una llista

Bé, entesos, podem accedir al primer element i a la resta de la llista, però com ho fem per a accedir al segon, tercer o altres elements de la llista? Hi ha diverses maneres d'accedir-hi, per exemple, el cap del cap d'una cua d'una llista (`caadr`), la cua de la cua d'una llista (`cddr`), etc.

La convenció bàsica és fàcil: «a» i «d» representen els caps i les cues de la llista. Així

    (car (cdr (car x) ) )

es podria escriure:

    (cadar x)

Per a tenir pràctica amb les funcions d'accés a llistes, intenteu escriure el següent (en una sola línia si utilitzeu la consola); utilitzeu diferents variacions de `car` i `cdr` per a accedir als diferents elements de la llista:

            (let* (
                     (x  '( (1 2 (3 4 5) 6)  7  8  (9 10) )
                     )
                  )
                  ; place your car/cdr code here
            )

Intenteu accedir al número 3 de la llista utilitzant només dues crides de la funció. Si podeu fer això, esteu en el camí per a esdevenir un mestre de Script-Fu.

A Scheme, un punt i coma (`;`) marca l'inici d'un comentari. L'intèrpret de l'script ignora això, i tot el que el segueix en la mateixa línia, de manera que podeu utilitzar-lo per afegir comentaris per refrescar la memòria quan mireu l'script més tard.

## El vostre primer codi de Script-Fu

No necessiteu parar i respirar? No? Bé, doncs llavors procedirem amb la quarta lliçó, el vostre primer codi de Script-Fu.

### Creació d'un script: un quadre de text

Una de les operacions més comunes que es realitza amb el GIMP és crear un quadre amb algun text dins per a una pàgina web, o un logotip. Però quan es comença, mai no se sap la mida adequada de la imatge, ni l'espai que ocuparà el text amb la mida de la lletra.

Aquest problema pot ser resolt i automatitzat amb l'Script-Fu.

Crearem un script anomenat «Text Box», que crearà una imatge amb la mida correcta, ajustada a una línia de text que l'usuari ha introduït. També deixarem a l'usuari triar la lletra tipogràfica, la seva mida i el color del text.

### Editeu i deseu els vostres scripts

Fins ara hem estat treballant a la consola Script-Fu. Ara, però, passarem a editar fitxers script. Els fitxers script han de ser fitxers de text senzill que podeu editar en un editor de text o codi. El nom que poseu no és tan important, tret de poder reconèixer l'script. Hauríeu de donar al fitxer script l'extensió .scm.

On col·loqueu els scripts és una qüestió de preferència. A les preferències de carpetes del GIMP podeu veure en quines carpetes el GIMP cerca els scripts. També és possible afegir una carpeta nova allà. La carpeta on el GIMP emmagatzema els seus propis scripts normalment no és la millor opció per als scripts, però per a la resta no dubteu a triar el que més us convingui.

### Les necessitats essencials

Cada script de Script-Fu defineix almenys una funció, que és la funció principal de l'script. És on fa la feina.

Cada script ha de registrar-se també en la base de dades de procediments, de manera que s'hi pugui accedir amb el GIMP .

Es defineix primer la funció principal:

            (define (script-fu-text-box inText inFont inFontSize inTextColor))

Ací hem definit una nova funció anomenada `script-fu-text-box` que pren quatre paràmetres que més tard correspondran a algun text, un tipus de lletra, la mida de la lletra i el color del text. La funció actualment està buida i per tant no fa res. Fins ara tot bé — res de nou, res d'elegant.

### Convencions de nomenclatura

Les Convencions de nomenclatura de l'Scheme prefereixen minúscules amb guions i s'han respectat dins el nom de la funció. No obstant això, es parteix de la convenció amb els paràmetres. Es volen noms més descriptius pels paràmetres i variables, i s'hi afegeix el prefix in als paràmetres, així es pot veure ràpidament quins valors entren en l'script, en comptes dels que es creen en ell. S'utilitza el prefix the per a les variables definides en l'script.

És la convenció del GIMP per a anomenar les funcions del vostre script `script-fu-abc`, perquè així apareixeran en la base de dades de procediments, totes elles es mostraran sota l'Script-Fu quan s'estiguin llistant les funcions. Això també ajuda a distingir-les dels connectors.

### Registre de la funció

Ara, registrem la funció amb el GIMP. Això es fa cridant la funció `script-fu-register`. Quan el GIMP llegeixi un script, executarà aquesta funció, que registrarà l'script en la base de dades de procediments. Podeu situar aquesta funció on vulgueu dins el vostre script, però normalment se situa al final, després de la resta de les línies del codi.

Aquest és el llistat de registre d'aquesta funció (s'explicaran tots aquests paràmetres de seguida):

      (script-fu-register
        "script-fu-text-box"                        ;function name
        "Text Box"                                  ;menu label
        "Creates a simple text box, sized to fit\
          around the user's choice of text,\
          font, font size, and color."              ;description
        "Michael Terry"                             ;author
        "copyright 1997, Michael Terry;\
          2009, the GIMP Documentation Team"        ;copyright notice
        "October 27, 1997"                          ;date created
        ""                                      ;image type that the script works on
        SF-STRING      "Text"          "Text Box"   ;a string variable
        SF-FONT        "Font"          "Charter"    ;a font variable
        SF-ADJUSTMENT  "Font size"     '(50 1 1000 1 10 0 1)
                                                    ;a spin-button
        SF-COLOR       "Color"         '(0 0 0)     ;color variable
      )
      (script-fu-menu-register "script-fu-text-box" "<Image>/File/Create/Text")

Si deseu aquestes funcions en un fitxer de text amb el sufix `.scm` al directori dels vostres scripts, seleccioneu Filtres Script-Fu Actualitza els scripts, aquest script nou apareixerà com Fitxer Crea Text Text Box.

Si crideu aquest nou script, no farà res, per descomptat, però podeu veure les anotacions que es van fer quan es va registrar l'script (més informació del que es va fer, es mostrarà després).

Finalment, si obriu el Navegador de procediments (Ajuda Navegador de procediments), veureu que l'script apareix en la base de dades.

### Passos per a registrar l'script

Per a registrar l'script en el GIMP, es cridarà la funció `script-fu-register`, s'ompliran els set paràmetres requerits i s'hi afegiran els nostres paràmetres, junt amb una descripció i els valors per defecte de cada paràmetre.

Els paràmetres requerits

- El nom de la funció que es defineix. Això és la crida de la funció quan es crida el nostre script (el punt d'entrada a l'script). És important perquè es poden definir funcions addicionals sota el mateix fitxer, i el GIMP necessita saber quines d'aquestes funcions crida. En aquest exemple, només es defineix una funció, «text-box», que s'ha registrat.

- L'etiqueta del menú és el nom que es mostrarà al menú. Per especificar la ubicació, vegeu .

- Una descripció del vostre script, que es mostrarà en el navegador de procediments.

- El vostre nom (l'autor de l'script).

- Informació dels Drets d'autor.

- La data en què es va fer l'script, o la data de la darrera revisió.

- Els tipus d'imatges amb què treballa l'script. Podrien ser: RGB, RGBA, GRAY, GRAYA, INDEXED, INDEXEDA. O no podrien ser cap d'elles, en aquest cas, s'està creant una imatge i no cal establir-ne el tipus.

### Registre dels paràmetres de l'script

Una vegada que s'han llistat els paràmetres requerits, cal precisar quins són els que corresponen amb les necessitats del nostre script. En llistar aquests paràmetres, es donen indicacions del tipus que són; això és pel diàleg que apareix quan l'usuari selecciona l'script. També es poden proporcionar valors per defecte.

Aquesta secció del procés de registre té el següent format:

Tipus de paràmetre | Descripció | Exemple
--- | --- | ---
`SF-IMAGE` | Si el vostre script opera en una imatge, hauria de ser el primer paràmetre després dels paràmetres requerits. El GIMP transmetrà una referència a la imatge en aquest paràmetre. | 3
`SF-DRAWABLE` | Si el vostre script opera sobre una imatge oberta, hauria de ser el segon paràmetre després del paràmetre `SF-IMAGE`. Es refereix a la capa activa. El GIMP transmetrà una referència a la capa activa en aquest paràmetre. | 17
`SF-VALUE` | Accepta nombres i cadenes de caràcters. Tingueu en compte que les cometes han d'estar precedides pel caràcter d'escapament, per la qual cosa és millor utilitzar `SF-STRING`. | 42
`SF-STRING` | Accepta cadenes de caràcters. | «Un text»
`SF-COLOR` | Indica que un color es requereix en aquest paràmetre. | '(0 102 255)
`SF-TOGGLE` | Es mostra una casella de selecció, per a obtenir un valor booleà. | TRUE o FALSE (Vertader o Fals)

### Registre la ubicació del menú

Un cop hàgim registrat el nostre script, hem de dir-li al GIMP on s'ha de trobar en el menú.

La millor ubicació del menú de l'script depèn de la seva funció. La majoria dels scripts es troben als menús dels Filtres i Colors.

Per a l'script actual que crea una imatge nova escollim un submenú de Fitxer Crea. Això és el que fa la línia amb la funció `script-fu-menu-register`. Així hem registrat el nostre script de caixa de text ací: Fitxer Crea Text Caixa de text .

Si us adoneu, el submenú Text en el menú Fitxer Crea no hi era quan vam començar el —GIMP que crea automàticament qualsevol menú que no existeixi.

El menú de l'script.

## Afegeix funcionalitats addicionals

Continueu amb la nostra formació i afegiu alguna funcionalitat al nostre script.

### Crea una imatge nova

En la lliçó anterior, es va crear una funció buida i es va registrar en el GIMP. En aquesta lliçó, es vol proporcionar funcionalitat a l'script, es vol crear una imatge nova, afegir-li text de l'usuari i redimensionar la imatge per a adaptar-la exactament al text.

Una vegada que sàpigueu establir variables, definir funcions i accedir als membres de la llista, la resta és baixada — tot el que heu de fer és familiaritzar-vos amb les funcions disponibles a la base de dades de procediments del GIMP i cridar-les directament. Obriu el .

Comenceu fent una imatge nova. Creareu una nova variable, `theImage`, habilitada al resultat de cridar la funció `gimp-image-new` integrada al GIMP.

Com podeu veure al navegador de base de dades, la funció `gimp-image-new` pren tres paràmetres — l'amplada de la imatge, l'alçada i el tipus d'imatge. Com que més tard canviarem la mida de la imatge per adaptar-la al text, farem una imatge RGB de 10×10 píxels. Emmagatzemarem l'amplada i les mides de la imatge en algunes variables, també ens hi referirem i les manipularem més endavant a l'script.

            (define (script-fu-text-box inText inFont inFontSize inTextColor)
            (let*
                  (
                     ; define our local variables
                     ; create a new image:
                     (theImageWidth  10)
                     (theImageHeight 10)
                     (theImage (car
                                    (gimp-image-new
                                     theImageWidth
                                     theImageHeight
                                     RGB
                                    )
                               )
                     )
                     (theText)     ;a declaration for the text
                                   ;we create later

Nota: utilitzem el valor `RGB` per a especificar que la imatge és una imatge `RGB`. Es podria utilitzar també `0`, però `RGB` és més descriptiu quan donem una ullada el codi.

També us hauríeu d'adonar que agafem el cap del resultat de la crida de la funció. Això podria semblar estrany, perquè la base de dades ens diu explícitament que retorna només un valor: l'ID (identificador) de la imatge recentment creada. Tanmateix, totes les funcions del GIMP retornen una llista, encara que només hi hagi un element en la llista, així que necessitem aconseguir el cap de la llista.

### Afegeix una capa nova a la imatge

Ara que tenim una imatge, necessitem afegir-li una capa. Cridarem la funció `gimp-layer-new` per a crear la capa, passant-li l'ID de la imatge que hem creat. (A partir d'ara, en lloc de llistar la funció completa, només llistarem les línies que estem afegint. Podeu veure l'script complet ací). Ja que hem declarat les variables locals que utilitzarem, també tancarem els parèntesis al final de les nostres declaracions de les variables:

            ;create a new layer for the image:
               (theLayer
                         (car
                              (gimp-layer-new
                               theImage
                               theImageWidth
                               theImageHeight
                               RGB-IMAGE
                               "layer 1"
                               100
                               LAYER-MODE-NORMAL
                              )
                          )
                )
             ) ;end of our local variables

Una vegada tinguem la capa nova, cal afegir-la a la imatge:

            (gimp-image-add-layer theImage theLayer 0)

Ara, només per diversió, es veuran els fruits del vostre treball fins ací, afegint aquesta línia per a mostrar la imatge nova i buida:

    (gimp-display-new theImage)

Deseu la vostra feina, seleccioneu Filtres Script-Fu Actualitza els scripts, executeu l'script i hi apareixerà una nova imatge. Probablement conté brossa (colors aleatoris), perquè no s'ha esborrat. Ho farem més tard.

### Afegeix el text

Elimineu la línia que mostra la imatge (o poseu un comentari amb un (`;`) com el primer caràcter de la línia).

Abans d'afegir text a la imatge, necessitem seleccionar els colors del fons (background) i del primer pla (foreground), perquè així aparegui amb el color que l'usuari ha especificat. Utilitzarem les funcions gimp-context-set-back/foreground:

            (gimp-context-set-background '(255 255 255) )
            (gimp-context-set-foreground inTextColor)

Amb els colors seleccionats correctament, netegeu la brossa present en la imatge omplint la capa amb el color del fons:

            (gimp-drawable-fill theLayer BACKGROUND-FILL)

Amb la imatge neta, ara està llesta per a afegir-hi un text:

            (set! theText
                          (car
                               (gimp-text-fontname
                                theImage theLayer
                                0 0
                                inText
                                0
                                TRUE
                                inFontSize PIXELS
                                "Sans")
                           )
            )

Encara que hi ha una crida de funció llarga, és bastant més senzill si repasseu els paràmetres mentre mireu l'entrada de la funció en el navegador de procediments. Bàsicament, es crea una nova capa de text i s'assigna a la variable `theText`.

Ara que tenim el text, podem prendre la seva alçada i amplada, i redimensionar la imatge i la capa d'imatge per a la mida del text:

            (set! theImageWidth   (car (gimp-drawable-width  theText) ) )
            (set! theImageHeight  (car (gimp-drawable-height theText) ) )

            (gimp-image-resize theImage theImageWidth theImageHeight 0 0)

            (gimp-layer-resize theLayer theImageWidth theImageHeight 0 0)

És possible que us pregunteu quina és la diferència entre un dibuixable i una capa. La diferència entre els dos és que un dibuixable és alguna cosa en el que s'hi pot dibuixar, incloses capes, però també canals, màscares de capa, la selecció, etc.; una capa és una versió més específica d'un dibuixable. En la majoria dels casos, la distinció no és important.

Amb la imatge enllestida, s'hi pot tornar a afegir la línia de visualització:

            (gimp-display-new theImage)

Deseu la feina, actualitzeu la base de dades i executeu el primer script!

### Neteja el senyal brut

Si intenteu tancar la imatge creada sense primer desar el fitxer, el GIMP preguntarà si voleu desar la feina abans de tancar-la. Pregunta això perquè la imatge està marcada com a bruta, o no desada. En el cas del vostre script, això és una molèstia per a les vegades que només feu una prova i no afegiu ni canvieu res en la imatge resultant; la vostra feina és fàcilment reproduïble en un script tan simple, així que té sentit desfer-se d'aquest senyal brut.

Per a fer això, es pot netejar el senyal brut després de mostrar la imatge:

            (gimp-image-clean-all theImage)

Això posa a 0 el comptador del senyal brut, fent-lo aparèixer com una imatge neta.

Afegir aquesta línia o no és qüestió del gust personal. S'utilitza en scripts que produeixin noves imatges, on els resultats són trivials, com en aquest cas. Si el vostre script és molt complicat, o si treballeu sobre una imatge existent, probablement no voldreu utilitzar aquesta funció.

## Estendre l'script «Text Box»

### Gestiona correctament l'acció de desfer

Quan feu un script, voldreu donar als usuaris l'opció de desfer les accions, ja que podrien cometre un error. Això és fàcil d'efectuar cridant les funcions `gimp-undo-push-group-start` i `gimp-undo-push-group-end` emmarcant el codi que manipula la imatge. El GIMP sap quan començar i parar les manipulacions enregistrades de la imatge, així, aquestes manipulacions es poden desfer més tard.

Si feu una imatge totalment nova, no té sentit utilitzar aquestes funcions perquè no s'està canviant una imatge existent. Malgrat tot, quan canvieu una imatge existent, segurament sí que voldreu utilitzar aquestes funcions.

Desfer un script funciona gairebé a la perfecció quan s'utilitzen aquestes funcions.

### Estendre l'script una mica més

Ara que heu creat un excel·lent i manejable script per a fer quadres de text, afegiu-li dues capacitats:

- Actualment, la imatge es redimensiona per a ajustar-se exactament al voltant del text, no hi ha lloc per a res més, com una ombra o un efecte especial (encara que molts scripts redimensionin la imatge quan calgui). Afegiu-li una memòria intermèdia al text i fins i tot deixeu que l'usuari especifiqui la quantitat de memòria intermèdia a un percentatge de la mida del text resultant.

- Aquest script es podria utilitzar fàcilment en altres scripts per a treballar amb text. Esteneu-lo perquè retorni la imatge i les capes, així, altres scripts podran recuperar aquest script i utilitzar la imatge i les capes.

### Modifica els paràmetres i la funció de registre

Per tal de permetre a l'usuari especificar la quantitat de memòria intermèdia, afegiu un paràmetre a la vostra funció i a la funció de registre:

      (define (script-fu-text-box inTest inFont inFontSize inTextColor inBufferAmount)
      (let*
            (
               ; define our local variables
               ; create a new image:
               (theImageWidth  10)
               (theImageHeight 10)
               (theImage (car
                              (gimp-image-new
                               theImageWidth
                               theImageHeight
                               RGB
                              )
                         )
               )
               (theText)          ;a declaration for the text
                                  ;we create later

               (theBuffer)        ;added

               (theLayer
                         (car
                             (gimp-layer-new
                              theImage
                              theImageWidth
                              theImageHeight
                              RGB-IMAGE
                              "layer 1"
                              100
                              LAYER-MODE-NORMAL
                             )
                         )
               )
            ) ;end of our local variables

       [Code here]
     )

      (script-fu-register
        "script-fu-text-box"                        ;function name
        "Text Box"                                  ;menu label
        "Creates a simple text box, sized to fit\
          around the user's choice of text,\
          font, font size, and color."              ;description
        "Michael Terry"                             ;author
        "copyright 1997, Michael Terry;\
          2009, the GIMP Documentation Team"        ;copyright notice
        "October 27, 1997"                          ;date created
        ""                                      ;image type that the script works on
        SF-STRING      "Text"          "Text Box"   ;a string variable
        SF-FONT        "Font"          "Charter"    ;a font variable
        SF-ADJUSTMENT  "Font size"     '(50 1 1000 1 10 0 1)
                                                    ;a spin-button
        SF-COLOR       "Color"         '(0 0 0)     ;color variable
        SF-ADJUSTMENT  "Buffer amount" '(35 0 100 1 10 1 0)
                                                    ;a slider
      )
      (script-fu-menu-register "script-fu-text-box" "<Image>/Font/Create/Text")

### Afegeix el codi nou

Anem a afegir el codi en dos llocs: just abans de redimensionar la imatge i al final de l'script (per a retornar la nova imatge, la capa i el text).

Després d'obtenir l'alçada i l'amplada del text, cal redimensionar aquests valors basats en la quantitat de memòria intermèdia especificada per l'usuari. No es caurà en l'error de no considerar si el valor està en l'interval 0-100%, pel fet que no sigui vital i perquè no hi ha cap raó per la qual l'usuari no pugui donar un valor de 200% de memòria intermèdia.

            (set! theBuffer (* theImageHeight (/ inBufferAmount 100) ) )

            (set! theImageHeight (+ theImageHeight theBuffer theBuffer) )
            (set! theImageWidth  (+ theImageWidth  theBuffer theBuffer) )

Tot el que es fa ací és configurar la memòria intermèdia basada en l'alçada del text, i afegir-la dues vegades tant a l'alçada com a l'amplada de la vostra nova imatge. (S'afegeix dues vegades perquè la memòria intermèdia s'hi ha d'afegir a banda i banda del text).

Ara que s'ha redimensionat la imatge per a permetre una memòria intermèdia, caldrà centrar el text en la imatge. Això es fa movent-lo a les coordenades (x, y) del (`theBuffer`, `theBuffer`). Es va afegir aquesta línia després de redimensionar la capa i la imatge:

            (gimp-layer-set-offsets theText theBuffer theBuffer)

Tireu endavant i deseu el vostre script, i després intenteu actualitzar la base de dades.

Tot el que queda per a fer és retornar la nostra imatge, la capa i la capa del text. Després de mostrar la imatge, s'afegeix aquesta línia:

    (list theImage theLayer theText)

És la darrera línia de la funció, i fa que aquesta llista estigui disponible a altres scripts que desitgin utilitzar-la.

Per a utilitzar el vostre nou script del quadre de text en un altre script, es podria escriure alguna cosa com:

            (set! theResult (script-fu-text-box
                             "Some text"
                             "Charter" "30"
                             '(0 0 0)
                             "35"
                            )
            )
            (gimp-image-flatten (car theResult))

Felicitats, esteu en el camí cap al Cinturó Negre de Script-Fu!

## El vostre script i la vostra feina

### El que heu escrit

A continuació, l'script complet:

      (script-fu-register
                "script-fu-text-box"                        ;function name
                "Text Box"                                  ;menu label
                "Creates a simple text box, sized to fit\
                  around the user's choice of text,\
                  font, font size, and color."              ;description
                "Michael Terry"                             ;author
                "copyright 1997, Michael Terry;\
                  2009, the GIMP Documentation Team"        ;copyright notice
                "October 27, 1997"                          ;date created
                ""                              ;image type that the script works on
                SF-STRING      "Text"          "Text Box"   ;a string variable
                SF-FONT        "Font"          "Charter"    ;a font variable
                SF-ADJUSTMENT  "Font size"     '(50 1 1000 1 10 0 1)
                                                            ;a spin-button
                SF-COLOR       "Color"         '(0 0 0)     ;color variable
                SF-ADJUSTMENT  "Buffer amount" '(35 0 100 1 10 1 0)
                                                            ;a slider
      )
      (script-fu-menu-register "script-fu-text-box" "<Image>/File/Create/Text")
      (define (script-fu-text-box inText inFont inFontSize inTextColor inBufferAmount)
        (let*
          (
            ; define our local variables
            ; create a new image:
            (theImageWidth  10)
            (theImageHeight 10)
            (theImage)
            (theImage
                      (car
                          (gimp-image-new
                            theImageWidth
                            theImageHeight
                            RGB
                          )
                      )
            )
            (theText)             ;a declaration for the text
            (theBuffer)           ;create a new layer for the image
            (theLayer
                      (car
                          (gimp-layer-new
                            theImage
                            theImageWidth
                            theImageHeight
                            RGB-IMAGE
                            "layer 1"
                            100
                            LAYER-MODE-NORMAL
                          )
                      )
            )
          ) ;end of our local variables
          (gimp-image-insert-layer theImage theLayer 0 0)
          (gimp-context-set-background '(255 255 255) )
          (gimp-context-set-foreground inTextColor)
          (gimp-drawable-fill theLayer BACKGROUND-FILL)
          (set! theText
                        (car
                              (gimp-text-fontname
                              theImage theLayer
                              0 0
                              inText
                              0
                              TRUE
                              inFontSize PIXELS
                              inFont)
                          )
            )
          (set! theImageWidth   (car (gimp-drawable-width  theText) ) )
          (set! theImageHeight  (car (gimp-drawable-height theText) ) )
          (set! theBuffer (* theImageHeight (/ inBufferAmount 100) ) )
          (set! theImageHeight (+ theImageHeight theBuffer theBuffer) )
          (set! theImageWidth  (+ theImageWidth  theBuffer theBuffer) )
          (gimp-image-resize theImage theImageWidth theImageHeight 0 0)
          (gimp-layer-resize theLayer theImageWidth theImageHeight 0 0)
          (gimp-layer-set-offsets theText theBuffer theBuffer)
          (gimp-floating-sel-to-layer theText)
          (gimp-display-new theImage)
          (list theImage theLayer theText)
        )
      )

### El que s'obté

El resultat en la pantalla

Scripts-Fu Programa d'aprenentatge