Sophie

Sophie

distrib > Mandriva > 2011.0 > x86_64 > by-pkgid > db02b65a5f0d74b8f6c8f1539fce41bb > files > 4

makethumbs-1.239-3mdv2011.0.src.rpm

#! /bin/sh

# This script rotates images.  It'll rotate the original images if it can
# do so safely, otherwise it'll record rotation details and when makethumbs.sh
# runs, it will generate rotated reduced images and thumbnail images.

GLOBAL_rcsid='$Id: rotate.sh,v 1.22 2002/09/28 04:52:16 molenda Exp $'
GLOBAL_rcsrev='$Revision: 1.22 $'

# This script is in the public domain, share and enjoy.
# The latest version is always at http://www.molenda.com/makethumbs/

# Written by Jason Molenda, 2001-11-03.


main ()
{
  enable_atexit_trap_handler
  set_environment ${1+"$@"}
  init_defaults
  find_programs
  parse_args ${1+"$@"}

  if [ $GLOBAL_rotate_original -eq 1 ]
  then
    rotate_images
  else
    record_image_rotations
  fi

  exit 0
}

init_defaults ()
{

  DEFAULT_rotation_filename="rot-state.txt"
  DEFAULT_rotation="none"
  GLOBAL_rotation_filename=$DEFAULT_rotation_filename
  GLOBAL_rotation=$DEFAULT_rotation

  TMPDIR=${TMPDIR-/tmp}

  find_in_path jpegtran
  if [ $RETURN_found -eq 1 ]
  then
    DEFAULT_rotate_original=1
    GLOBAL_have_jpegtran=1
  else
    DEFAULT_rotate_original=0
    GLOBAL_have_jpegtran=0
    check_permissions
  fi
  GLOBAL_rotate_original=$DEFAULT_rotate_original

  GLOBAL_saw_rotate_original=0
  GLOBAL_rotate_version=`echo "$GLOBAL_rcsrev" | sed 's,[^0-9.],,g'`
}

