Script file generated from LiVES

<define>
|1.7
</define>

<name>
ripple
</name>

<version>
1
</version>

<author>
saulgoode|http://chiselapp.com/user/saulgoode/repository/RFX-GIMP/home
</author>

<description>
Ripple|rippling|1|1|
</description>

<requires>
gimp
</requires>

<params>
ripple-period|Period|num0|50|0|10000|
ripple-amp|Amplitude|num0|20|0|10000|
ripple-modulation|Modulation|num2|0.00|0.00|10000.00|0.25|
ripple-mod-type|Modulation Type|string_list|0|Linear|Sinusoidal|
ripple-direction|Vertical|bool|1|
ripple-edge|Edge Handling|string_list|0|Smear|Wrap|Blank|
ripple-sine|Sine Wave|bool|1|1|
ripple-triangle|Triangle Wave|bool|0|1|
ripple-velocity|Velocity|num0|0|-10000|10000|
</params>

<param_window>
</param_window>

<properties>
0x0001
</properties>

<language_code>
0xF0
</language_code>

<pre>
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License version 3 or higher
# as published by the Free Software Foundation.

use IO::Socket; 
use Text::Balanced;

if ($ENV{'RFXGIMP_PORT'}) {
  $rfx_port = $ENV{'RFXGIMP_PORT'};
  }
else {
  $rfx_port = 10008; 
  }

$sock = new IO::Socket::INET ( PeerAddr => 'localhost', 
                               PeerPort => $rfx_port, 
                               Proto => 'tcp' 
                               );
if ( not defined $sock ) {
  my $rfx_pid = fork();
  if (not defined $rfx_pid) {
    &sig_error("UNABLE TO EXECUTE GIMP: Not enough resources");
    } 
  elsif ($rfx_pid == 0) {
    if ( -f $tmpdir . "rfxgimp.pid") {
      open(PIDFILE, $tmpdir . "rfxgimp.pid");
      # should probably do some sanity checking for the off chance that
      # the PID has been recycled or the system has rebooted (e.g, check
      # if process was executed with /usr/bin/perl. But for now...
      kill(15, -<PIDFILE>); # the negative PID means kill all children, too.
      close(PIDFILE);
      }
    setpgid($$,0); # change the pgroup to this forked process, rather than
                   # the original LiVES (so that we don't kill LiVES when 
                   # this prgroup is killed).
    open(PIDFILE, ">" . $tmpdir . "rfxgimp.pid"); # overwrite old file
    print PIDFILE $$;
    close(PIDFILE);
    my $start_gimp = qq{ gimp -i -b "(plug-in-script-fu-server 1 $rfx_port \\\"\\\")" & };
    system ( $start_gimp ); # though started as separate process, GIMP now
                            # is part of this spawned child's pgroup, not the LiVES pgroup
    sleep(); # do nothing, forever
    &sig_error("GIMP killed by external process\n");
    }
  else {
    while (not defined $sock) {
      sleep (1);
      $sock = new IO::Socket::INET ( PeerAddr => 'localhost', 
                                     PeerPort => $rfx_port, 
                                     Proto => 'tcp' 
                                     );
      }
    }
  }

# Define a Perl subroutine for sending messages to the SF server and waiting
# for a response.
#
sub rfx_sendmsg {
  my $message = $_[0];
  my $len = length ($message);
  if ($len > 65535) {
    &sig_error("ERROR: script is too long for one server request: $len > 65535");
    };
  # send script to GIMP
  my $header = pack( 'an', 'G', $len);
  syswrite( $sock, $_ ) for ($header, $message);
  # wait for response
  my $rin = '';
  vec( $rin, fileno($sock), 1 ) = 1;
  select( $rin,  undef, undef, undef );    # wait (forever) for response start
  select( undef, undef, undef, .1 );       # wait a bit for response to finish
                                           #  increase wait if INVALID/INCOMPLETE RESPONSE occurs
  # response
  $len = sysread( $sock, $header, 4 ) or &sig_error("INVALID RESPONSE: empty response");
  ( $len == 4 and $header =~ /^G/ ) or &sig_error("INVALID RESPONSE: bad header");
  my $status;
  ($status, $len) = unpack( 'xCn', $header );
  my $response;
  ( sysread( $sock, $response, $len ) == $len ) or &sig_error("INCOMPLETE RESPONSE: $response");
  # exit if response is not "Success"
  if ( $status and $response =~ /^Error: Success\n/i ) {
    &sig_error("UNSUCCESSFUL EXECUTION: Script-fu error");
    }
  $status; 
  }

