
Gimp to wielki powód do dumy całego środowiska Open Source. Jest jednym z najlepszych graficznych narzędzi dla Linuxa. Jest to program do tworzenia i obróbki grafiki rastrowej. Również znakomicie sobie radzi przy tworzeniu obrazków dla stron WWW. Program działa w środowisku XFree86, choć istnieją wersję na inne platformy takie jak MS Windows, Mac etc.Wprowadzenie do Scheme dla użytkowników Gimpa
Spis treści
- 1. Wstęp
- 2. Podstawy
- 3. Fukcje
- 4. Zmienne
- 4.1. Operacje na zmiennych
- 4.1. Operacje na listach
- 4.3. Tablice
- 5 Pętle
- 6.Gimpowa PDB
- 7.Rejestrowanie skryptu
- 8. Hello World - prosty skrypcik
- 9. Zaznaczenia
1. Wprowadzenie
Jedną z ciekawszych właściwości Gimp'a jest fakt iż cała jego funkcjonalność może być oprogramowalna. Głównym językiem używanym do pisania skryptów w Gimp'ie jest pochodna Lispa - Scheme ( w najbliższej przyszłości ma być zastąpiony przez jeszcze bardziej okrojony język - tiny-Fu ). W tej częsci referatu postaram się przedstawić krótko ten stosunkowo prosty język programowania. Będą to niesetty tylko podstawy, ponieważ mimo swej prostoty język Scheme to dość potężne narzędzie.
2. Podstawy
W Scheme tak samo jak w lispie, wszystkie funkcje wywołujemy otaczając je nawiasami. Na początku wyrażenia podajemy nazwę funkcji, a następnie jej argumenty. Np.: suma 1 i 2 będzie wyglądała następująco:( + 1 2 )gdzie '+' to nazwa funkcji ( suma ), a 1 i 2 to jej argumenty. Wyrazenia takie mozemy dowolnie zagniezdzac np:( + 1 ( - 4 5 ) )oznacza 1 + ( 4 - 5 ) Tzw. "białe znaki" ( takie jak spacje czy tabulatory) nie mają znaczenia .
3. Funkcje
Poza funkcjami arytmetycznymi, Scheme ( jak każdy porządny język programowania ), ma wiele innncyh. Wszystkie odpalamy analogicznie do operatorow czyli:( funkcja arg1 arg2 ... )Aside from the four arithmetic functions that are represented through the symbols + - * / there are lots of other functions built into the language. All of them have the form(foo param1 param2 ...)Własne funkcje możemy definiowac za pomoca slowa kluczowego define. Przykladowo wyrazeniem:( define ( kwadrat x ) ( * x x ) )tworzymy funkcję podnoszącą liczbę do kwadratu, z której możemy skorzystać w sposób następujący:( kwadrat 3 )( a ile to bedzie ?!? ) ;)
4. Zmienne i listy
Zmienne deklarujemy i ustawiamy za pomocą słowa kluczowego set!. Zmienne tak zadeklarowane będą globalne, lecz my jako programiści gimpa nie musimy się tym przejmować ( po każdym uruchomieniu środowisko samo się czyści ). A oto i kilka przypisań:(set! zielony 4352 ) (set! kat_w_radianach ( * 3.141 ( / 60 180 ) ) )Podobnie jak w lispie kluczową rolę dla języka Scheme mają listy. Script-fu ( odmiana Scheme którą będziemy się zajmować ) nie jest wyjątkiem i również bardzo mocno wykorzystuje listy, np. przy zapisie liczb w systemie RGB ( red green blue ).'(255 127 0)to na przykład zapis koloru pomarańczowego. Znak ' zawarty przed listą ma kluczowe znaczenie. Oznacza on cytowanie - czyli mówi on imterpreterowi by nie traktował listy jako wywołanie funkcji 255 ( ;) ), lecz raczej jako lista będąca stałą.Aby stworzyć zmienną nazwaną jako pomarancz z daną wartoscią, a następnie użyć jej jako tła piszemy co następuje:
(set! pomarancz '(255 127 0) ) (gimp-set-background-color pomarancz)Uwaga dla programujących w LISP'ie i pochodnych : W Scheme inną wartością oznacza się fałsz, listę pustą i wartość niezdefiniowaną
4.1. car, cdr i inne gady (*)
Lista, tak jak w lispie składa się "głowy" i "ogona". "Głową" nazywamy jej pierwszy element, a "ogonem" resztę listy. Dla przykładu dla listy '( 127 0 0 ) , głową jest 127, a ogonem lista (!) '( 0 0 ). Funkcja car zwraca nam właśnie "głowę", cdr "ogon". A oto i przykład użycia wymienionych funkcji:(set! kolor '( 127 0 1 ) ) ( 127 0 1 ) ( car kolor ) 127 (cdr kolor) ( 0 1 )Aby pobrac wartosc niebieskiego dla koloru trzeba sie troszke nameczyc stosujac kombinacje wczesniej poznanych funkcji:( car ( cdr ( cdr ( kolor ) ) ) )Zeby ulatwić prace programistom wprowadzono dodatkowe funkcje, takie jak: - cadr - cddr - caddr dzięki którym można w dosyć prosty sposób dostać sie do odpowiednich elementów. Dla przykładu nasza operacja w skrócie wygląda następująco:( caddr kolorW Script-fu funkcje zwracają wartości w postaci list, co czyni car jedną z najbardziej użytecznych funkcji. Np. dla funkcji gimp-new-image czy gimp-new-layer ( które użyjemy za chwilę ), wartością zwracaną jest tylko jeden element, ale ponieważ zawiera się on w liście, dostęp do niego mamy dzięki funkcji car
4.2. Zmienne lokalne (*)
Bardziej doświadczeni programiści używają zmiennych lokalnych, co jest oczywistym wyborem szczególnie w dużych i rozbudowanych funkcji lub w takich w których stosujemy rekurencję.Zmienne lokalne deklarujemy za pomocą słowa kluczowego let* tak jak w następującym przykładzie:
(let* ( ( a 5 ) ( b 14 ) ( ( ( * a b ) ) ) )W naszym przykładzie zmienne a i b obowiązują tylko w obrębie nawiasów okaląjacych funkcję let*
4.3. Tablice
Dostęp do tablic realizowany jest poprzez konstrukcje:(set! tab (cons-array 4 'byte)) (aset a 2 42) (aref a 3)gdzie CONS-ARRAY tworzy tablicę, ASET wpisuje podaną wartość do tablicy, natomiast AREF zwraca zawartość odpowiedniej komórki tablicy.
5. Instrukcje sterujące
Jak każdy sznujący się język programowania, Scheme posiada ( co prawda mocno okrojone, ale za to bardzo funkcjonalne instrukcje sterujące. Jeśli chodzi o instrukcję warunkową to mamy:( if ( warunek ) ( jesli_warunek_spelniony ) ( jesli_warunek_nie_spelniony ))Jedyną pętlą obecną w script-fu jest while. Oto jej składnia:( while ( warunek ) ( dzialanie1 ) ( dzialanie2 ) )
6. PDB - gimpowa procedural database
Wszystkie funkcje z jakich możemy korzystać, by oprogramować GIMP'a są dostępne dzięki tzw. PDB ( procedural database ). Każda z procedur tam zawartych ma odpowienik w postaci funkcji scheme, np:( gimp-image-new 640 480 RGB )tworzy nowy obrazek w gimpie o rozmiarach 640x480 ( słodkie VGA :) ) z paletą kolorów RGB/Dla przykładu procedura gimp-image-new wygląda następująco:
i jak widać dostarcza nam wielu cennych informacji takich jak: - parametry - wartości zwracane - autor - etc.
7. Rejestrowanie skryptu w Script-Fu
Po tym jak już uda nam się napisać jakąś użyteczną funkcję ( co uczynimy niebawem ), aby móc jej używać, musimy zarejestrować ją w script-fu. Robimy to za pomocą funkcji script-fu-reqister. Oto cele rejestrowania funkcji:Ostatni punkt dokładnke oznacza, że skrypt stanie się integralną częścią Gimpa tak jak komendy wbudowane czy plug-in'y. Tak długo jak będzie zarejestrowany będziemy go mogli używać z wnętrza programu. Parametry przyjmowane przez script-fu-register możemy podzielić na dwie części. Pierwsza to te które zawsze muszą być podane. Są to:
- Wybór miejsca zadokowania skryptu w rozwijanych menu Script-fu
- Powiedzenie script-fu jaki typ parametrów skrypt pobiera i nadanie im domyślnych wartości
- Zarejestrowanie skryptu w PDB
Poza tym podajemy argumenty jakie przyjmuje skrpyt. Każdy parametr ma trzy atrybuty:
- Nazwa funkcji
- Umiejscowienie w menu.
- Krótki opis funkcji.
- Autor skryptu.
- Licencja.
- Data utworzenia.
- Lista obrazków dla których może być wywoływany ten skrypt. Dotyczy to tylko obrazków które już istnieją.
A oto przykład rejestracji skryptu ( ze wszystkimi możliwymi opcjami ):
Typ argumentu Typ danych Opis SF-IMAGE Wartość całkowita (id obrazka) Do pobrania id obrazka SF-DRAWABLE Wartość całkowita (id obszaru) Pobranie id obszaru SF-VALUE String Wartość wprowadzona SF-TOGGLE Wartość logiczna (TRUE lub FALSE) Do wprowadzania wartości logicznych SF-PATTERN String (Nazwa patternu) Pozwala wybrać pattern( deseń ) SF-ADJUSTMENT Lista (wart-startowa wart-min wart-max maly-krok duzy-krok [int=0 lub float=1] [slider=0 lub roll-box=1]) Tworzy suwak lub okienko do wprowadzania wartości SF-FILENAME String (nazwa pliku) Pozwala wybrać plik SF-STRING String Do wprowadzania stringów SF-FONT String ( nazwa fonta ) Pozwala wybrać czcionkę SF-COLOR Lisa (RGB) [0-255] Pozwala wybrać kolor SF-OPTION Lista stringów Pozwala wybrać wartość z listy SF-GRADIENT String (nazwa gradientu) Pozwala wybrać gradient
(script-fu-register "my-demo-box" "/kubek2k/Script-Fu/Demko..." "Do nothing" "Joe User" "Joe User" "August 2000" "" SF-ADJUSTMENT "SF-ADJUSTMENT (slider)" '( 30 1 2000 1 10 1 0) SF-ADJUSTMENT "SF-ADJUSTMENT" '(400 1 2000 1 10 1 1) SF-COLOR "SF-COLOR" '(255 0 255) SF-DRAWABLE "SF-DRAWABLE" 0 SF-FONT "SF-FONT" "" SF-GRADIENT "SF-GRADIENT" "Golden" SF-IMAGE "SF-IMAGE" 0 SF-OPTION "SF-OPTION" '("Option 1" "Option 2" "Option 3") SF-PATTERN "SF-PATTERN" "Wood" SF-STRING "SF-STRING" "Testowy String" SF-TOGGLE "SF-TOGGLE" TRUE SF-VALUE "SF-VALUE" "0" SF-FILENAME "SF-FILENAME" "/")
7.1. Umieszczanie skryptu w menu
Jak wiemy umiejscowienie skryptu w menu określa argument 2. W naszym przypadku jest to pasek narzędziowy, ale mamy też inne możliwości. Nie podając na początku ścieżki specjalnej sekwencji umieszczmy swoje skrypty w głównym oknie Gimpa. Możemy też podać <Image> co będzie oznaczać że skrypt będzie się znajdował w menu okienka z obrazkiem ( najlepszy wybór ).
8. Zaznaczenia
Wklejając coś ze schowka resultat nie jest wprowadzany bezpośrednio na warstwę, lecz znajduje się w tzw. warstwie tymczasowej. Możemy sobie manipulować tą warstwą ile tylko chcemy do czasu aż nie wkleimy czegoś nowgo lub jej nie zaktwiczymy ( symbol kotwicy ).
8.1. Kopiowanie zaznaczonego obszaru
Aby dokonać skopiowania zaznaczonego obszaru, używamy funkcji gimp-edit-copy. Po takiej operacji całe zaznaczenie znajdzie się w buforze który możemy następnie wykorzystać, na przykład jako nową warstwę w rysunku.
9. Hello World - pisanie po obrazku
Pierwszym skryptem który wykonamy będzie prościutki ( tak się wydaje ) skrypt piszący nam po obrazku dowolny tekst i tworzący cień dla niego. Rozpiszmy sobie kroki:Teraz należy się zastanowić czy to wszystko ( ;) ) i czy jesteśmy to w stanie uczynić bez ingerencji użytkownika. Pierwszy krok wygląda na prosty - szukamy zatem funkcji która będzie w stanie nam pomóc w wypisywaniu tekstu na obrazku i ... znajdujemy ( gimp-text-fontname ). Wygląda na to że będziemy potrzebować: numeru obrazka ( o to zadba program ), umiejscowienia nowej warstwy ( to nie jest aż takie istotne ), wielkości i kroju czcionki ( tym zajmie się użytkownik ). Kiedy już zwalilismy większość pracy na innych ( ;) ) testujemy nową procedurę z pomocą konsoli ( jest ona osiągalna z menu Dodatki->Script-Fu->Script-Fu console... ).
- Utworznie napisu takiego jaki chcemy
- Stworzenie jego kopii
- cieniowanie z pomocą kopii
Następnym krokiem który powinniśmy uczynić to stworzenie kopii naszego napisu. Posłużymy się tu operacją ( gimp-layer-copy ) - funkcja ta jest stosunkowo prosta - jej wywołanie polega na podaniu kopiowanej warstwy i kanału alpha ( to nie jest dla nas istotne ). Niestety brak duplikacji warstw w script-fu zmusza nas do dodania kopii do obrazka. Uważnie szukając odnajdujemy ( gimp-image-add-layer ). Podajmy jej numerek obrazka, warstwy do dodania i pozycję nowej warstwy.
Super - mamy dwie kopie stworzonego tekstu, ale co z tym zrobić? Słuszne pytanie - tutaj musimy posłużyć się wrodzonym instynktem i zastanowić się jak cień może wyglądać. Autor po przeczytaniu jednego z podręczników do Gimp'a ( bo sam oczywiście nie był na tyle inteligentny by na to wpaść ), dowiedział się, że jednym z lepszych sposobów na stworzenie efektownego cienia jest wprowadzenie tak zwanego zakłócenia do obrazka ( ang. noise ). Chcąc to uczynić posłużymy się tzw. rozmyciem Gaussa ( funkcja ( plug_in_gauss ) ). Następnie chcąc wmówić użytkownikowi że znajduje się w trzecim wymiarze, przesuwamy nieco rozmyta warstwę względem pierwotnej ( funkcja ( gimp-layer-translate ) ). Dobrze, ale jak ma wyglądać taki skrypt?? Oto i on:( define ( hello-world image warstwa text font-size font ) ( let* ( ( nasztext ( car ( gimp-text-fontname image -1 ( / ( car ( gimp-image-width image ) ) 2 ) ( / ( car ( gimp-image-height image ) ) 2 ) text 0 TRUE font-size 1 font ) ) ) ( kopia ( car (gimp-layer-copy nasztext 1 ) ) ) ) ( gimp-image-add-layer image kopia 0 ) ( plug-in-gauss 1 image kopia 3 3 0 ) ( gimp-layer-translate kopia 3 3 ) ( gimp-image-raise-layer image nasztext ) ( gimp-image-merge-down image nasztext 0 ) ( gimp-displays-flush ) ) ) (script-fu-register "hello-world" _"Źródło skryptu/Script-Fu/kubek2k/Hello World..." "Wypisuje dowolny tekst i tworzy cien..." "Jakub Janczak" "Jakub Janczak" "January 2005" "" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0 SF-STRING "Text" "Hello World!!!" SF-VALUE "Font-size" "14" SF-FONT "Fontname" "Arial" )
Użyte funkcje
wyjaśnienia wymagają jeszcze funkcje ( gimp-image-raise-layer ), ( gimp-image-merge-down ) i ( gimp-displays-flush ). Pierwsza odpowiada za wyniesienie warstwy pierwotnej nad rozmytą ( bez tego nie byłoby efektu ). Druga powoduje scalenie warstw. Trzecia powoduje wyświetlenie wszystkich zmian znajdujących się jeszce w buforach wewnętrznych Gimp'a. A oto i przykładowy obrazek wygenerowany skryptem:
Przykłady
Pierwszy z przykładów wymazuje co n-ty pikselowy pasek z obrazkaOstatni z przykładów kopiuje obrazy ze schowka do aktualnego obrazu w sposób losowy dobierając pozycję i kąt obrotu
Oto przykład działania skryptu:
;; ;; Skrypt do wymazywania co n-tej kolumny ;; Jakub Janczak ;; ;; (define (script-fu-wymaz-co-n img drawable n) (gimp-undo-push-group-start img) (let* ( (szer (car (gimp-drawable-width drawable))) (wys (car (gimp-drawable-height drawable))) ( x 0 ) ) ( (while (< x szer ) (gimp-rect-select img x 0 1 wys REPLACE FALSE 0) (gimp-edit-clear drawable) (set! x (+ x n)) ) ) ) (gimp-selection-none img) (gimp-undo-push-group-end img) (gimp-displays-flush) ) (script-fu-register "script-fu-wymaz-co-n" _"<Image>/Script-Fu/moje/Wymaz co n-ta kolumne..." "Wymazuje co n-ta kolumne" "Jakub Janczak" "GNU GPL" "9 sty 2005" "RGB* GRAY* INDEXED*" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0 SF-ADJUSTMENT "Every Nth Pixel" '(3 2 10 1 1 0 0) ;; ciekawa rzecz - tworzy dosyć wygodny suwak )'Źródło skryptu
Użyte funkcje:
( gimp-rect-select obraz x y szer wys operacja zmiekcz wsp_zmiekcz ) -worzy zaznaczenie prostokątne w p (x,y) o wysokości wys i szerokości szer. Trzeci argument to typ operacji ( przecięcie, dodanie, odjęcie ). Czwarty argument jest odpowiedzialny za zmiękczenie brzegów ( ustawienie go daje całkiem ciekawe efekty ).
( gimp-edit-clear obszar ) - czyści zaznaczony obszar
( gimp-selection-none obraz ) - wyłącza wszelkie zaznaczenia na obrazie
( gimp-displays-flush) pokazuje wszystkie zmiany na obrazkach ( tzw. flush )
Drugi omawiany skrypt tworzy efekt półprzezroczystej siatki. A oto przykład działania:Przed:
![]()
Po:
![]()
Po niewielkich zmianach w skrypcie możemy uzyskać jeszcze ładniejszą siatkę:
![]()
;; ;; Jakub Janczak ;; Tworzy ciekawy efekt półprzezroczystej siatki na zaznaczonej częsci obrazka ;; ;; (define (script-fu-grid-overlay img drawable color size) (define (draw-line drawable startx starty endx endy) (let ((line (cons-array 4 'double))) (aset line 0 startx) (aset line 1 starty) (aset line 2 endx) (aset line 3 endy) (gimp-pencil drawable 4 line) )) (gimp-undo-push-group-start img) (let* ((szer (car (gimp-drawable-width drawable))) (wys (car (gimp-drawable-height drawable))) (siatka (car (gimp-layer-new img szer wys RGB-IMAGE "grid" 100 NORMAL-MODE))) (sx 0) (sy 0) ) (gimp-layer-add-alpha siatka) (gimp-image-add-layer img siatka -1) (gimp-rect-select img 0 0 szer wys REPLACE FALSE 0) (gimp-edit-clear siatka) (gimp-palette-set-foreground color) (gimp-brushes-set-brush "pixel (1x1 square)") (while ( > sy wys) (set! sy (+ sy size)) (draw-line siatka 0 sy szer sy) ) (while (> sx szer ) (set! sx (+ sx size)) (draw-line siatka sx 0 sx wys) ) (gimp-layer-set-opacity siatka 25) (gimp-selection-none img) (gimp-undo-push-group-end img) (gimp-displays-flush) ) ) (script-fu-register "script-fu-grid-overlay" _"<Image>/Script-Fu/kubek2k/Dodaj przezroczysta siatke..." "Dodaje przezroczysta siatke" "Jakub Janczak" "Jakub Janczak" "Sty 2005" "RGB* GRAY* INDEXED*" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0 SF-COLOR _"Color" '(255 255 255) SF-VALUE _"Size" "10")' Źródło skryptu
Użyte funkcje:
( gimp-layer-new obraz szer wys paleta_warstwy nazwa_warstwy stopien_pokrycia sposób_scalenia ) - tworzy nową warstwę ( ważne aby paleta kolorów warstwy nie była bogatsza od palety obrazu ). Stopień pokrycia oznacza jak bardzo przezroczytsta będzie nowa warstwa.
( gimp-pencil obszar ilosc_wspolrzednych wspolrzedne ) - narzedzie rysuje ołówkiem po zadanych w 3. parametrze współrzędnych
( gimp-palette-set-foreground kolor ) - ustawia kolor wypełnienia
( gimp-layer-set-opacity wsp_przezroczystosci ) - ustawia współczynnik przezroczystości warstwy
Przy okazji zobaczyliśmy jak korzystamy z tablic i funkcji wewnętrznych w Scheme
Nazwa motylki pochodzi od pierwotnego przeznaczenia skryptu który miał symulować nalot chmary motyli ;). Obecnie służy np. do zaśnieżania obrazków ( śniegu mamy w tym momencie aż zanadto ;) ).
Kod programu:
( define ( motylki image warstwa n ) ( let* ( ( wys ( car ( gimp-image-height image ) ) ) ( szer ( car ( gimp-image-width image ) ) ) ( i 0 ) ) ( while ( < i n ) ( let* ( ( tmp ( car ( gimp-edit-paste warstwa 100 ) ) ) ( wystmp ( car ( gimp-drawable-height tmp ) ) ) ( szertmp ( car ( gimp-drawable-width tmp ) ) ) ) ( gimp-layer-set-offsets tmp ( rand ( - szer szertmp ) ) ( rand ( - wys wystmp ) ) ) ( gimp-drawable-transform-rotate tmp ( / ( rand 180 ) 6.28 ) 1 0 0 0 0 0 3 0 ) ( print i ) ( set! i ( + i 1 ) ) ) ) ( gimp-image-merge-visible-layers image 1 ) ) ) (script-fu-register "motylki" _"<Image>/Script-Fu/kubek2k/Motylki..." "Wrzuca n zaznaczen..." "Jakub Janczak" "Jakub Janczak" "January 2005" "" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0 SF-VALUE _"Size" "10")Źródło skryptu
Jedyne co wymaga wyjasnienia to funkcje:
( gimp-layer-set-offsets ) - funkcja ustalająca oległość warstwy od górnego lewego rogu obrazka
( gimp-image-merge-visible-layers ) - funkcja scala wszustkie widoczne warstwy
11. Materiały:
To wszystko - miłego Gimpowania!!!
Autor: Jakub Janczak. W ramach referatu z przedmiotu Obliczenia Symboliczne prowadzonych w Katedrze Informatyki AGH
Adres orginału http://student.uci.agh.edu.pl/~janczak/gimp-scheme/scheme.html