#!/bin/sh -
#
# gif2anim [options] image_anim.gif...
#
# This script uses the ImageMagick 'convert' program to take a gif animation
# (normally ending in '_anim.gif' and NOT just '.gif') and converts it into a
# collection of X Pixmap files (or GIFs) as well as a "animation sequence
# file" which lists all settings needed to re-build the original GIF
# animation.
#
# OPTIONS
#      -g             use an gif suffix for frmae images (def: xpm)
#      -s suffix      use this suffix for the frame images
#      -n             skip frame images, just create the '.anim' file
#      -b framename   basename for the individual frames
#      -a framename   only do animations named '_anim.gif'
#      -o file.anim   output to this .anim file (- for stdout)
#      -l             just list the anim file to stdout, no images
#      -v             Be verbose in animation conversions
#
# The animation file uses the string "BASENAME" to represent the basenames for
# the individual frame images that it loads when re-creating the original GIF
# animation.  This allows you to specify a different set of images without
# changling any other settings.
#
# NOTE: This script reqires both the ImageMagick 'convert' program and
# 'identify' programs to extract the images and information needed.
#
####
#
# WARNING: Input arguments are NOT tested for correctness.
# This script represents a security risk if used ONLINE.
# I accept no responsiblity for misuse. Use at own risk.
#
# Anthony Thyssen    25 April 1996    <anthony@cit.gu.edu.au>
#
# 1 November 2005  Expanded with options for basename handling.
#
PROGNAME=`type $0 | awk '{print $3}'`  # search for executable on path
PROGDIR=`dirname $PROGNAME`            # extract directory of program
PROGNAME=`basename $PROGNAME`          # base name of program
Usage() {
  echo >&2 "$PROGNAME:" "$@"
  sed >&2 -n '/^###/q; s/^#$/# /; 3s/^#/# Usage:/;  3,$s/^# //p;' \
          "$PROGDIR/$PROGNAME"
  exit 10;
}

sfx="gif"           # Default output suffix of images to produce
init=1              # the count for the first frame in sequence
fmt="%03d"          # The format for frame count
frames=true         # output frame images by defult
basename=           # use this name for the individual frame images
animfile=           # no default animfile to output to.
all_gifs=           # forcefully convert any ".gif" file
VERBOSE=            # be verbose
awk=awk

while [ $# -gt 0 ]; do
  case "$1" in
  -g) sfx="gif" ;;             # output frame images as GIF's (default)
  -x) sfx="xpm" ;;             # output frame images as XPM's
  -s) sfx="$1"; shift ;;       # output frame images with this suffix
  -n) frames= ;;               # don't output any individual frames
  -b) basename="$2"; shift ;;  # use this basename for frames
  -o) animfile="$2"; shift ;;  # output .anim file here
  -l) frames=; animfile=- ;;   # List anim file to standard output, no images
  -v) VERBOSE=true ;;          # Be verbose
  --) shift; break ;;    # end of user options
  -*) Usage "Unknown option \"$1\"" ;;
  *)  break ;;           # end of user options
  esac
  shift   # next option
done

if [ $# -eq 0 ]; then
  Usage "No GIF animations given"
fi

# echo without return (all systems, including old BSD systems)
if [ "X`echo -n`" = "X-n" ]; then
  echo_n() { echo ${1+"$@"}"\c"; }
else
  echo_n() { echo -n ${1+"$@"}; }
fi

# Is the command available on this machine?
cmd_found() {
  case "`type $1 2>&1`" in *'not found'*) return 1 ;; esac; return 0
}
cmd_found convert  || Usage "No IM convert command found -- ABORTING"
cmd_found identify || Usage "No IM identify command found -- ABORTING"

# output animation details to stdout
if [ "X$animfile" = "X-" ]; then
  animfile=/dev/stdout
fi

# use gawk if it is present. (mawk has a parse bug under Ubuntu)
if cmd_found gawk; then
  awk=gawk
fi

# -----------------------------------------------------

