GIMP Script-fu: quick learning and writing a simple Scheme scripts (+ batch processing for free)
Membership
In this article you will learn how in the shortest possible time to learn the basics of scripting in GIMP in the language of the Scheme and proceed directly to the solution of simple practical problems. This material is intended only for those who are going to automate the routine processing of the here and now, not strongly going into details and without sacrificing precious time. Also, the article is not recommended to use as benefits Scheme separately from Script-fu. This is due to the simplistic style of programming in this material and no light other important facts which we are now concerned is much less than the speed of development.
Contents:
- is Short syntax the
- Variables the
- Functions the
- Lists the
- check the script in GIMP the
- coding the
- Conclusion
What do we need? the
What do we need?
English interface: it is enough to create the environment variable "LANG" with value "en". Why is it necessary? First, it will be easier to look for the conformity of the procedures interface objects. Secondly, I don't have to lead the team to two languages. Thirdly, in English on the Internet the most.
the Script-fu Console: Filters → Script-fu → Console. Here we will be able to test small pieces of code that need with the development of the language.
Explorer procedures: Help → Procedure Browser. Here you can easily find the function that performs the desired action and to read the full description (all well documented).
code Editor with highlighting and/or counting matching brackets. Will leave on your taste. I had Notepad++. But remember, the brackets will be a lot!
In the next few sections contain extracts from the first four documentation Script-fu and a bit of ad-libbing. It is strongly recommended to try running the examples below in the console.
brief syntax
- the function Name always comes first in parentheses, followed by its parameters. the
- Mathematical operators are also functions.
All expressions in Scheme should be surrounded by parentheses. the
the
(* (+ 1 2) (sqrt (- 13 4)) 10)
The latter will be deemed the result of the multiplication. As can be seen, the multiplication function is passed three arguments: the result of adding the result of the root extraction of the difference and the number. Note the number of brackets: they are everywhere compulsory. It can interfere, but it is always clear what is being computed.
-
the
- Function and each argument must be separated from each other by spaces.
(+ 1 2)
" — correct code, "(+1 2)
" — is not.-
the
- Everything that comes after the character "
;
" is a comment and is ignored.
Variables
Variables in Scheme are defined using the
let*
. General appearance:the
(let*
(
(variable value)
...
(variable value)
)
(expression)
...
(expression)
)
When compared with imperative languages, it is something like a Declaration of local variables. In other words, after the brackets, closes the
let*
, the variables cease to exist.Example:
the
(let*
(
(a 1)
(b (+ a 2))
)
(+ a b)
)
Another example:
(let*
( (x 9) )
(sqrt x)
)
Please note that even in the case when we define only one variable, external brackets, for a list of variables do not fall!
New value of the variable can be assigned using the
set!
:the
(set! the value variable)
Example:
the
(let*
( (a 42) (b 21) (x 0) )
(set! x (/ a b))
)
Options
Their functions can be defined by adding
define
:Value of the function is the result of the last command executed in the function code.
Also, the device can calculate the difference modules (). This can be done using the
abs
, but we will do a little more complicated:the
(define (difference x y)
(if (x y) (- x y) (- y x))
)
Here we used the
if
, which tests whether the first its argument, and based on this executes either the second or the third argument (the latter, as you can see, optional).Please note that the function can treat their arguments as variables, but it changes only their copy. You can verify this in the following way:
the
(let* ((a 3) (b -4)) (list (difference a b) a b))
(The
list
is used here to output multiple results — values of the function, the variable a
variable and b
, — and learn more about lists later). Run console and check that the variable values have not changed.Lists
To define the list, simply write (no commas):
the
'(0 1 1 2 3 5 8 13)
An empty list may be specified via the "
'()
", and "()
". The lists can contain atomic values, as well as other lists:the
(let*
(
(x
'("GIMP" (1 2 3) ("is" ("the great" () ) ) )
)
)
x
)
Because a single apostrophe we have already written, the inner lists to precede it optionally.
To add to the list another item you need to use the concatenation
cons
:the
(cons 1 '(2 3 4) )
It works equally well with an empty list ("
(cons 1 () )
" will give a list of one element).To create a list that contains the values of previously declared variables, you will need the
list
:the
(let* ( (a 1) (b 2) (c 3) )
(list a b c 4 5)
)
To understand the difference with the definition of the list using an apostrophe, replace "
(list a b c 4 5)
" to "'(a b c 4 5)
" and compare the output.It's all good, but how do you get the contents of the list? For this there are two functions. First,
car
, returns the head of list, that is the first element. The second, cdr
, returns the tail of the list, i.e. a list containing all elements except the first. Both functions assume the list is nonempty. Examples:the
(car '(1 2 3 4) )
(cdr '(1 2 3 4) )
(car '(1) )
(cdr '(1) )
Instead of repeatedly calling
car
and cdr
is useful to use functions of type caadr
, cddr
, etc. for Example, to get the second list item, write the following:the
(cadr '("first" "second") )
equivalent tothe
(car (cdr '("first" "second") ) )
In the following example, try to get to the element 3, using only two calls to such functions:
the
(let* ( (
x '( (1 2 (3 4 5) 6) 7 8 (9 10) )
) )
; your code here
)
If you have, then you are almost ready to write your first script.
Registration script in GIMP
Before you sit down to write code, to provide convenient conditions.
For scripts user GIMP creates in your home directory to the folder
.gimp-2.6/scripts
. So the script picked up, enough to put the scm file in the GIMP menu select Filters → Script-fu → Refresh Scripts (that is, if GIMP is already running, otherwise he will load at startup).File obviously, it is necessary to put written functions. It can contain as many functions, but it would be nice logically different functions spread across different files, and files named after the content. Another recommendation, even the agreement: our functions should be named according to the type of
script-fu-functionname
.By and large, this is enough, that we can call our functions from the console.
But if we want to have the script had its own menus, and in his call to open the window with the settings, it is necessary to add two functions responsible for registration. And there is nothing complicated, just look at an example.
Suppose we want to write a function that improves the quality of the text on the image with nonuniform illumination (in fact, I have already written, but this does not prevent us to do it again). Here is its definition:
the
(define (script-fu-readability inImage inLayer inRadius inHigh-input))
I know, I know, there is only function Declaration and it does nothing. The code will be useful later. Now we are and that is enough. Registration happens like so:
the
(script-fu-register
"script-fu-readability"
"Readability"
"Improves text readability on the photos. It's needed only when there is a non-uniform illumination",
"Dragonizer"
"Copyleft, use it at your own sweet will"
"January 7, 2011"
"RGB* GRAY* INDEXED*"
SF-IMAGE "The image" 0
SF-DRAWABLE "The layer" 0
SF-ADJUSTMENT "Median blur: radius" '(15 1 20 1 5 0 SF-SLIDER)
SF-ADJUSTMENT "Levels: intensity of highest input" '(235 0 255 1 10 0 SF-SPINNER)
)
(script-fu-menu-register "script-fu-readability" "< Image > /Filters/User's scripts")
The first function is passed to the next. The first argument is the name of our function, the second is the display name, the description, fourth — the author, the fifth — information about copyright, the sixth — creation date. Seventh — types of supported images (RGB, RGBA, GRAY, GRAYA, INDEXED, INDEXEDA).
Subsequent arguments are optional. They (except for
SF-IMAGE
and SF-DRAWABLE
) allow you to create the script window widgets such as lines, jackdaws, sliders, spinners, color picker, font and more, to convey the user selection to the function. Referred to as SF-IMAGE
will give us a link to the current open image, and SF-DRAWABLE
— for the selected layer. I won't describe all the SF-*
, the settings you can see the tables here (else read is not necessary, because summarized in this article). And I advise you to look this picture to understand what you will need (took here).The window is ready, it remains to add the call in the menu of GIMP, which makes the second function of the code above. Two arguments: again, the function name and the path to the menu. The path starts with
<Image>
, if some of the branches previously existed, GIMP will add them.Another example: if we wanted to write a script that creating image with desired properties, we would have removed the
SF-IMAGE
and SF-DRAWABLE
from the first function instead of "RGB* GRAY* INDEXED*"
would use an empty string ""
(we don't have the open image, we create it), and the second function would change the path to something like "<Image>/File/Create/Something"
.To see the result, save our work in "the
script-fu-readability.scm
", and update the scripts. Now open/create any image and choose from the menu to our script.coding
Here it is, the coveted moment! But hasten to disappoint: there's nothing complicated here. Exactly. Functions you already know how to write. And all you may need from the editor, it is easy to find in the browser procedures. Need some kind of operation with layers? Search by query "
layer
". Invert the image? You need something that contains "invert
". And so on.I will make only two observations:
-
the
- it would be nice to conclude all the actions performed by the script, between the functions
gimp-image-undo-group-start
andgimp-image-undo-group-end
, as is done below, so that the user does not have to undo each action separately.
the - All GIMP functions return the result lists, regardless of the amount of data in the result. Easily punctured, waiting for example,
layer
, and receiving(layer)
. So don't forget to docar
in such cases.
the
(define (script-fu-readability inImage inLayer inRadius inHigh-input)
(let* (
(layer2 0)
)
(gimp-image-undo-group-start inImage)
(if (not (= (car (gimp-image-base-type inImage)) GRAY)) (gimp-image-convert-grayscale inImage))
(set! layer2 (car (gimp-layer-copy inLayer FALSE)))
(plug-in-despeckle RUN-NONINTERACTIVE inImage layer2 inRadius 0 -1 256)
(gimp-layer-set-mode layer2 DIFFERENCE-MODE)
(set! inLayer (car (gimp-image-flatten inImage)))
(gimp-invert inLayer)
(gimp-levels inLayer HISTOGRAM-VALUE 0 inHigh-input 0.1 0 255)
(gimp-image-undo-group-end inImage)
)
)
Having at hand the procedure browser, it is easy to understand here, if you're interested.
Batch processing
Where-where? That's not all. I think we've come this far to write a lousy script that processes one image? Yes hands would be faster! So let's get GIMP to open all files from a given folder to process and save to another folder.
Best of all — to adapt the code below to do something else, just change it calls the function on the right, everything else will not change (well, unless you want to save the file to a different extension).
Code partially borrowed from this topic (thanks Apostol), but it saves the file, overwriting the original. The
morph-filename
taken otsuda.the
(define (morph-filename orig-name new-extension)
(let* ((buffer (vector "" "" "")))
(if (re-match "^(.*)[.]([^.]+)$" orig-name buffer)
(string-append (substring orig-name 0 (car (vector-ref buffer 2))) new-extension)
)
)
)
(define (script-fu-batch-readability inInFolder inOutFolder inRadius inHigh-input)
(let* ((filelist (cadr (file-glob (string-append inInFolder DIR-SEPARATOR "*") 1))))
(while (not (null? filelist))
(let* ((filename (car filelist))
(image (car (gimp-file-load RUN-NONINTERACTIVE filename filename)))
(layer (car (gimp-image-get-active-layer image)))
)
(script-fu-readability image layer inRadius inHigh-input)
(set! layer (car (gimp-image-get-active-layer image)))
(set! filename (string-append inOutFolder DIR-SEPARATOR
(morph-filename (car (gimp-image-get-name image)) "png")))
(file-png-save2 RUN-NONINTERACTIVE image layer filename filename 0 9 0 0 0 1 0 0 0)
(gimp-image-delete image)
)
(set! filelist (cdr filelist))
)
)
)
Opinion
Script Readability with the batch version can be downloaded here (the mirror). Code is commented, even too much.
Once again, that the article is not exhaustive in the broadest sense and is designed only to allow the reader to sit down, carefully read, in parallel with practice, and start creating scripts that solve his problem. So that it takes as much time as required for more or less quality.
If you read the article till the end, now you know how to Script-fu as well as me.
Комментарии
Отправить комментарий