Script-Fu. Путь новичка.

Nov 02, 2008 16:40


В GIMP я не новичок, но раньше руки никогда не доходили до написания к нему скриптов. Точнее доходили, но не далеко. Всякая предыдущая попытка что-нибудь сваять на этом поприще заканчивалась провалом в виду первого же неработающего примера, а досконально разбираться времени не хватало. Но недавно меня припёрло... Просто стало жалко своего времени когда речь зашла о пакетной обработке фотографий для подгодовки к публикации на сайте. ImageMagic я конечно тоже рассматривал, но у него все-таки не столь широкие возможности. Смотрел и в сторону GEGL, но не нашел достаточно документации. Вооружился я в итоге браузером и исходниками GIMP и пошел курить эту тему до умопомрачения.

В итоге я выяснил что с недавних пор поменялся диалект Schema (который в свою очередь является диалектом Lisp), используемый в GIMP. Не так давно им был SIOD, тепрь (а точнее в сентябре 2006-го в версии GIMP 2.2) нам подсунули Tiny-Fu, базирущийся на стандарте R5RS. Выяснил я это после того как очередная попытка использовать более менее серьезный пример на SIOD, изобилующих в сети, окончилась провалом =) И с тех пор замаячил свет в конце тонеля в моих попытках разобраться что к чему. Но это было позже....

А сначала я взял за основу статью Сергея Головко. Статья хороша тем, что вменяемо описывает синтаксис и основы Lisp. Но сходу написать нужный скрипт все равно не удалось. Во-первых он описывает в статье диалект SIOD (тут я еще не был в курсе о смене диалекта). Во-вторых было совершенно не понятно как работать с файлами (этим я озадачился на первом этапе). Ну и не совсем еще были ясны нюансы в основных конструкциях языка, а просмотр процедур в GIMP дает информацию исключительно о PDB (для тех, кто не в курсе - это набор внутренних функций GIMP для работы с изображением, задумчиво именуемый базой данных), а по языку ну ни слова.

В итоге я полез в исходники, где и наткнулся на "документацию" по TinySCHEME. Для интересующихся скажу что лежит она в исходниках по пути: gimp-2.6.1/plug-ins/script-fu/tinyscheme/Manual.txt. Этот файлик и открыл мне глаза, хотя документацией его можно назвать с большой натяжкой... Чуть позднее я наткнулся на другой файлик, в котором описывались функции не реализованные в Tiny-Fu для совместимости с SIOD: /usr/local/share/gimp/scripts/script-fu-compat.init. Именно из этих файлов я и узнал нужное мне ключевое слово для поиска. А именно TinySCHEME. Справедливости ради следует отметить, что если бы я был более внимательным, то нашел бы это в Консоли Script-Fu =)

И все-таки удобно когда есть доступ к исходникам уже готового функционала. Дальнейшее изучение языка я продолжил в уже готоых script-fu скриптах, лежащих в: /usr/local/share/gimp/scripts/. Описание моих последующих поисков, путешествия по граблям и изучение методом научного тыка я пожалуй опущу. Вот что у меня получилось в итоге:

