; step-transform.scm: ; ; Transform selection / layer with a combination of scaling, rotation and offset, ; optionally merge with a copy of another layer above and / or a layer below, - ; each step in a new layer, or separate file (by extension). ; ; The optional filename is required to end in a period followed by exactly ; three characters to identify the file format. Frame numbers are then added ; between name and extension. ; ; This is free software, with NO warranty at all. ; See the GNU General Public License for details: ; http://www.gnu.org/copyleft/gpl.html ; ; Casper Maarbjerg, http://www.nyx.net/~cmaarbj/ ; December 1998 ; Modified for Gimp-1.2, May 2003 ; Modified for Gimp-2.0, January 2005 ; (define (script-fu-step-transform image src fgnd fg-on bgnd bg-on steps scale degrees x-offset y-offset wrap filename) (let* ((newlayer 0) (next 0) (selection 0) (newfile "") (basename filename) (ext filename) (base-length 0) (x-adj 0) (y-adj 0) (x-offs x-offset) (y-offs y-offset) (step-scale 1.0) (version 1.0) (name (car (gimp-layer-get-name src))) (type (car (gimp-image-base-type image))) (mode (car (gimp-layer-get-mode src))) (fg-image (car (gimp-drawable-image fgnd))) (bg-image (car (gimp-drawable-image bgnd))) (opacity (car (gimp-layer-get-opacity src))) (comp-opacity (car (gimp-layer-get-opacity fgnd))) (comp-mode (car (gimp-layer-get-mode fgnd))) (height (car (gimp-image-height image))) (width (car (gimp-image-width image))) (radians (* 6.28318530717959 (/ degrees 360.0))) (rot radians)) ;; Script-Fu version compatibility issues (^%!@#;) (if (= (car (gimp-procedural-db-query "gimp_version" "" "" "" "" "" "")) 1) (set! version (string->number (car (gimp-version))))) ; when available (if (>= version 2) ; channel-ops-offset deprecated (begin (define layer-offset gimp-drawable-offset)) (define layer-offset gimp-channel-ops-offset)) (if (<= version 1.0) ; add image argument to procedure calls and (begin ; rename undo-en/disabilities (define disable-undo gimp-image-disable-undo) (define enable-undo gimp-image-enable-undo) (define (layer-offset d w f x y) (gimp-channel-ops-offset image d w f x y)) (define (layer-rotate d i a) (gimp-rotate image d i a)) (define (layer-copy d) (gimp-edit-copy image d)) (define (layer-paste d p) (gimp-edit-paste image d p)) (define (load-selection s) (gimp-selection-load image s))) (begin ; version > 1.0 (define disable-undo gimp-image-undo-disable) (define enable-undo gimp-image-undo-enable) (define (layer-rotate d i a) (gimp-rotate d i a)) (define (layer-copy d) (gimp-edit-copy d)) (define (layer-paste d p) (gimp-edit-paste d p)) (define (load-selection s) (gimp-selection-load s)))) (disable-undo image) (if (= (car (gimp-selection-is-empty image)) TRUE) (gimp-selection-all image) (begin (set! selection (car (gimp-selection-save image))) (gimp-image-set-active-layer image src))) (define (fit-layer n) ; to restore image dimensions and align (set! x-adj (car (gimp-drawable-offsets n))) (set! y-adj (cadr (gimp-drawable-offsets n))) (gimp-layer-resize n width height x-adj y-adj)) (if (> (length filename) 4) (begin (set! base-length (length filename)) ; split filename 4 characters from end (set! ext (substring filename (- base-length 4) base-length)) (set! basename (substring filename 0 (- base-length 3))) (define (save-frame n) (fit-layer newlayer) (set! newfile (string-append basename (number->string n) ext)) ; compose filename (gimp-file-save 1 image newlayer newfile newfile) (gimp-image-free-shadow image))) ; for layered animations, replace works better than combine (define (save-frame n) (gimp-layer-set-name newlayer (string-append name " " (number->string n) " (replace)")))) (define (set-visible state) (let* ((layers (gimp-image-get-layers image)) (layer-count (car layers))) (set! layers (cadr layers)) (while (> layer-count 0) (set! layer-count (- layer-count 1)) (gimp-layer-set-visible (aref layers layer-count) state)))) (if (or (> bg-on 0) (> fg-on 0)) (set-visible FALSE)) (if (= bg-on 0) (define (add-bgnd) '()) (define (add-bgnd) (gimp-selection-none image) (layer-copy bgnd) (set! comp (car (layer-paste newlayer 0))) ; 0 = clear selection (gimp-floating-sel-to-layer comp) (gimp-image-lower-layer image comp))) ; put background behind (if (= fg-on 0) (define (add-fgnd) '()) (define (add-fgnd) (gimp-selection-none image) (layer-copy fgnd) (set! comp (car (layer-paste newlayer 0))) (gimp-floating-sel-to-layer comp))) (if (= (+ bg-on fg-on) 0) (define (do-merge) '()) (define (do-merge) (gimp-layer-set-mode comp comp-mode) (gimp-layer-set-opacity comp comp-opacity) (gimp-layer-set-mode newlayer mode) (gimp-layer-set-opacity newlayer opacity) (plug-in-align-layers 1 image newlayer 1 1) ; link-after-alignment use-bottom (set! newlayer (car (gimp-image-merge-visible-layers image CLIP-TO-IMAGE))) (gimp-layer-set-visible newlayer FALSE))) (if (or (= degrees 0.0) (= degrees 360.0)) (define (do-rotate) '()) (define (do-rotate) (if (>= version 2.0) (gimp-layer-resize-to-image-size newlayer)) (set! newlayer (car (layer-rotate newlayer TRUE rot))) ; TRUE to enable interpolation (if (> (car (gimp-layer-is-floating-sel newlayer)) 0) (gimp-floating-sel-to-layer newlayer)) (set! rot (+ rot radians)) (if (< version 2.0) (fit-layer newlayer)))) (if (and (= x-offs 0) (= y-offs 0)) (define (do-offset) '()) (define (do-offset) (if (> (car (gimp-layer-is-floating-sel newlayer)) 0) (gimp-floating-sel-to-layer newlayer)) (gimp-selection-none image) (if (>= version 2.0) (gimp-layer-resize-to-image-size newlayer)) (layer-offset newlayer wrap 1 x-offs y-offs) ; 1 = transparent fill (set! x-offs (+ x-offs x-offset)) (set! y-offs (+ y-offs y-offset)))) (if (or (= scale 1.0) (= scale 0.0)) (define (do-scale) '()) (define (do-scale) (gimp-selection-none image) (fit-layer newlayer) (set! step-scale (* step-scale scale)) (gimp-layer-scale newlayer (* width step-scale) (* height step-scale) 1) ; 1 = image origin (fit-layer newlayer))) (while (> steps 0) (if (> selection 0) (load-selection selection) (gimp-selection-all image)) (layer-copy src) (set! newlayer (car (gimp-layer-new image width height type "Frame" opacity mode))) (set! newlayer (car (layer-paste src 0))) (do-rotate) (do-scale) (if (> (car (gimp-layer-is-floating-sel newlayer)) 0) (gimp-floating-sel-to-layer newlayer)) (do-offset) (add-bgnd) (add-fgnd) (do-merge) (set! steps (- steps 1)) (set! next (+ next 1)) (save-frame next)) (if (> selection 0) ; cleanup (begin (load-selection selection) (gimp-image-remove-channel image selection))) (if (or (> bg-on 0) (> fg-on 0)) (set-visible TRUE)) (gimp-displays-flush) (enable-undo image))) (script-fu-register "script-fu-step-transform" "/Script-Fu/Animators/Transform" "Transform selection/layer a number of times, each step in a new layer/file" "Casper Maarbjerg" "Casper Maarbjerg, http://www.nyx.net/~cmaarbj/" "20-Dec-1998, 28-May-2003, 21-Jan-2005" "RGB RGBA" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0 SF-DRAWABLE "Foreground" 0 SF-TOGGLE "Merge Foreground" 0 SF-DRAWABLE "Background" 0 SF-TOGGLE "Merge Background" 0 SF-VALUE "Number of steps" "1" SF-VALUE "Scale (> 0.0)" "1.0" SF-VALUE "Rotation/Step" "0.0" SF-VALUE "X-offset" "0" SF-VALUE "Y-offset" "0" SF-TOGGLE "Offset wraparound" 1 SF-VALUE "Filename.typ" "\"\"")