parse_args ()
{
  local optname optarg filez fn

  if [ $# -eq 0 ]
  then
    help
    exit 1
  fi

  while [ $# -gt 0 ]
  do
    optname="`echo $1 | sed 's,=.*,,'`"
    optarg="`echo $1 | sed 's,^[^=]*=,,'`"
    case "$1" in
      -o | --overwrite*)
           if [ "$GLOBAL_saw_rotate_original" -eq 1 ]
           then
             echo ERROR: More than one -o and -p option specified! >&2
             help
             exit 1
           fi
           ARGV_rotate_original=1
           GLOBAL_rotate_original=$ARGV_rotate_original
           GLOBAL_saw_rotate_original=1
         ;;
      -p | --preserve*)
           if [ "$GLOBAL_saw_rotate_original" -eq 1 ]
           then
             echo ERROR: More than one -o and -p option specified! >&2
             help
             exit 1
           fi
           ARGV_rotate_original=0
           GLOBAL_rotate_original=$ARGV_rotate_original
           GLOBAL_saw_rotate_original=1
           check_permissions
         ;;
      -r | --right | --rr | -rr | --clock* | --rotate-right | r)
           GLOBAL_rotation="clockwise"
           shift
           break
         ;;
      -l | --left | --rl | -rl | --counter* | --rotate-left | l)
           GLOBAL_rotation="counter-clockwise"
           shift
           break
         ;;
      --help | -h | --version | -v)
           help
           exit 1
         ;;
      *)
           echo ERROR: I don\'t understand option "$1" 1>&2
           help
           exit 1
         ;;
    esac
    shift
  done

  if [ -n "$GLOBAL_rotation" -a $# -eq 0 ]
  then
    echo ERROR: Rotation specified but no files listed! 1>&2
    exit 1
  fi

  make_tmpfile filez
  GLOBAL_file_list=$RETURN_tmpfile

  while [ $# -gt 0 ]
  do
    fn="$1"
    if echo "$fn" | egrep -i -- '-[trl].jpg$' >/dev/null 2>&1
    then
      shift
      continue
    fi
    divine_filename "$fn"
    if [ -n "$RETURN_filename" ]
    then
      fn="$RETURN_filename"
    else
      shift
      continue
    fi
    echo "$fn" >> $GLOBAL_file_list
    shift
  done
}

help ()
{
# The following exec goop so I don't have to manually redirect every
# message to stderr in this function.
  exec 4>&1    # save stdout fd to fd #4
  exec 1>&2    # redirect stdout to stderr

  if [ $GLOBAL_rotate_original -eq 1 ]
  then
    echo "Usage: `basename $0` [-p|-o] <-r|-l> file1.jpg file2.jpg file3.jpg ..."
    echo ' -p | --preserve     Do not touch original image, even if we can do so safely.'
  else
    echo 'Usage: `basename $0` [-r|-l] file1.jpg file2.jpg file3.jpg ...'
    echo ' -o | --overwrite    Transform original images, not just reduced ones'
  fi

  echo   ' -r | --rotate-right Rotate images to the right (90 deg clockwise)'
  echo   ' -l | --rotate-left  Rotate images to the left (90 deg counter clockwise)'
  echo   ''
  echo   "    `basename $0` tries to rotate images losslessly if possible."
  if [ $GLOBAL_rotate_original -eq 1 ]
  then
    echo   "    Lossless rotation is possible on this system, so it is the default."
  else
    echo   "    Lossless rotation is not possible on this system, so by default the"
    echo   "    original images will not be modified--only the reduced and thumbnail"
    echo   "    images will be rotated."
  fi
  echo   "    You can override this behavior with -o (overwrite) or with -p (preserve)"
  echo   ""
  echo   "    Filenames can be any unique part of the filename.  e.g. if DSCN0532.jpg"
  echo   "    exists, '`basename $0` r 32' will rotate it 90 degrees clockwise."
  echo   ""
  echo   "    You can find the latest verison of this program at http://www.molenda.com/"
  echo   -n "    This is version v$GLOBAL_rotate_version of "
  echo  "`basename $0`."
  exec 1>&4   # Copy stdout fd back from temporary save fd, #4
}


# Don't rotate the image, just record what rotation the user requested
# for when makethumbs creates thumbnails/reduced/etc images.

record_image_rotations ()
{
  local tfile filename normalized_filename

  make_tmpfile roter
  tfile=$RETURN_tmpfile

  cat $GLOBAL_file_list | while read filename
  do
    if grep -i "^[a-z-]* ${filename}$" $GLOBAL_rotation_filename >/dev/null 2>&1
    then
      grep -vi "^[a-z-]* ${filename}$" $GLOBAL_rotation_filename > $tfile
      cat $tfile > $GLOBAL_rotation_filename
    fi
    normalized_filename=`echo "$filename" |
          sed -e 's,.JPG$,.jpg,' -e 's,.jpeg$,.jpg,' -e 's,.JPEG$,.jpg,' \
              -e 's,.PNG$,.png,' -e 's,.GIF$,.gif,'`
    echo "$GLOBAL_rotation $normalized_filename" >> $GLOBAL_rotation_filename
    remove_generated_versions "$filename"
  done
  cat -n $GLOBAL_rotation_filename |  sort -k 3 -k 1n | uniq -f 2 |
      sed 's,^[ 	]*\([0-9]*\)[ 	]*,\1 ,' |
      cut -d ' ' -f 2- > $tfile
  [ -s $tfile ] && cat $tfile > $GLOBAL_rotation_filename
}


# Rotate an image, either losslessly (via jpegtran) or lossy
# (uncompress to pnm, rotate, recompress to jpeg).  This function
# should probably give the user some way of specifying the final
# compression for a lossy rotation.

rotate_images ()
{
  local tfile filename
  if [ $GLOBAL_have_jpegtran -eq 1 ]
  then
    [ $GLOBAL_rotation = "clockwise" ] && degrees=90
    [ $GLOBAL_rotation = "counter-clockwise" ] && degrees=270
  else
    [ $GLOBAL_rotation = "clockwise" ] && degrees=-90
    [ $GLOBAL_rotation = "counter-clockwise" ] && degrees=90
  fi

  make_tmpfile rot
  tfile=$RETURN_tmpfile

  cat $GLOBAL_file_list | while read filename
  do
    if [ ! -f "$filename" ]
    then
      echo WARNING: File \"$filename\" does not exist! >&2
      continue
    fi
    if [ $GLOBAL_have_jpegtran -eq 1 ]
    then
      cat "$filename" | jpegtran -trim -copy all -rotate $degrees > $tfile
    else
      [ $GLOBAL_rotation = "counter-clockwise" ] && degrees=-90
      cat "$filename" | djpeg -ppm | pnmrotate $degrees |
          cjpeg -optimize > $tfile
    fi

    if [ -s $tfile ]
    then
      cat $tfile > "$filename"
      remove_generated_versions "$filename"
    else
      echo ERROR: Rotation of \"$filename\" failed for some reason. 1>&2
    fi

  done
}

# The user may give us a filename fragment, e.g. DSCN0392 instead of
# DSCN0392.jpg, so try to guess what they might mean.  Caller may get
# an empty RETURN_filename, in which case a warning/error should be
# issued to the user.
divine_filename ()
{
  local name i tmp

  name="$*"
  RETURN_filename=""

# Exact match?
  if [ -f "$name" ]
  then
    RETURN_filename="$name"
    return
  fi

# Missing its suffix?

  for i in jpg jpeg gif png tif tiff
  do
    if [ -f "${name}.$i" ]
    then
      RETURN_filename="${name}.$i"
      return
    fi
  done

# Grab any possible matches from the dir listing, see if we luck out.
  make_tmpfile filevars
  tmp=$RETURN_tmpfile

  ls -1 | grep -i "$name" |
          egrep -v '.html$|-[trl].(jpg|gif|png)$' > $tmp
  [ ! -s "$tmp" ] && return

  if [ `cat "$tmp" | wc -l` -eq 1 ]
  then
    RETURN_filename=`cat "$tmp"`
    return
  fi

# If multiple possible matches, report it
  echo WARNING: Unable to guess which file you want to rotate given \"$name\" 1>&2

# FIXME: Maybe some more heuristics could be done.  Like if we have
# multiple filename matches, but only one jpg, use that.  Or use the
# first jpg we find in preference to any others.

  return
}

remove_generated_versions ()
{
  local fn

  fn="$*"
  source_name_to_thumb_name "$fn"
  rm -f "$RETURN_thumb_name"
  source_name_to_reduced_name "$fn"
  rm -f "$RETURN_reduced_name"
  source_name_to_large_name "$fn"
  rm -f "$RETURN_large_name"
}

source_name_to_thumb_name ()
{
  RETURN_thumb_name=`echo "$*" | sed 's,\.[^.]*$,-t.jpg,'`
  if [ "$*" = "$RETURN_thumb_name" ]
  then
    echo ERROR: I couldn\'t create a thumb name for "\"$*\""! >&2
    exit 1
  fi
  if echo "$RETURN_thumb_name" | egrep -- '-t-t\.' >/dev/null 2>&1
  then
    echo ERROR: I couldn\'t create a reduced name for "\"$*\""! >&2
    exit 1
  fi
}

source_name_to_reduced_name ()
{
  RETURN_reduced_name=`echo "$*" | sed 's,\.[^.]*$,-r.jpg,'`
  if [ "$*" = "$RETURN_reduced_name" ]
  then
    echo ERROR: I couldn\'t create a reduced name for "\"$*\""! >&2
    exit 1
  fi
  if echo "$RETURN_reduced_name" | egrep -- '-r-r\.' >/dev/null 2>&1
  then
    echo ERROR: I couldn\'t create a reduced name for "\"$*\""! >&2
    exit 1
  fi
}

source_name_to_large_name ()
{
  RETURN_large_name=`echo "$*" | sed 's,\.[^.]*$,-l.jpg,'`
  if [ "$*" = "$RETURN_large_name" ]
  then
    echo ERROR: I couldn\'t create a large name for "\"$*\""! >&2
    exit 1
  fi
  if echo "$RETURN_large_name" | egrep -- '-l-l\.' >/dev/null 2>&1
  then
    echo ERROR: I couldn\'t create a large name for "\"$*\""! >&2
    exit 1
  fi
}

#########################################################
#### Miscellaneous helper functions (mostly from makethumbs)
#########################################################


# RETURN_found is 1 if found, 0 if not found.  If found, $RETURN_fullname
# contains the path + filename.
find_in_path ()
{
    local OFS i target dir

    target="$*"
    RETURN_fullname=""
    RETURN_found=0
    OFS="$IFS"
    IFS=:
    for i in $PATH
    do
      [ -z "$i" ] && i="."
      if [ -f "$i/$target" ]
      then
        RETURN_fullname="$i/$target"
        RETURN_found=1
        break
      fi
    done
    IFS="$OFS"
}

check_permissions ()
{
  local have_file_write_perms have_dir_write_perms file_exists

  have_file_write_perms=0
  have_dir_write_perms=0
  file_exists=0

  if [ -w . ]
  then
    have_dir_write_perms=1
  fi

  if [ -e $DEFAULT_rotation_filename ]
  then
    file_exists=1
  fi

  if [ $file_exists -eq 1 -a -w $DEFAULT_rotation_filename ]
  then
    have_file_write_perms=1
  fi

  if [ $file_exists -eq 0 -a $have_dir_write_perms -eq 0 ]
  then
    echo ERROR: Cannot write to `pwd` and $DEFAULT_rotation_filename doesn\'t exist! 1>&2
    exit 1
  fi

  if [ $file_exists -eq 1 -a $have_file_write_perms -eq 0 ]
  then
    echo ERROR: Cannot write to $DEFAULT_rotation_filename ! 1>&2
    exit 1
  fi
}

# Look around and see what programs are installed in $PATH.
find_programs ()
{
  local prog varname

  for prog in mktemp
  do
    varname=`echo $prog | tr -d '-'`
    find_in_path $prog
    if [ $RETURN_found -eq 1 ]
    then
      eval GLOBAL_${varname}_is_present=1
    else
      eval GLOBAL_${varname}_is_present=0
    fi
  done
}


# Unnecessary paranoia - makethumbs can successfully operate even
# if you have a umask of 777 thanks to this function.  What the heck.

make_file_owner_read_writable ()
{
  [ -f "$*" ] && chmod u+rw "$*"
}


# Returns a temp file in $RETURN_tmpfile.
# Takes an optional description name argument.
make_tmpfile ()
{
  make_tmpfile_in_a_dir "$TMPDIR" "$1"
}

make_tmpfile_in_cwd ()
{
  make_tmpfile_in_a_dir . "$1"
}

# Returns a temp file in $RETURN_tmpfile.
make_tmpfile_in_a_dir ()
{
  local base_tmpfile n dir name

  dir="$1"
  name="$2"

  [ -z "$dir" ] && dir="$TMPDIR"
  if [ $GLOBAL_mktemp_is_present -eq 1 ]
  then
    RETURN_tmpfile=`mktemp -q "$dir/rotate-${name}.XXXXXXX"`
    touch "$RETURN_tmpfile"
    if [ $? -eq 0 -a ! -L "$RETURN_tmpfile" -a -O "$RETURN_tmpfile" ]
    then
      make_file_owner_read_writable "$RETURN_tmpfile"
      add_cleanup "$RETURN_tmpfile"
      return
    fi
  fi

  base_tmpfile="$dir/rotate-${name}.$$"
  RETURN_tmpfile="$base_tmpfile"
  n=0
  while [ -f "$RETURN_tmpfile" ]
  do
    n=`expr $n + 1`
    RETURN_tmpfile="${base_tmpfile}-$n"
  done
  touch "$RETURN_tmpfile"
  if [ -L "$RETURN_tmpfile" -o ! -O "$RETURN_tmpfile" ]
  then
    echo "ERROR: Did someone try to spoof my tmp file \"$RETURN_tmpfile\"?" 1>&2
    echo "ERROR: I don't know what's up with that.  Aborting."
    exit 1
  fi
  make_file_owner_read_writable "$RETURN_tmpfile"
  add_cleanup "$RETURN_tmpfile"
  return
}

set_environment ()
{
  IFS=" 	
  "
  export IFS
  TMPDIR=${TMPDIR-/tmp}

# Some of the optional programs makethumbs runs suck and will dump
# core with the slightest provocation - suppress that if possible.

  ulimit -c 0 >/dev/null 2>&1

# POSIX 1003.2 doesn't guarantee that echo -n works -- some systems (OK, Solaris)
# require you to put "\c" at the end of the line to avoid the line wrap.
# The general idea here was lifted from autoconf.

  if [ x`(echo -n foo; echo bar) | grep foobar` = xfoobar ]
  then
    ac_n="-n"
    ac_c=""
  else
    ac_n=""
    if [ x`(echo 'foo\c'; echo bar) | grep foobar` = xfoobar ]
    then
      ac_c='\c'
    fi
  fi

# Detect if the 'local' keyword, a somewhat edgy extension to the Bourne
# shell language (har har) is supported.  If not, try to run a shell that
# does support it.  Flow of control won't make it past this part of the
# function--it usually will either return or exec another program.

  testvar=testval
  check_if_local_supported

  if [ "x$ROTATE_AVOID_INF_LOOP" != "x" -a $testvar != testval ]
  then
    echo "Hm, I re-ran myself but local still doesn't work.  Sigh.  We'll see what happens." 1>&2
    return
  fi

  if [ $testvar = testval ]
  then
    return
  fi

  for shell in bash ksh
  do
    find_in_path $shell
    if [ $RETURN_found -eq 1 ]
    then
      echo "Ignore any warnings about 'local' - will try rerunning under ${shell}." 1>&2
      echo "You can skip this rerun step by changing the first line of this script to read" 1>&2
      echo "#! $RETURN_fullname" 1>&2
      echo "Or leave it as it is -- not a big deal." 1>&2
      ROTATE_AVOID_INF_LOOP=didrun
      export ROTATE_AVOID_INF_LOOP
      exec $shell $0 ${1+"$@"}
    fi
  done

  echo "WARNING:  This shell does not seem to support the locak keyword but I" 1>&2
  echo "          could not find a better shell... things may not work well." 1>&2
}

check_if_local_supported ()
{
  local testvar
  testvar=not-testval
}

enable_atexit_trap_handler ()
{
  trap "atexit  0"  0
  trap "atexit  1"  1
  trap "atexit  2"  2
  trap "atexit 15" 15
}

add_cleanup ()
{
  GLOBAL_cleanuplist="$GLOBAL_cleanuplist $*"
}

remove_cleanup ()
{
  local fn
  fn="$*"

  GLOBAL_cleanuplist=`echo $GLOBAL_cleanuplist | sed "s|${fn}||"`
}

atexit ()
{
  trap "" 0 1 2 15
  [ -n "$GLOBAL_cleanuplist" ] && rm -f $GLOBAL_cleanuplist
  [ -n "$1" ] && exit $1
  exit 1
}

#########################################################
#### Call to main
#########################################################

main ${1+"$@"}

exit 0