GIMP Script-Fu Первый Дан. Наивные графические преобразования

от автора

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

Библиотека функций к Script-fu

подготовка
(define path-home (getenv "HOME")) (define path-lib (string-append path-home "/work/gimp/lib/")) (define path-work (string-append path-home "/work/gimp/")) (load (string-append path-lib "util.scm")) (load (string-append path-lib "img.scm")) (load (string-append path-lib "struct.scm")) (load (string-append path-lib "point.scm")) ;;там операции с углами.

Напишем первую функцию:

;;установили цвет бекграунда (define i1 (create-1-layer-img 640 480)) (define isource1 (car (file-png-load 1                                      (string-append path-work "i1.png") "i1")))  (define (draw-from-image1 dest dest-x dest-y src)   (let ((dw2 (car (gimp-layer-new-from-drawable                (car (gimp-image-get-active-layer src)) dest))))     (gimp-image-add-layer dest dw2 0)     (gimp-layer-set-offsets dw2 dest-x dest-y)     (gimp-image-merge-visible-layers dest CLIP-TO-IMAGE)))  (draw-from-image1 i1 10 50 isource1) 

С помощью этой функции мы можем разместить любое загруженное изображение на редактируемом изображении в указанной позиции.

"Размещение одного изобржажения в другом на заданном смещении"

«Размещение одного изображения в другом на заданном смещении»

Целевой прямоугольник может не совпадать, с размером изображения, поэтому мы должны уметь масштабировать размещаемое изображение. Напишем вторую функцию:

(define (draw-from-image-scale dest dest-x dest-y src sc-x sc-y)   (let* ((dw2 (car (gimp-layer-new-from-drawable                     (car (gimp-image-get-active-layer src)) dest)))          (h (car (gimp-drawable-height dw2)))          (w (car (gimp-drawable-width  dw2))))     (gimp-image-add-layer dest dw2 0)     (gimp-layer-scale dw2 (* w sc-x) (* h sc-y) TRUE)     (gimp-layer-set-offsets dw2 dest-x dest-y)     (gimp-image-merge-visible-layers dest CLIP-TO-IMAGE)))  (draw-from-image-scale i1 10 50 isource1 0.5 3) (draw-from-image-scale i1 150 50 isource1 2.5 1.4) (draw-from-image-scale i1 320 50 isource1 0.9 1.2) 
"Размещение изображений с масштабированием "

«Размещение изображений с масштабированием «

Повороты

А теперь разберёмся с поворотами. Изображения нужно не только сдвигать и масштабировать, но и поворачивать.

(define (draw-from-image-rotate dest dest-x dest-y src sc-x sc-y alfa)   (let* ((dw2 (car (gimp-layer-new-from-drawable                     (car (gimp-image-get-active-layer src)) dest)))          (h (car (gimp-drawable-height dw2)))          (w (car (gimp-drawable-width  dw2)))          (delta 0.001)          (alfa-r (gr2rad alfa)))     (gimp-image-add-layer dest dw2 0)     (if (or (> (abs (- sc-x 1)) delta)             (> (abs (- sc-y 1)) delta))         (gimp-layer-scale dw2 (* w sc-x) (* h sc-y) TRUE))     (if (> (abs alfa-r) delta)         (gimp-drawable-transform-rotate dw2 alfa-r FALSE 0 0                                         TRANSFORM-FORWARD                                         INTERPOLATION-LINEAR                                         FALSE 1                                         TRANSFORM-RESIZE-ADJUST))     (gimp-layer-set-offsets dw2 dest-x dest-y)     (gimp-image-merge-visible-layers dest CLIP-TO-IMAGE))) 

По функции видно последовательность действий: сначала масштабируем, потом поворачиваем

"Размещение изображений с поворотом "

«Размещение изображений с поворотом «

Как вам? По мне так получилось — не очень! Точка начала вставляемого рисунка уехала при повороте! Это надо исправить! Пишем второй вариант.

