Напомню нашу цель, это создание языка функциональной геометрии. Одно из базовых операций в нём является отрисовка некоторого изображения в заданный прямоугольник, вернее даже не прямоугольник, а рамку, которая может представлять из себя параллелограмм, повёрнутый на произвольный угол относительно горизонтальной оси координат, расположенный в любой точке плоскости рисования. Пока мы и близко не приблизились к этой цели. Продолжим исследование возможностей 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/
Добавить комментарий