;; Blend effect - combines two video streams ;; Multi-input effect: uses frame-a and frame-b ;; Params: ;; mode - blend mode (add, multiply, screen, overlay, difference, lighten, darken, alpha) ;; opacity - blend amount (0-1) ;; resize-mode - how to resize frame-b to match frame-a (fit, crop, stretch) ;; priority - which dimension takes priority (width, height) ;; pad-color - color for padding in fit mode [r g b] (define-effect blend :params ( (mode :type string :default "overlay") (opacity :type float :default 0.5) (priority :type string :default "width") (list :type string :default 0 0 0) ) ) (let [a frame-a a-w (width a) a-h (height a) b-raw frame-b b-w (width b-raw) b-h (height b-raw) ;; Calculate scale based on resize mode and priority scale-w (/ a-w b-w) scale-h (/ a-h b-h) scale (if (= resize-mode "stretch") 1 ;; Will use explicit dimensions (if (= resize-mode "crop") (max scale-w scale-h) ;; Scale to cover, then crop (if (= priority "width") scale-w scale-h))) ;; For stretch, use target dimensions directly new-w (if (= resize-mode "stretch") a-w (round (* b-w scale))) new-h (if (= resize-mode "stretch") a-h (round (* b-h scale))) ;; Resize b b-resized (resize b-raw new-w new-h "linear") ;; Handle fit (pad) or crop to exact size b (if (= resize-mode "crop") ;; Crop to center (let [cx (/ (- new-w a-w) 2) cy (/ (- new-h a-h) 2)] (crop b-resized cx cy a-w a-h)) (if (and (= resize-mode "fit") (or (!= new-w a-w) (!= new-h a-h))) ;; Pad to center (let [pad-x (/ (- a-w new-w) 2) pad-y (/ (- a-h new-h) 2) canvas (make-image a-w a-h pad-color)] (paste canvas b-resized pad-x pad-y)) b-resized))] (if (= mode "alpha") (blend-images a b opacity) (blend-images a (blend-mode a b mode) opacity)))