; Jagged Border, V1.1 ; ; AUTHOR: theilr (http://flickr.com/photos/theilr), (c) 2009 ; ; This script was tested with GIMP 2.6.7 ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License Version 3 as ; published by the Free Software Foundation. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License at http://www.gnu.org/licenses for ; more details. ; ; DESCRIPTION: Creates a white (or black) border around an image that ; merges in with the image so that on a larger white (or black) ; background, the image appears to have a ragged border. This is ; similar to the Gimp's Fuzzy Border, but it adapts its jaggedness to ; the image. (Also unlike Fuzzy Border, it is deterministic, it does ; not depend on random number seeds.) ; ; The script is located in menu " / Filters / theilr" ; But it probably belongs in " / Filters / Decor" ; ; USAGE NOTES: Since this non-destructively produces a border as a ; separate layer, you can tweak the border; eg smooth it (yuck, then ; it's not very jagged anymore!), change its color, use it to build ; some fancy drop-shadow, etc. A number of effects can be obtained by ; using the white/black border layer and/or its inverse as a layer ; mask. ; ; You can apply the border to other images. For instance, you can ; make a high (or low) contrast version of your image for the purpose ; of making the border, but once you have the border, you can apply it ; to your original image. ; ; If you don't like the rounded corners in the Rectangular mode, you ; can run Horizontal and Vertical separately and then just merge them ; ; If you check "Enforce one-pixel border" than your border will be at least ; one pixel wide around the whole image. Usually you won't need this, but ; if you have very dark things at the border of the image, they might get ; in the way of the fuzzy select. ; ; BUGS: ; Smooth amount is assumed to be double the border size; this is ad hoc ; Ideally, the border would adjust itself to be as narrow as possible at ; its thinnest point. No point wasting good pixels! ; Currently, the border is "seeded" from UL and LR corners, can forsee ; situations when this would be inadequate; eg, very dark component ; running through the border. I'm implemented workaround that basically ; adds a one-pixel border around the whole image. ; Threshold is a parameter, but in practice I always use 1, maybe should ; just remove it as a parameter. ; I really don't like the rounded corners that Rectangular mode gives; the ; default should be what you get when you make horizontal and vertical ; borders separately and then combine them -- currently, you have to do ; that manually. ; I don't know what this will do if layer and canvas are different sizes; ; I can imagine neat effects where you might want to specify (eg, with a ; selection) a border that only surrounds part of your image. ; No way to interactively change a lot of these parameters; you just ; have to try different values and see what you get ; Need a better name for this script (ragged border? adaptively ragged?) ; Q: does it make sense to have borders any color other than black or white? ; ; SCRIPT SUMMARY: ; Make new layer which is black with a white border, blur the border, ; add the new layer to a copy of the image of interest, select the ; white area, and throw away that temporary layer. Make a new layer, ; which is white over the selection (which is the border area), ; and black in the interior. This layer is in ADDITION-MODE, and so ; the black interior is effectively transparent. ; ; To make black borders, the strategy is essentially the same, except ; that the original image is inverted before being added to the blurred ; white frame. After the new border layer is generated, it is inverted, ; and changed from ADDITION-MODE to MULTIPLY-MODE. ; ; ; ; Version 1.0 (Oct 2009) -- ; Version 1.1 (Nov 2009) -- added option for black borders ; ============================================================================= (define (script-fu-jagged-border inImage inLayer inBorderShape inBlackBorder inBorderSize inThresh inFillIslands inOnePixelBorder) (let* ( ;define local variables (theWidth (car (gimp-image-width inImage))) (theHeight (car (gimp-image-height inImage))) (cpyLayer (car (gimp-layer-copy inLayer TRUE))) ;copy of image (tmpLayer (car (gimp-layer-new inImage theWidth theHeight RGB-IMAGE "tmp" 100 NORMAL-MODE))) (bdrLayer (car (gimp-layer-new inImage theWidth theHeight RGB-IMAGE "Border" 100 NORMAL-MODE))) ) (gimp-image-undo-group-start inImage) ;; Make a black layer with a white border (gimp-image-add-layer inImage tmpLayer -1) (gimp-edit-fill tmpLayer WHITE-FILL) (gimp-invert tmpLayer) ; ie, BLACK-FILL ;; Make a selection, equivalent to shrinking in by inBorderSize (if (= inBorderShape 0) ;; Rectangular (gimp-rect-select inImage inBorderSize inBorderSize (- theWidth (* inBorderSize 2)) (- theHeight (* inBorderSize 2)) CHANNEL-OP-ADD FALSE 0) ) (if (= inBorderShape 1) ;; Horizontal only (gimp-rect-select inImage 0 inBorderSize theWidth (- theHeight (* inBorderSize 2)) CHANNEL-OP-ADD FALSE 0) ) (if (= inBorderShape 2) ;; Vertical only (gimp-rect-select inImage inBorderSize 0 (- theWidth (* inBorderSize 2)) theHeight CHANNEL-OP-ADD FALSE 0) ) (if (= inBorderShape 3) ;; Elliptical (gimp-ellipse-select inImage inBorderSize inBorderSize (- theWidth (* inBorderSize 2)) (- theHeight (* inBorderSize 2)) CHANNEL-OP-ADD FALSE FALSE 0) ) (gimp-selection-invert inImage) (gimp-edit-fill tmpLayer WHITE-FILL) (gimp-selection-none inImage) ;; blur the border (plug-in-gauss-iir RUN-NONINTERACTIVE inImage tmpLayer (* inBorderSize 2) TRUE TRUE) ;; Now put up a copy of the image, to be added to this border layer (gimp-image-add-layer inImage cpyLayer -1) (gimp-desaturate cpyLayer) ;; make it a desaturated image (does this help?) (if (= inBlackBorder 1) (gimp-invert cpyLayer) ) (if (= inOnePixelBorder 1) ;; add a single layer of white pixels around the image (good idea?) ;; it does waste border pixels in horiz-only or vert-only modes ;; but it ensures that the entire border will be generated (begin (gimp-selection-all inImage) (gimp-selection-shrink inImage 1) (gimp-selection-invert inImage) (gimp-edit-fill cpyLayer WHITE-FILL) (gimp-selection-none inImage) ) ) (gimp-layer-set-mode cpyLayer ADDITION-MODE) ;; When we merge down we need to capture the identity ;; of the merged layer, rename it tmpLayer (set! tmpLayer (car (gimp-image-merge-down inImage cpyLayer 0))) ;; select the white border, then remove the tmp layer ;; because all we care about is the selection (gimp-fuzzy-select tmpLayer 0 0 inThresh CHANNEL-OP-ADD TRUE FALSE 0 FALSE) (gimp-fuzzy-select tmpLayer (- theWidth 1) (- theHeight 1) inThresh CHANNEL-OP-ADD TRUE FALSE 0 FALSE) (gimp-image-remove-layer inImage tmpLayer) ;; now make a new layer (by default it is black, is that reliable? (gimp-image-add-layer inImage bdrLayer -1) (gimp-edit-fill bdrLayer WHITE-FILL) ;; make the selection white (gimp-selection-none inImage) (gimp-layer-set-mode bdrLayer ADDITION-MODE) (if (= inFillIslands 1) (begin (gimp-fuzzy-select bdrLayer (/ theWidth 2) (/ theHeight 2) 127 CHANNEL-OP-ADD TRUE FALSE 0 FALSE) (gimp-selection-invert inImage) (gimp-edit-fill bdrLayer WHITE-FILL) ;; fill in the islands (gimp-selection-none inImage) ) ) (if (= inBlackBorder 1) (begin (gimp-invert bdrLayer) (gimp-layer-set-mode bdrLayer MULTIPLY-MODE) ) ) (gimp-image-undo-group-end inImage) (gimp-displays-flush) ) ) (script-fu-register "script-fu-jagged-border" "_Jagged Border" "Makes a white border that merges with the image" "theilr" "(c) theilr" "25 Oct 2009" "RGB*" SF-IMAGE "Image" 0 SF-DRAWABLE "Drawable" 0 SF-OPTION "Border shape" '("Rectangular" "Horizontal only" "Vertical only" "Elliptical" ) SF-OPTION "Border color" '("White" "Black") SF-ADJUSTMENT "Border width" '(50 0 1000 1 50 0 SF-SLIDER) SF-ADJUSTMENT "Threshold" '(1 0 255 1 10 0 SF-SLIDER) SF-TOGGLE "Fill in the islands" TRUE SF-TOGGLE "Enforce one-pixel border" TRUE ) (script-fu-menu-register "script-fu-jagged-border" "/Filters/_theilr")