;; что то вроде остатка по модулю от 360 (define (angle-360 angle)   (cond    ((>= angle 360) (angle-360 (- angle 360)))    ((< angle 0)   (angle-360 (+ angle 360)))    (#t angle)))  ;; непосредственно функция вычисления смещения, которое зависит от величины угла поворота. (define (calc-offset-for-rotate alfa w h)   (let* ((a (angle-360 alfa))          (a-r (gr2rad a)))     (cond      ((<= a 90)       (cons (- (* h (sin a-r))) 0))      ((<= a 180)       (cons (- (- (* h (sin a-r))                   (* w (cos a-r))))             (* h (cos a-r))))      ((<= a 270)       (cons (* w (cos a-r))             (+ (* w (sin a-r))                (* h (cos a-r)))))      ((<= a 360)       (cons 0             (* w (sin a-r))))      )))   (define (draw-from-image-rotate dest dest-x dest-y src sc-x sc-y alfa)   (gimp-image-undo-disable dest)   (let* ((dw2 (car (gimp-layer-new-from-drawable                     (car (gimp-image-get-active-layer src)) dest)))          (h (car (gimp-drawable-height dw2)))          (w (car (gimp-drawable-width  dw2)))          (delta 0.001)          (alfa-r (gr2rad alfa)))      (gimp-image-add-layer dest dw2 0)     (if (or (> (abs (- sc-x 1)) delta)             (> (abs (- sc-y 1)) delta))         (gimp-layer-scale dw2 (* w sc-x) (* h sc-y) TRUE))     (if (> (abs alfa-r) delta)         (set! dw2 (car (gimp-drawable-transform-rotate dw2 alfa-r FALSE 0 0                                                    TRANSFORM-FORWARD                                                    INTERPOLATION-LINEAR                                                    FALSE 1                                                    TRANSFORM-RESIZE-ADJUST))))     (let* ((deltas (calc-offset-for-rotate alfa (* w sc-x) (* h sc-y)))            )       (gimp-layer-set-offsets dw2                               (+ dest-x (car deltas))                               (+ dest-y (cdr deltas))))     (gimp-image-merge-visible-layers dest CLIP-TO-IMAGE))   (gimp-image-undo-enable dest))

Здесь я применяю ещё и отмену от создания списка отката редактирования, уж больно большие списки отката создаются, но делать это не обязательно.
Выполняем тестирование.

(draw-from-image-rotate i1 100 200 isource1 1.0 1.0 0) (draw-from-image-rotate i1 100 200 isource1 1.0 1.0 30) (draw-from-image-rotate i1 100 200 isource1 1.0 1.0 45) (draw-from-image-rotate i1 100 200 isource1 1.0 1.0 90)
"Корректное размещение изображений с поворотом "

«Корректное размещение изображений с поворотом «

Давайте создадим на основе этой функции другую, создающую вращение изображений вокруг заданного центра.

(define (rot-img1 dest src x y scale num)   (let ((a1 (floor (/ 360 num)))         (a-cur 0))     (while (< a-cur 360)       (draw-from-image-rotate dest x y src scale scale a-cur)       (set! a-cur (+ a-cur a1)))))  (rot-img1 i1 isource1 300 200 0.5 5) (rot-img1 i1 isource1 100 100 0.3 4)
"Композиция изображений с поворотом "

«Композиция изображений с поворотом «

При построении функции draw-from-image-rotate мы использовали три функции GIMP: gimp-layer-scale, gimp-drawable-transform-rotate, gimp-layer-set-offsets, это получилось в следствии того что к её окончательному виду мы подходили постепенно, эволюционно, задействуя средства ГИМПа по мере необходимости. GIMP же в свою очередь имеет функцию, позволяющую заменить все эти три функции одной:

;; новый подход через функции трансформации (define (draw-from-image-rotate2 dest dest-x dest-y src sc-x sc-y alfa)   (let* ((dw2 (car (gimp-layer-new-from-drawable                     (car (gimp-image-get-active-layer src)) dest)))          (h (car (gimp-drawable-height dw2)))          (w (car (gimp-drawable-width  dw2)))          (delta 0.001)          (alfa-r (gr2rad alfa)))     (gimp-image-add-layer dest dw2 0)     (gimp-item-transform-2d dw2 0 0 sc-x sc-y alfa-r dest-x dest-y)     (gimp-image-merge-visible-layers dest CLIP-TO-IMAGE)     )) 

Протестируем её с помощью функции кратного вращения изображения.

(define (rot-img2 dest src x y scale num)   (gimp-image-undo-group-start dest)   (let ((a1 (floor (/ 360 num)))         (a-cur 0))     (while (< a-cur 360)       (draw-from-image-rotate2 dest x y src scale scale a-cur)       (set! a-cur (+ a-cur a1))))   (gimp-image-undo-group-end dest))    (rot-img2 i1 isource1 250 200 0.5 14) (rot-img2 i1 isource1 450 200 0.4 5) 
"Использование оптимизированной функции поворота изображения "

«Использование оптимизированной функции поворота изображения «

Как видите GIMP имеет огромное разнообразие функций позволяющих прийти к одному результату разными путями. Далее мы рассмотрим использование функции трансформации изображений позволяющую заменить весь набор рассмотренных ранее, тех которые рассмотрены не были, настоящую киллер функцию, остальных функции преобразования, с небольшой поправочкой — линейных преобразований.

Но прежде чем перейти к её рассмотрению, давайте ещё немного расширим возможности языка тинисхема, о чём и будет следующая статья.


ссылка на оригинал статьи https://habr.com/ru/articles/860458/


Комментарии

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *