; ; photo-stack ; ; This script turns a simple image into a rendition of a pile of ; photographs, with the original image at the top. Each picture in ; the stack has a white border added, and a shadow behind it (to ; delimit it from the one below). All the underlying pictures are, of ; course, copies of the top one. ; ; The following options are supported (with the given defaults): ; Border Color (white): ; The color of the border added to the image. ; Border Width (10): ; The width in pixels of the border added to the image. ; Pictures in Stack (3): ; The number of pictures in the final stack, including the ; original image. ; Rotate Sloppiness (100): ; Amount of rotational sloppiness to add to each picture. 0 ; means don't rotate them. ; Move Sloppiness (10): ; Amount of sideways sloppiness to add to each picture. 0 means ; don't move them. ; Top Straight (TRUE): ; If TRUE, keep the top image straight; otherwise, skew it like ; the others. ; Add Shadow (TRUE): ; If TRUE, add a shadow to each layer (recommended). ; Shadow Radius (12.0): ; Blur radius in pixels used to generate each layer's shadow. ; Shadow Weight (100%): ; Opacity for the shadow layers: 0 - 100. ; Work on Copy (TRUE): ; If TRUE, everything is done on a copy of the original image ; (highly recommended). ; Flatten Layers (FALSE): ; If TRUE, the image is merged into a single layer when all's ; done, and autocrops it. ; ; Issues: ; * Unless the user elects to flatten the resulting image, I don't ; autocrop it, and you're left with a huge image. I need an ; autocrop which takes into account the sizes and extents of ; *all* the layers, not just the current one, to fix this. ; * With very large move sloppiness values, you could get a ; clipped image. ; * Using this on a multi-layered source will discard the layers. ; * Undo doesn't work, I think largely because of the "Add Border" ; script. I could do the border adding within the script ; easily enough and fix that. ; ; Thoughts: ; * Currently all the pictures in the stack are the same size. I ; could add some random cropping and/or resizing, and even 90° ; rotations... ; * Could have the ability to make multiple images, from separate ; layers, into a stack... And then maybe add a "permute" ; option, to generate multiple stacks, one with each image on ; top, to make a whole photo album. ; Main function: (define (script-fu-photo-stack inImage inLayer inColor inSize inNum inSlop inSpill inTopStraight inShadow inShadRadius inShadWeight inCopy inFlatten ) (let* ( theImage theLayer width height newLayer angle ) ; Figure out what image and layer we're working on. If the user ; wants to work on a copy, then copy the image; the passed-in ; layer handle (inLayer) then becomes invalid. (set! theImage (if (= inCopy TRUE) (car (gimp-image-duplicate inImage)) inImage )) (set! theLayer (car (gimp-image-get-active-layer theImage))) (gimp-undo-push-group-start theImage) (srand (realtime)) ; Stick a border on the original image; then flatten it, so we've ; got a single layer to work on. (script-fu-addborder theImage theLayer inSize inSize inColor 0) (set! theLayer (car (gimp-image-flatten theImage))) (gimp-layer-add-alpha theLayer) ; Double the width and height of the image. I can't think of a ; better way to figure out how big it needs to be, to handle all ; the random resizing and skewing we're going to do. (set! width (car (gimp-image-width theImage))) (set! height (car (gimp-image-height theImage))) (gimp-image-resize theImage (* width 2) (* height 2) (/ width 2) (/ height 2)) (gimp-layer-resize theLayer (* width 2) (* height 2) (/ width 2) (/ height 2)) ; For every *additional* copy we need, add it. (while (> inNum 1) ; Copy the original to make the new copy, just under the ; original. (set! newLayer (car (gimp-layer-copy theLayer TRUE))) (gimp-image-add-layer theImage newLayer 1) ; Skew it, and add a shadow if required. (clint-skew-layer theImage newLayer inSlop inSpill) (if (= inShadow TRUE) (clint-add-shadow theImage newLayer 1 inShadRadius inShadWeight)) (set! inNum (- inNum 1)) ) ; If we don't need the original (top) image kept straight, skew ; it; add a shadow to the original if required. (if (= inTopStraight FALSE) (clint-skew-layer theImage theLayer inSlop inSpill)) (if (= inShadow TRUE) (clint-add-shadow theImage theLayer 0 inShadRadius inShadWeight)) ; Flatten the image if requested. Having done this, we can safely ; autocrop it. (if (= inFlatten TRUE) (begin (set! theLayer (car (gimp-image-merge-visible-layers theImage 1))) (plug-in-autocrop 1 theImage theLayer) )) ; Tidy up. (if (= inCopy TRUE) (begin (gimp-image-clean-all theImage) (gimp-display-new theImage) )) (gimp-undo-push-group-end theImage) ) ) ; Skew a layer by the given slop (rotation) and spill (vert/horiz ; shift) factors, randomized. (define (clint-skew-layer image layer slop spill) (let* (dx dy angle) ; X/Y shift. (if (> spill 0) (begin (set! dx (+ (rand spill) 3)) (set! dy (+ (rand spill) 3)) (if (= (rand 2) 1) (set! dx (- 0 dx))) (if (= (rand 2) 1) (set! dy (- 0 dy))) (gimp-layer-translate layer dx dy) )) ; Rotational skew. (if (> slop 0) (begin (set! angle (+ (/ (rand slop) 1000) 0.02)) (if (= (rand 2) 1) (set! angle (- 0 angle))) (gimp-rotate layer TRUE angle) )) ) ) ; Add a shadow layer. (define (clint-add-shadow image layer depth radius opacity) (set! layer (car (gimp-layer-copy layer TRUE))) (gimp-image-add-layer image layer (+ depth 1)) (gimp-selection-layer-alpha layer) (gimp-palette-set-foreground '(0 0 0)) (gimp-bucket-fill layer 0 0 100 0 FALSE 0 0) (gimp-selection-none image) (plug-in-gauss-iir 1 image layer radius TRUE TRUE) (gimp-layer-set-opacity layer opacity) ) ; Register the function with the GIMP: (script-fu-register "script-fu-photo-stack" "/Script-Fu/Modify/Photo Stack" "foo" "Ian Cameron Smith" "1998, Ian Cameron Smith, http://www.hermit.org/" "27 May 1998" "RGB RGBA GRAY GRAYA" SF-IMAGE "The Image" 0 SF-DRAWABLE "The Layer" 0 SF-COLOR "Border Color:" '(255 255 255) SF-VALUE "Border Width:" "10" SF-VALUE "Pictures in Stack:" "3" SF-VALUE "Rotate Sloppiness:" "100" SF-VALUE "Move Sloppiness:" "10" SF-TOGGLE "Top Straight?" TRUE SF-TOGGLE "Add Shadow?" TRUE SF-VALUE "Shadow Radius:" "12.0" SF-VALUE "Shadow Weight (%):" "100" SF-TOGGLE "Work on Copy?" TRUE SF-TOGGLE "Flatten Layers?" FALSE )