; 210_edges_mats-and-frames.scm ; last modified/tested by Paul Sherman [gimphelp.org] ; Wednesday, 07/01/2020 on GIMP 2.10.20 ;================================================== ; ; Installation: ; This script should be placed in the user or system-wide script folder. ; ; Windows 7/10 ; C:\Program Files\GIMP 2\share\gimp\2.0\scripts ; or ; C:\Users\YOUR-NAME\AppData\Roaming\GIMP\2.10\scripts ; ; ; Linux ; /home/yourname/.config/GIMP/2.10/scripts ; or ; Linux system-wide ; /usr/share/gimp/2.0/scripts ; ;================================================== ; ; LICENSE ; ; This program is free software: you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation, either version 3 of the License, or ; (at your option) any later version. ; ; 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 for more details. ; ; You should have received a copy of the GNU General Public License ; along with this program. If not, see . ; ;============================================================== ; Original information ; ; Copyright (C) 2003 Eric Jeschke (eric@redskiesatnight.com) ; Based on code by ; Copyright (C) 1997 Andy Thomas (alt@picnic.demon.co.uk) ; and ; Copyright (C) 1997 Andrew Donkin (ard@cs.waikato.ac.nz) ; ;============================================================== ; gimp-scheme should add this...it's a scheme "standard" (define (cadddr l) (caddr (cdr l))) ; ditto ; non-functional mapper (discards values, used for effect). (define (for-each proc l) (if (not (null? l)) (begin (proc (car l)) (for-each proc (cdr l))))) ; Create an array from a list. (define (list-to-array contents) (let* ((alen (length contents)) (n_array (cons-array alen 'double)) (count 0)) (for-each (lambda (val) (aset n_array count val) (set! count (+ count 1))) contents) n_array)) ; Takes a color (represented as a list of numbers: (R G B)) and a delta ; value and returns four new colors representing the left, top, right and ; bottom shades. Used for coloring the mat bevel. ; ; returns (LC TC RC BC) (define (getcolors color delta) (letrec ((deltacolor (lambda (v d) (max (min (+ v d) 255) 0))) (adjcolor (lambda (cl d) (mapcar (lambda (v) (deltacolor v d)) cl))) ) (list (adjcolor color (- 0 (/ delta 2))) ; left color (adjcolor color (- 0 delta)) ; top color (adjcolor color (/ delta 2)) ; right color (adjcolor color delta) ; bottom color ) )) ; utility routine to decipher color choice option and return the ; appropriate fill: from dialog color picker, current fg, or current bg. (define (get-color fillchoice colorchoice) (cond ((= fillchoice 0) colorchoice) ((= fillchoice 1) (car (gimp-context-get-foreground))) (TRUE (car (gimp-context-get-background))) )) ; Draw a border around an image. ; ; This is the workhorse function. Draws a constant width border around ; an image with optional padding on each of the 4 sides. If 'delta' > 0 ; then each side will be colored so that it resembles a bevel (unless ; the fillchoice is a pattern). (define (draw-border drawable borderwidth lpad tpad rpad bpad ; # pixels to pad on L, T, R, B fillchoice ; type of fill fillcolor delta ; fill parameters bumppattern ; "texture" pattern leavebumpmap ; flag: TRUE-->preserve bumpmap ibumpp ; flag: TRUE-->bump interactively layername ; border is drawn on a new layer leaveselectionp ; if true, border becomes selection ) (let* ((img (car (gimp-item-get-image drawable))) (imgtype (car (gimp-drawable-type-with-alpha drawable))) (owidth (car (gimp-image-width img))) ; current image w & h (oheight (car (gimp-image-height img))) (old-fg (car (gimp-context-get-foreground))) (old-bg (car (gimp-context-get-background))) ; calculate new dimensions (width (+ owidth (* 2 borderwidth) lpad rpad)) (height (+ oheight (* 2 borderwidth) tpad bpad)) ; calculate coordinates for filling (ulimage_x (+ borderwidth lpad)) (ulimage_y (+ borderwidth tpad)) (llimage_x ulimage_x) (llimage_y (+ ulimage_y oheight)) (lrimage_x (+ llimage_x owidth)) (lrimage_y llimage_y) (urimage_x lrimage_x) (urimage_y ulimage_y) (ulborder_x lpad) (ulborder_y tpad) (llborder_x ulborder_x) (llborder_y (+ llimage_y borderwidth)) (lrborder_x (+ lrimage_x borderwidth)) (lrborder_y (+ lrimage_y borderwidth)) (urborder_x lrborder_x) (urborder_y ulborder_y) ; get colors for each side (returns LC TC RC BC) (filltype BG-BUCKET-FILL) (color (get-color fillchoice fillcolor)) (colors (getcolors color delta)) ; create a new layer above current one (layer (car (gimp-layer-new img width height imgtype layername 100 LAYER-MODE-NORMAL-LEGACY))) (ibumpflag (if (= ibumpp TRUE) 0 1)) ) ; fill with transparent pixels and resize to new dimensions (gimp-drawable-fill layer 3) (gimp-image-resize img width height ulimage_x ulimage_y) ; add the layer (gimp-image-insert-layer img layer 0 0) ; set up for pattern fill if that was requested (if (> fillchoice 2) (set! filltype PATTERN-BUCKET-FILL)) ; color the left polygon (gimp-context-set-background (car colors)) (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list ulborder_x ulborder_y ulimage_x ulimage_y llimage_x llimage_y llborder_x llborder_y ulborder_x ulborder_y))) (gimp-edit-bucket-fill layer filltype LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) ; color the left pad (if (> lpad 0) (begin (gimp-context-set-background color) (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list 0 ulborder_y ulborder_x ulborder_y llborder_x llborder_y 0 llborder_y 0 ulborder_y))) (gimp-edit-bucket-fill layer filltype LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) )) ; color the top polygon (gimp-context-set-background (cadr colors)) (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list ulborder_x ulborder_y ulimage_x ulimage_y urimage_x urimage_y urborder_x urborder_y ulborder_x ulborder_y))) (gimp-edit-bucket-fill layer filltype LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) ; color the top pad (if (> tpad 0) (begin (gimp-context-set-background color) (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list 0 0 0 ulborder_y width urborder_y width 0 0 0))) (gimp-edit-bucket-fill layer filltype LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) )) ; color the right polygon (gimp-context-set-background (caddr colors)) (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list urborder_x urborder_y urimage_x urimage_y lrimage_x lrimage_y lrborder_x lrborder_y urborder_x urborder_y))) (gimp-edit-bucket-fill layer filltype LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) ; color the right pad (if (> rpad 0) (begin (gimp-context-set-background color) (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list width urborder_y urborder_x urborder_y lrborder_x lrborder_y width lrborder_y width urborder_y))) (gimp-edit-bucket-fill layer filltype LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) )) ; color the bottom polygon (gimp-context-set-background (cadddr colors)) (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list llborder_x llborder_y llimage_x llimage_y lrimage_x lrimage_y lrborder_x lrborder_y llborder_x llborder_y))) (gimp-edit-bucket-fill layer filltype LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) ; color the bottom pad (if (> bpad 0) (begin (gimp-context-set-background color) (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list 0 height 0 llborder_y width lrborder_y width height 0 height))) (gimp-edit-bucket-fill layer filltype LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) )) ; if user wanted to texture the border, do a bump map (if (not (null? bumppattern)) (let* ((old-pattern (car (gimp-patterns-get-pattern))) (bumpmap (car (gimp-layer-new img width height imgtype "Texture Bump Map" 100 LAYER-MODE-NORMAL-LEGACY))) ) (gimp-image-insert-layer img bumpmap 0 0) (gimp-patterns-set-pattern bumppattern) ; NOTE: if we try to do a bump map on only the selection we get ; wierd artifacts around the edges; as a kludge, we turn on ; "preserve transparency" and bump map the entire thing. It might ; also be possible to just grow the selection, but I haven't tried ; that yet. (gimp-layer-set-preserve-trans layer 1) (gimp-selection-all img) (gimp-edit-bucket-fill bumpmap PATTERN-BUCKET-FILL LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) (gimp-patterns-set-pattern old-pattern) (plug-in-bump-map ibumpflag img layer bumpmap 125 45 3 0 0 0 0 TRUE FALSE 1) (if (= leavebumpmap TRUE) (gimp-item-set-visible bumpmap 0) (gimp-image-remove-layer img bumpmap) ) (gimp-layer-set-preserve-trans layer 0) )) ; clear selection (gimp-selection-none img) ; set selection to border if desired (if (= leaveselectionp TRUE) (begin (gimp-image-select-polygon img CHANNEL-OP-REPLACE 10 (list-to-array (list ulimage_x ulimage_y urimage_x urimage_y lrimage_x lrimage_y llimage_x llimage_y ulimage_x ulimage_y))) (gimp-selection-invert img) )) ; clean-up (gimp-context-set-background old-bg) ; return value (list layer) );end let* ) ; Script to add a mat around an image. ; (define (210-add-mat image drawable bevelwidth ; mat bevel width in pixels bevelfillchoice ; {0 (Choose) | 1 (FG color) | 2 (BG color)} bevelcolorchoice ; (Choose) color from color selection dialog delta ; amount to vary fill to create bevel effect matwidth matfillchoice ; as above, but for the mat matcolorchoice texturep ; flag: TRUE-->bump map the mat mattexture ; pattern for bump mapping mat leavebumpmapp ; flag: TRUE-->preserve bump map ibumpp ; flag: TRUE-->bump interactively lpad ; amount to pad the mat on the left tpad ; top rpad ; right bpad ; bottom layersp ; flag: TRUE-->preserve new layers leaveselectionp ; flag: TRUE-->mat is selected on exit ) (gimp-image-undo-group-start image) (if (not (= RGB (car (gimp-image-base-type image)))) (gimp-image-convert-rgb image)) (let* ((img (car (gimp-item-get-image drawable))) (pattern (if (= texturep TRUE) mattexture '())) ) ; draw bevel (if (> bevelwidth 0) (draw-border drawable bevelwidth 0 0 0 0 bevelfillchoice bevelcolorchoice delta '() FALSE FALSE "Mat Bevel" FALSE) ) ; draw mat (if (> matwidth 0) (draw-border drawable matwidth lpad tpad rpad bpad matfillchoice matcolorchoice 0 pattern leavebumpmapp ibumpp "Mat" leaveselectionp) ) ; merge layers if user did not want them (if (= layersp FALSE) (begin (if (> matwidth 0) (let ((layer (car (gimp-image-get-active-layer img)))) (gimp-image-merge-down img layer EXPAND-AS-NECESSARY) )) (if (> bevelwidth 0) (let ((layer (car (gimp-image-get-active-layer img)))) (gimp-image-merge-down img layer EXPAND-AS-NECESSARY) )) )) ; th-th-th-that's all folks! (gimp-image-undo-group-end img) (gimp-displays-flush) ) ) ; Script to add a frame around an image. ; (define (210-add-frame image drawable framewidth framefillchoice ; as above, but for the mat framecolorchoice texturep ; flag: TRUE-->bump map the mat frametexture ; pattern for bump mapping mat leavebumpmapp ; flag: TRUE-->preserve texture bump map ibumpp ; flag: TRUE-->bump interactively bevelindex ; "depth" of 3D effect ds-width ; inner shadow width ds-opacity ; inner shadow opacity layersp ; flag: TRUE-->preserve new layers leaveselectionp ; flag: TRUE-->mat is selected on exit leavebevelbumpmapp ; flag: TRUE-->preserve bevel bump map ) (gimp-image-undo-group-start image) (if (not (= RGB (car (gimp-image-base-type image)))) (gimp-image-convert-rgb image)) (let* ((img (car (gimp-item-get-image drawable))) (imgtype (car (gimp-drawable-type-with-alpha drawable))) (pattern (if (= texturep TRUE) frametexture '())) ) ; parameter sanity checks (if (<= framewidth 0) (set! framewidth 10)) (if (> bevelindex (/ framewidth 2)) (set! bevelindex (/ framewidth 2))) ; draw border (let* ((frame (car (draw-border drawable framewidth 0 0 0 0 framefillchoice framecolorchoice 0 pattern leavebumpmapp ibumpp "Frame" TRUE))) (selection (car (gimp-selection-save img))) (width (car (gimp-image-width img))) ; current image w & h (height (car (gimp-image-height img))) (old-bg (car (gimp-context-get-background))) (bumpmap (car (gimp-layer-new img width height imgtype "Frame Bevel Bump Map" 100 LAYER-MODE-NORMAL-LEGACY))) (index 1) ) ; Initialise our bumpmap (gimp-image-insert-layer img bumpmap 0 0) (gimp-item-set-visible bumpmap 0) (gimp-context-set-background '(0 0 0)) (gimp-drawable-fill bumpmap FILL-BACKGROUND) (gimp-image-select-item img CHANNEL-OP-REPLACE selection) ; Fill with a gradient of sorts ; TODO: there has got to be a more efficient way to do this ; (gradient fills?) (while (< index bevelindex) (let ((gv (/ (* index 255) bevelindex))) (begin (gimp-context-set-background (list gv gv gv)) (gimp-edit-bucket-fill bumpmap BUCKET-FILL-BG LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) (gimp-selection-shrink img 1) (set! index (+ index 1)) ))) ; Now the white interior of the bumpmap (gimp-context-set-background '(255 255 255)) (gimp-edit-bucket-fill bumpmap BUCKET-FILL-BG LAYER-MODE-NORMAL-LEGACY 100 0 FALSE 0 0) ; Do the bump map. (gimp-selection-none img) (plug-in-bump-map 1 img frame bumpmap 125 45 3 0 0 0 0 TRUE FALSE 1) ; remove bump map if user did not want it (if (= leavebevelbumpmapp FALSE) (gimp-image-remove-layer img bumpmap) ) ; Now for the inner shadow (if (> ds-width 0) (let* ((ds-color '(0 0 0)) ; create the shadow layer (shadow (car (gimp-layer-new img width height imgtype "Shadow" ds-opacity LAYER-MODE-NORMAL-LEGACY))) ) (gimp-image-insert-layer img shadow 0 0) (gimp-selection-none img) (gimp-edit-clear shadow) (gimp-context-set-background ds-color) (gimp-image-select-item img CHANNEL-OP-REPLACE selection) (gimp-selection-feather img ds-width) (gimp-edit-fill shadow FILL-BACKGROUND) (gimp-image-select-item img CHANNEL-OP-REPLACE selection) (gimp-edit-clear shadow) )) ; merge layers if user did not want them (if (= layersp FALSE) (begin ;(gimp-image-set-active-layer img frame) ;(gimp-image-merge-down img frame EXPAND-AS-NECESSARY) (gimp-image-merge-visible-layers img EXPAND-AS-NECESSARY) )) ; leave the selection if the user requested it (if (= leaveselectionp TRUE) (gimp-image-select-item img CHANNEL-OP-REPLACE selection) (gimp-selection-none img) ) ; clean up (gimp-image-remove-channel img selection) (gimp-context-set-background old-bg) );end let* ; th-th-th-that's all folks! (gimp-image-undo-group-end img) (gimp-displays-flush) ) ) ; Obligatory script registrations... (script-fu-register "210-add-mat" "Add Matte" "Add a single mat around an image" "Eric Jeschke " "Eric Jeschke" "5/27/03" "*" SF-IMAGE "Input Image" 0 SF-DRAWABLE "Input Drawable" 0 SF-ADJUSTMENT "Bevel Width" '(5 0 250 1 10 0 1) SF-OPTION "Bevel Fill" '("Color" "FG color" "BG color" "Pattern") SF-COLOR "Bevel Fill Color" '(221 221 221) SF-ADJUSTMENT "Delta Value on Bevel Color" '(25 1 255 1 10 0 1) SF-ADJUSTMENT "Mat Width" '(35 0 1000 1 10 0 1) SF-OPTION "Mat Fill" '(_"Color" "FG color" "BG color" "Pattern") SF-COLOR "Mat Fill Color" '(128 128 128) SF-TOGGLE "Texture Mat" FALSE SF-PATTERN "Texture Pattern" "Wood" SF-TOGGLE "Leave Texture Bump Map" FALSE SF-TOGGLE "Bump Interactively" FALSE SF-ADJUSTMENT "Left Pad" '(0 0 1000 1 10 0 1) SF-ADJUSTMENT "Top Pad" '(0 0 1000 1 10 0 1) SF-ADJUSTMENT "Right Pad" '(0 0 1000 1 10 0 1) SF-ADJUSTMENT "Bottom Pad" '(0 0 1000 1 10 0 1) SF-TOGGLE "Use Layers" FALSE SF-TOGGLE "Leave Selection" FALSE ) (script-fu-menu-register "210-add-mat" "/Script-Fu/Edges") (script-fu-register "210-add-frame" "Frame with Bevel" "Add a frame around an image, ability to adjust bevel and shadow" "Eric Jeschke " "Eric Jeschke" "5/27/03" "*" SF-IMAGE "Input Image" 0 SF-DRAWABLE "Input Drawable" 0 SF-ADJUSTMENT "Frame Width" '(35 0 1000 1 10 0 1) SF-OPTION "Frame Fill" '("Color" "FG color" "BG color" "Pattern") SF-COLOR "Frame Fill Color" '(128 128 128) SF-TOGGLE "Texture Frame" FALSE SF-PATTERN "Texture Pattern" "Wood" SF-TOGGLE "Leave Texture Bump Map" FALSE SF-TOGGLE "Bump Interactively" FALSE SF-ADJUSTMENT "Beveling Index" '(10 0 250 1 10 0 1) SF-ADJUSTMENT "Inner Shadow Width" '(8 0 100 1 10 0 1) SF-ADJUSTMENT "Inner Shadow Opacity" '(50 0 100 1 10 0 1) SF-TOGGLE "Use Layers" FALSE SF-TOGGLE "Leave Selection" FALSE SF-TOGGLE "Leave Bevel Bump Map" FALSE ) (script-fu-menu-register "210-add-frame" "/Script-Fu/Edges")