for i in "$@" ; do
  [ "$VERBOSE" ] && echo_n "converting \"$i\" "
  if [ ! -f "$i" ]; then
    echo >&2 "Unable find file \"$i\""
    continue
  fi

  # --- find out the type ---
  name="`expr "//$i" : '.*/\([^/]*\)'`"           # remove path to file
  suffix="`expr "$name" : '.*\.\([^./]*\)$'`"     # extract last suffix
  name="`expr "$name" : '\(.*\)\.[^.]*$'`"        # remove last suffix

  case "$name.$suffix" in
   *.gif ) ;;
   * )     [ "$VERBOSE" ] && echo_n "${b}"
           echo >&2 "Skipping non-GIF file: \"$i\""
           continue ;;
  esac

  name=`echo "$name" | sed 's/_anim//'`        # remove any "_anim" part
  [ "$basename" ] && name=$basename
  anim_output=${animfile:-"$name.anim"}

  # Generate Animation file...
  date=`date +'%Y-%m-%d %R:%S'`
  #giftrans -L "$i" 2>&1 |
  identify -verbose "$i" |
    $awk '#  This is designed to parse either IM "identify", or "giftrans"
      BEGIN { print "#";
              print "# Animation Sequence File \"'"$i"'\"";
              print "# using a BASENAME of     \"'"$name"'\"";
              print "# Extracted on    '"$date"'";
              print "#";
              frame='"$init"'
              last_offset="+0+0";
            }
      /Application Extension/ { print "-loop 20"; } # FUDGE IT!
      /Iterations:/           { if ( ! loop ) {
                                  print "-loop " $NF;
                                  loop = 1;
                              } }
      /Delay Time:/ ||
      /Delay:/                { delay = $NF; }
      /Disposal Method:/      { dispose = $3 }
      /Dispose:/              { dispose = $NF; }
      /Image Width:/          { size    =            $(NF-1); }
      /Image Height:/         { size    = size   "x" $(NF-1); }
      /Geometry:/             { size    = $NF; }
      /Logical Screen Width:/ { canvas  =            $(NF-1); }
      /Logical Screen Height:/{ canvas  = canvas "x" $(NF-1); }
      /Image Left Position:/  { offset  =        "+" $(NF-1); }
      /Image Top Position:/   { offset  = offset "+" $(NF-1); }
      /Page geometry:/        { canvas  = substr($NF,0,match($NF, "+" )-1 );
                                offset  = substr($NF,  match($NF, "+" ) ); }
      # End of the data for this frame
      /Table Based Image Data:/ || /Version:/     {
                        if ( delay != last_delay ) {
                          print "-delay " delay;
                          last_delay = delay;
                        }
                        delay=0;   # no delay is given if it is set to zero
                        if ( dispose != last_dispose ) {
                          print "-dispose " dispose;
                          last_dispose = dispose;
                        }
                        if ( ! c_set ) { print "-page " canvas; c_set = 1; }
                        if ( offset != last_offset ) {
                            printf "%-14s ", "-page " offset;
                            last_offset = offset;
                        } else {
                            printf "%-14s ", "";
                        }
                        printf "BASENAME_'"$fmt.$sfx"'  #size %s\n",
                                frame++, size; }
    ' > $anim_output
  [ "$VERBOSE" -a -f "$anim_output" ] &&
         echo_n "`grep -c \\.$sfx\$ ${name}.anim | tr -d ' '` frames"

  # split up GIF animation
  if [ "$frames" ]; then
    convert -delay 0 -dispose none -loop 0  "$i" +repage \
            -scene $init +adjoin  "${name}_${fmt}.${sfx}"

    # Fix the X Pixmap color tables
    # using the AIcons Library "xpm-fix" script
    if [ "$sfx" = 'xpm' ] && cmd_found xpm-fix; then
      [ "$VERBOSE" ] && echo_n " pixmap-fixes"
      xpm-fix `sed -n "s/ *BASENAME_/${name}_/p" ${name}.anim`
    fi
  fi

  [ "$VERBOSE" ] && echo " DONE"

done