(define (images-prepare dir_to_prepare i_w i_h t_w t_h) ; Выводим список паттернов для имен загружаемых файлов (define (prepare-patterns dtp) (define fts '("jpg" "JPG" "jpeg" "JPEG" "png" "PNG")) (define pts ()) (for-each (lambda (format) (set! pts (cons (string-append dtp "/*." format) pts)) ) fts ) pts ) ; Выводим список путей загружаемых файлов (define (get-file-paths pats) (define fls ()) (for-each (lambda (pattern) (set! fls (append (cadr (file-glob pattern 1)) fls)) ) pats ) fls ) ; Делим строку по разделяющему символу (define (split-sring str sep) (define ret ()) (define tmp ()) (for-each (lambda (simb) (if (string=? (atom->string simb) sep) (begin (if (null? tmp) (begin (set! ret (cons (list->string tmp) ret)) ) (begin (set! ret (cons (list->string (reverse tmp)) ret)) ) ) (set! tmp ()) ) (begin (set! tmp (cons simb tmp)) ) ) ) (string->list str) ) (if (null? tmp) (begin (set! ret (cons (list->string tmp) ret)) ) (begin (set! ret (cons (list->string (reverse tmp)) ret)) ) ) (reverse ret) ) ; Получаем имя файла с изображением превьюшки (define (get-tumb-name name) (define ret "") (define lst (split-sring name ".")) (define len (length lst)) (define iteract 0) (for-each (lambda (simb) (set! iteract (+ iteract 1)) (set! ret (string-append ret simb)) (if (= iteract (- len 1)) (begin (set! ret (string-append ret "_th")) ) ) (if (< iteract len) (begin (set! ret (string-append ret ".")) ) ) ) lst ) ret ) ; Повышаем резкость изображения по хитрому алгоритму (define (rez img ind) (define sublayer_one 0) (define sublayer_two 0) (set! sublayer_one (car (gimp-layer-copy (car (gimp-image-get-active-layer img)) 1))) (gimp-image-add-layer img sublayer_one -1) (gimp-desaturate sublayer_one) (gimp-layer-set-mode sublayer_one GRAIN-MERGE-MODE) (set! sublayer_two (car (gimp-layer-copy sublayer_one 1))) (gimp-image-add-layer img sublayer_two -1) (gimp-invert sublayer_one) (plug-in-gauss 1 img sublayer_one ind ind 1) (gimp-image-flatten img) ) (define width 0) (define height 0) (define width_th 0) (define height_th 0) (define img 0) (define drawable 0) (define save_image 0) (define newfilename "") (define filelist (get-file-paths (prepare-patterns dir_to_prepare))) (for-each (lambda (file) (set! img (car (gimp-file-load 1 file file))) (set! drawable (car (gimp-image-get-active-layer img))) (gimp-layer-set-name drawable "bg") (if (> (car (gimp-image-width img)) (car (gimp-image-height img)) ) (begin (set! width i_w) (set! height i_h) (set! width_th t_w) (set! height_th t_h) ) (begin (set! width i_h) (set! height i_w) (set! width_th t_h) (set! height_th t_w) ) ) ; Подгоняем размер изображения (gimp-image-scale-full img width height INTERPOLATION-LANCZOS) (rez img 1.0) (set! newfilename (string-append dir_to_prepare "/out/" (car (gimp-image-get-name img)))) ; Удаляем exif данные из изображения. По умолчанию GIMP поворачивает ; изображение, если в exif есть информация об ориентации, а саму exif ; запись не изменяет. Лечится удалением exif (gimp-image-parasite-detach img "exif-data") ; Сохраняем изображение (gimp-file-save RUN-NONINTERACTIVE img (car (gimp-image-get-active-layer img)) newfilename newfilename) ; Делаем превьюшку (gimp-image-scale-full img width_th height_th INTERPOLATION-LANCZOS) (rez img 0.5) (set! newfilename (string-append dir_to_prepare "/out/" (get-tumb-name (car (gimp-image-get-name img))))) (gimp-file-save RUN-NONINTERACTIVE img (car (gimp-image-get-active-layer img)) newfilename newfilename) ; Быстро бежим к помойке и выносим мусор =) (gimp-image-clean-all img) (gimp-image-delete img) ) filelist ) ) (script-fu-register "images-prepare" "/Script-Fu/Prepare Images" "Prepare Images" "SvvoRD" "SvvoRD" "2008" "" ;Вид объекта интерфейса Название Значение по умолчанию SF-DIRNAME "Directory" "" SF-ADJUSTMENT "Image width" '(800 1 4000 1 10 0 1) SF-ADJUSTMENT "Image height" '(600 1 4000 1 10 0 1) SF-ADJUSTMENT "Thumbnail width" '(133 1 500 1 10 0 1) SF-ADJUSTMENT "Thumbnail height" '(100 1 500 1 10 0 1) ) Перед употреблением следует скопировать все нужные файлы в отдельную директорию и создать в ней директорию "out". Туда и будет падать результат. Честно говоря желаемого результата я еще не достиг. По хорошему тут очень желательно было бы добавить интерактивный вызов инструмента Crop и инструменты по подгонке цвета, но как выяснилось, Script-Fu делать этого не позволяет. Либо я опять копал не в том месте... В следующий раз посмотрю как себя поведут скрипты на Perl и Python. Правда первый с GIMP используется редко, но его я знаю хорошо, а второй используетя часто, но его я практически не знаю. Так что мне еще предстоит множество увлекательных приключений. Чего и вам желаю.... З.Ы. Редактор тут убогий...  

gimp, script-fu

Previous post Next post
Up