# define a Script-fu utility function to save frames using the PNG or JPG
# compression levels specified in 'gimprc'. 
# To specify a PNG compression level of 5, include the following line
# in gimprc:
#   (rfx-png-compression "5") 
# If not specified then a default level of "3" is assumed.
# "3" is a good choice for PNGs because higher levels double the write
# times while only offering about 15% reduction in file size.
# To specify a JPG compression level of 85, include the following line
# in gimprc:
#   (rfx-jpg-compression "85") 
# If not specified then a default level of "93" is assumed.

# NOTE: 'rfx-save-frame' DELETES the image.  
&rfx_sendmsg( qq{
  (begin
    (define rfx-curtmpdir "$curtmpdir")
    (define rfx-imgext "$img_ext")
    (unless (defined? 'rfx-save-frame)
      (define rfx-png-compression (catch #f (gimp-gimprc-query "rfx-png-compression")))
      (set! rfx-png-compression (if rfx-png-compression
                                  (string->number (car rfx-png-compression))
                                  3 ))
      (define rfx-jpg-compression (catch #f (gimp-gimprc-query "rfx-jpg-compression")))
      (set! rfx-jpg-compression (if rfx-jpg-compression
                                  (string->number (car rfx-jpg-compression))
                                  93 ))
      (define (rfx-save-frame image basename)
        (let ((filename (string-append rfx-curtmpdir DIR-SEPARATOR basename))
              (layer (car (gimp-image-get-active-layer image))) )
          (if (string-ci=? rfx-imgext ".jpg")
            (begin
              (gimp-context-push)
              (gimp-context-set-background '(6 6 6))
              (let loop ((layers (vector->list (cadr (gimp-image-get-layers image)))))
                (unless (null? layers)
                  (if (= (car layers) layer)
                    (gimp-drawable-set-visible layer TRUE)
                    (gimp-drawable-set-visible (car layers) FALSE) )
                  (loop (cdr layers)) ))
              (set! layer (car (gimp-image-flatten image)))
              (file-jpeg-save RUN-NONINTERACTIVE 
                              image 
                              layer
                              filename 
                              filename 
                              (/ rfx-jpg-compression 100)
                              0 ; smoothing 
                              1 ; optimize 
                              1 ; progressive 
                              "" ; comment 
                              0 ; subsmp (0-4)
                              1 ; baseline 
                              0 ; restart 
                              0 ;dct 
                              )
              (gimp-context-pop) )
            (begin
              (unless (zero? (car (gimp-image-base-type image)))
                (gimp-image-convert-rgb image) )
              (file-png-save2 RUN-NONINTERACTIVE 
                              image 
                              layer
                              filename 
                              filename 
                              FALSE ; interlace
                              rfx-png-compression
                              FALSE ; bkgd
                              (car (gimp-drawable-has-alpha layer))
                              FALSE ; offs
                              FALSE ; phys
                              FALSE ; time
                              TRUE  ; comment
                              FALSE ; svtrans
                              )))
          (gimp-image-delete image) ))))
  }
  );
</pre>

<loop>
# $p0 ; period (in pixels)
# $p1 ; amplitude
# $p2 ; amplitude modulation cycles (0=none, number cycles during frame sequence)
# $p3 ; modulation type linear/sinusoidal (dropdown)
# $p4 ; direction (bool: horiz=0 vert=1)
# $p5 ; edge type (dropdown: smear, wrap, blank)
# $p6 ; sine wave  (radio group 1)
# $p7 ; triangle   (radio group 1)
# $p8 ; velocity (0=constant, else number of pixels shifted each frame)

# Note: GIMP's Ripple plug-in does not directly support either phase shifting
#       or negative amplitudes. To implement phase shifting, it is therefore
#       necessary to resize the drawable by the amount of the shift. To
#       accommodate negative amplitudes, the effect is also phase shifted
#       by half the period.
#
#       rfx-ripple-mod and rfx-ripple-phase are each a pair containing
#       the current value and the increment amount. Both need to be defined
#       globally and therefore can not be defined within a lambda/let.
#
#       In the case of rfx-ripple-phase, the value is an offset in the 
#       range 0 <= X < period (period is in pixels). 
#
#       In the case of rfx-ripple-mod, the value is an offset that is in the
#       range 0 <= X < 1. The script then determines the scaling of 
#       the actual ripple amplitude based upon the evaluation of either
#       the triangle or sinusoidal.
#
&rfx_sendmsg (
  qq{
    (begin
      (unless (zero? $p8) 
        (if (= $frame $start)
          (define rfx-ripple-phase (cons 0 
                                         (if (> $p8 0)
                                           (- $p0 $p8) 
                                           (- $p8) )))
          (set! rfx-ripple-phase (cons (let loop ((phase-offset (+ (car rfx-ripple-phase)
                                                                   (cdr rfx-ripple-phase) )))
                                         (if (< phase-offset $p0)
                                           phase-offset
                                           (loop (- phase-offset $p0)) ))
                                       (cdr rfx-ripple-phase) ))))
      (unless (zero? $p2)
        (if (= $frame $start)
          (define rfx-ripple-mod (cons 0 (* $p2 (/ (succ (- $end $start))))))
          (set! rfx-ripple-mod (cons (let loop ((amp-offset (+ (car rfx-ripple-mod)
                                                               (cdr rfx-ripple-mod) )))
                                       (if (< amp-offset 1)
                                         amp-offset
                                         (loop (- amp-offset 1)) ))
                                     (cdr rfx-ripple-mod) ))))
      (let ((period $p0)
            (amplitude $p1)
            (mod-cycles $p2)
            (mod-linear $p3)
            (direction $p4)
            (edge $p5)
            (sine $p6)
            (triangle $p7)
            (velocity (- $p8))
            (phase-offset 0)
            )
        (let* ((input-file (string-append "$curtmpdir" DIR-SEPARATOR "$in"))
               (image (car (gimp-file-load RUN-NONINTERACTIVE input-file input-file)))
               (layer (car (gimp-image-get-active-layer image))) )
          ; calculate layer offfset owing to animated phase
          (unless (zero? velocity) ; phase motion
            (set! phase-offset (car rfx-ripple-phase)) )
          (set! amplitude 
            (* amplitude
              (if (zero? mod-cycles)
                1
                (let ((fract (- (car rfx-ripple-mod) (truncate (car rfx-ripple-mod)))))
                  (if mod-linear
                    (cond 
                      ((< fract 0.25)
                        (* amplitude fract 4) )
                      ((< fract 0.50)
                        (* amplitude (- 1 (* (- fract 0.25) 4))) )
                      ((< fract 0.75)
                        (* amplitude (- (* amplitude (- fract 0.5) 4))) )
                      (else
                        (- (* amplitude (- fract 0.75) 4) 1) )))
                    (sin (* 2 *pi* fract)) ))))
          (when (< amplitude 0)
            (set! phase-offset (+ phase-offset (/ period 2)))
            (if (>= phase-offset period)
              (set! phase-offset (- phase-offset period)) ))
          (set! amplitude (abs amplitude))
          (unless (zero? phase-offset)
            (if (zero? direction) 
              (gimp-layer-resize layer
                                 $width
                                 (+ phase-offset $height)
                                 0
                                 phase-offset )
              (gimp-layer-resize layer
                                 (+ phase-offset $width)
                                 $height
                                 phase-offset
                                 0 )))
          (plug-in-ripple RUN-NONINTERACTIVE image layer
                          period
                          amplitude
                          direction
                          edge
                          sine
                          TRUE  ; always use antialias
                          FALSE ; we don't need tilability
                          )
          (gimp-layer-resize-to-image-size layer)
          (rfx-save-frame image "$out") 
          )
        )
      )
    }
  );

</loop>

<post>
</post>

<onchange>
init|if ($p4 == 1) { # horizontal
init|  $p0_max = $width;
init|  $p1_max = $height;
init|  }
init|else { # vertical
init|  $p0_max = $height;
init|  $p1_max = $width;
init|  }
init|$p2_max = $end - $start;
init|$p2_min = 0;
init|$p8_max = $end - $start;
init|$p8_min = $start - $end;
</onchange>

