; rr_make_seamless.scm
; by Rob Antonishen
; http://ffaat.pointclark.net

; Version 1.3 (20100625)

; Description
;
; Make Image Seamless.  
; Credit for the method to Redrobes of ViewingDale, see www.ViewingDale.com, You can mail on the contact page on that site for support.
; V1.0 - Initial Version
; V1.1 - Added option to tile vertically, horizontally, or both.  Added additional parameter to paste the center in.
; V1.2 - Changed to use of named buffers
; V1.3 - fixes "bug" created by bug fix for gimp 2.6.9 in gimp-histogram

; 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 2 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.
;
; The GNU Public License is available at
; http://www.gnu.org/copyleft/gpl.html
(define (script-fu-rr_make_seamless img inLayer inFlatten inCenter inOrient)
  (let* 
    (
    (width (car (gimp-image-width img)))
    (height (car (gimp-image-height img)))
    (imgTemp (car (gimp-image-duplicate img)))
    (layerTemp (car (gimp-image-flatten imgTemp)))
    (imgWorking (car (gimp-image-duplicate imgTemp)))
    (layerWorking 0)
    (float 0)
    (layerBlur 0)
    (layerBlur2 0)
    (layerColor 0)
    (layerColor2 0)
    (buffname "seamlessbuff")
    )

    ; it begins here
  
    (gimp-image-undo-disable imgWorking)
    (set! imgWorking (car (plug-in-tile RUN-NONINTERACTIVE imgTemp layerTemp (* 2 width) (* 2 height) TRUE)))  ;create a tiled copy

    (set! layerWorking (car (gimp-image-get-active-layer imgWorking))) ; get the layer
    (set! inFlatten (- 1.0 inFlatten))
  
    (if (or (= inOrient 0) (= inOrient 1))
    (begin
      ;build the selection (vertical)
      (gimp-selection-none img)
      (gimp-ellipse-select img (- (* width 0.50) (* width 0.07)) (* height 0.05) (* width 0.14) (* height 0.45) CHANNEL-OP-REPLACE TRUE TRUE (* width 0.02))
      (gimp-ellipse-select img (- (* width 0.50) (* width 0.07)) (* height 0.50) (* width 0.14) (* height 0.45) CHANNEL-OP-ADD TRUE TRUE (* width 0.02))
      (gimp-ellipse-select img (- (* width 0.50) (* width 0.125)) (* height 0.05) (* width 0.25) (* height 0.45) CHANNEL-OP-ADD TRUE TRUE (* width 0.10))
      (gimp-ellipse-select img (- (* width 0.50) (* width 0.125)) (* height 0.50) (* width 0.25) (* height 0.45) CHANNEL-OP-ADD TRUE TRUE (* width 0.10))
      (gimp-ellipse-select img (- (* width 0.50) (* width 0.02)) (* height 0.00) (* width 0.04) (* height 1.00) CHANNEL-OP-ADD TRUE TRUE (* width 0.02))
      (gimp-ellipse-select img (- (* width 0.50) (* width 0.04)) (* height 0.20) (* width 0.08) (* height 0.60) CHANNEL-OP-ADD TRUE TRUE (* width 0.08))
      (gimp-ellipse-select img (- (* width 0.53) (* width 0.06)) (* height 0.15) (* width 0.12) (* height 0.20) CHANNEL-OP-ADD TRUE TRUE (* width 0.02))
      (gimp-ellipse-select img (- (* width 0.47) (* width 0.06)) (* height 0.65) (* width 0.12) (* height 0.20) CHANNEL-OP-ADD TRUE TRUE (* width 0.02))
      ; copy it
      (set! buffname (car (gimp-edit-named-copy-visible img buffname))) 
      ;paste it in
      (set! float (car (gimp-edit-named-paste layerWorking buffname FALSE)))
      (set! float (car (gimp-drawable-transform-2d-default float 0 0 1 1 0 0 (* height -0.5) FALSE FALSE)))
      (gimp-floating-sel-anchor float)

      (set! float (car (gimp-edit-named-paste layerWorking buffname FALSE)))
      (set! float (car (gimp-drawable-transform-2d-default float 0 0 1 1 0 0 (* height 0.5) FALSE FALSE)))
      (gimp-floating-sel-anchor float)
    ))

    (if (or (= inOrient 0) (= inOrient 2))
    (begin
      ;build the selection (horizontal)
      (gimp-selection-none img)
      (gimp-ellipse-select img (* width 0.05) (- (* height 0.50) (* height 0.07)) (* width 0.45) (* height 0.14) CHANNEL-OP-REPLACE TRUE TRUE (* height 0.02))
      (gimp-ellipse-select img (* width 0.50) (- (* height 0.50) (* height 0.07)) (* width 0.45) (* height 0.14) CHANNEL-OP-ADD TRUE TRUE (* height 0.02))
      (gimp-ellipse-select img (* width 0.05) (- (* height 0.50) (* height 0.125)) (* width 0.45) (* height 0.25) CHANNEL-OP-ADD TRUE TRUE (* height 0.10))
      (gimp-ellipse-select img (* width 0.50) (- (* height 0.50) (* height 0.125)) (* width 0.45) (* height 0.25) CHANNEL-OP-ADD TRUE TRUE (* height 0.10))
      (gimp-ellipse-select img (* width 0.00) (- (* height 0.50) (* height 0.02)) (* width 1.00) (* height 0.04) CHANNEL-OP-ADD TRUE TRUE (* height 0.02))
      (gimp-ellipse-select img (* width 0.20) (- (* height 0.50) (* height 0.04)) (* width 0.60) (* height 0.08) CHANNEL-OP-ADD TRUE TRUE (* height 0.08))
      (gimp-ellipse-select img (* width 0.15) (- (* height 0.47) (* height 0.06)) (* width 0.20) (* height 0.12) CHANNEL-OP-ADD TRUE TRUE (* height 0.02))
      (gimp-ellipse-select img (* width 0.65) (- (* height 0.53) (* height 0.06)) (* width 0.20) (* height 0.12) CHANNEL-OP-ADD TRUE TRUE (* height 0.02))
  
      ; copy it
      (set! buffname (car (gimp-edit-named-copy-visible img buffname)))  
      ;paste it in
      (set! float (car (gimp-edit-named-paste layerWorking buffname FALSE)))
      (set! float (car (gimp-drawable-transform-2d-default float 0 0 1 1 0 (* width -0.5) 0 FALSE FALSE)))
      (gimp-floating-sel-anchor float)

      (set! float (car (gimp-edit-named-paste layerWorking buffname FALSE)))
      (set! float (car (gimp-drawable-transform-2d-default float 0 0 1 1 0 (* width 0.5) 0 FALSE FALSE)))
      (gimp-floating-sel-anchor float)
    ))
  
    (if (eq? inCenter TRUE)
    (begin
      ;build the selection (center)
      (gimp-selection-none img)
      (gimp-ellipse-select img (- (* width 0.50) (* width 0.20)) (- (* height 0.50) (* height 0.20)) (* width 0.40) (* height 0.40) CHANNEL-OP-REPLACE TRUE TRUE (* (min height width) 0.10))

      ; copy it
      (set! buffname (car (gimp-edit-named-copy-visible img buffname)))

      (gimp-selection-none img)
  
      ;paste it in
      (set! float (car (gimp-edit-named-paste layerWorking buffname FALSE)))
      (gimp-floating-sel-anchor float)
    ))

    (gimp-selection-none img)
    (gimp-selection-none imgWorking)
         
    ;high pass filter with preserve DC
    (set! layerBlur (car (gimp-layer-copy layerWorking FALSE)))
    (gimp-image-add-layer imgWorking layerBlur -1)

    ;blur
    (if (> inFlatten 0)
      (plug-in-gauss-rle 1 imgWorking layerBlur (* (min height width) inFlatten) 1 1) ;2
    )  
    (gimp-image-set-active-layer imgWorking layerBlur)  ;top layer
  
    ;get the average colour of the input layer
    (set! layerColor (car (gimp-layer-copy layerWorking FALSE)))
    (gimp-image-add-layer imgWorking layerColor -1)

    (gimp-context-set-foreground (list (car (gimp-histogram layerColor HISTOGRAM-RED 0 255)) (car (gimp-histogram layerColor HISTOGRAM-GREEN 0 255)) (car (gimp-histogram layerColor HISTOGRAM-BLUE 0 255))))
    (gimp-drawable-fill layerColor FILL-FOREGROUND) ;3
    (gimp-image-set-active-layer imgWorking layerColor) 

    ;copy the solid colour layer
    (set! layerColor2 (car (gimp-layer-copy layerColor FALSE)))
    (gimp-image-add-layer imgWorking layerColor2 -1)    
    (gimp-layer-set-mode layerColor LAYER-MODE-SUBTRACT-LEGACY)
    (gimp-image-set-active-layer imgWorking layerColor2)

    ;copy the blurred layer
    (set! layerBlur2 (car (gimp-layer-copy layerBlur FALSE)))
    (gimp-image-add-layer imgWorking layerBlur2 -1)   
    (gimp-layer-set-mode layerBlur2 LAYER-MODE-SUBTRACT-LEGACY)

    (gimp-image-set-active-layer imgWorking layerBlur2)
  
    (set! layerBlur (car (gimp-image-merge-down imgWorking layerColor 0)))
    (set! layerBlur2 (car (gimp-image-merge-down imgWorking layerBlur2 0)))
    
    (gimp-layer-set-mode layerBlur LAYER-MODE-SUBTRACT-LEGACY)
    (gimp-layer-set-mode layerBlur2 LAYER-MODE-ADDITION-LEGACY)
    
    (set! layerWorking (car (gimp-image-merge-down imgWorking layerBlur 0)))
    (set! layerWorking (car (gimp-image-merge-down imgWorking layerBlur2 0)))

    ;crop the image
    (gimp-image-crop imgWorking width height (* width 0.5) (* height 0.5)) ;1
    ;and offset
    (gimp-drawable-offset layerWorking TRUE 0 (/ width 2) (/ height 2))
    
    ;done
  
    (gimp-display-new imgWorking)
    (gimp-image-undo-enable imgWorking)
    (gimp-displays-flush)
  )
)

(script-fu-register "script-fu-rr_make_seamless"
                    "<Image>/Filters/Map/RR Make Seamless..."
                    "A better make seamless."
                    "Rob Antonishen"
                    "Rob Antonishen"
                    "Oct 2008"
                    ""
                    SF-IMAGE      "image"      0
                    SF-DRAWABLE   "drawable"   0
                    SF-ADJUSTMENT "Color Flattening" '(0.75 0.00 1.00 0.01 0.10 2 0)    
                    SF-TOGGLE     "Center Blend to Corners?" FALSE          
                    SF-OPTION     "Orientation"      '("Both" "Horizontal" "Vertical")          
)       