Image Resizing

From IndyMedia
Jump to navigation Jump to search

SSI

There is no way to test if a file exists with SSI (well apart from generating an error message, which can be customised) but we do have the original image size so we can test if width >= 640 and it's it's 2011/06 or later and then embed a scaled image, but it's not so simple when you have only string' comparisons not numeric ones!

So we can have code like this to test if the image width is greater than 640 in SSI:

<!--#set var="IMG_WIDTH" value="${image["img_width"]}"-->
<!--#set var="IMG_HEIGHT" value="${image["img_height"]}"-->

<noparse><!--#if expr="(${IMG_WIDTH} = /^....$/) || (${IMG_WIDTH} = /^.....$/) || (${IMG_WIDTH} = /^......$/)"--></noparse>
  <comment>if we have more that 4 digits set SCALED=on</comment> <!--#set var="SCALED" value="on"-->
<noparse><!--#elif expr="(${IMG_WIDTH} = /^...$/) && (${IMG_WIDTH} = /^7/) || (${IMG_WIDTH} = /^8/) || (${IMG_WIDTH} = /^9/)" --></noparse>
  <comment>if we have 3 digits and the first one is greater than 6</comment> <!--#set var="SCALED" value="on"-->
<noparse><!--#elif expr="(${IMG_WIDTH} = /^...$/) && (${IMG_WIDTH} = /^6/) && (${IMG_WIDTH} = /^.5/) || (${IMG_WIDTH} = /^.6/) || (${IMG_WIDTH} = /^.7/) || (${IMG_WIDTH} = /^.8/) || (${IMG_WIDTH} = /^.9/)" --></noparse>
  <comment>if we have 3 digits and the first one is 6 and the second is greater or equal 5</comment> <!--#set var="SCALED" value="on"-->
<noparse><!--#elif expr="(${IMG_WIDTH} = /^...$/) && (${IMG_WIDTH} = /^6/) && (${IMG_WIDTH} = /^.4/) && (${IMG_WIDTH} = /^..1/) || (${IMG_WIDTH} = /^..2/) || (${IMG_WIDTH} = /^..3/) || (${IMG_WIDTH} = /^..4/) || (${IMG_WIDTH} = /^..5/) || (${IMG_WIDTH} = /^..6/) || (${IMG_WIDTH} = /^..7/) || (${IMG_WIDTH} = /^..8/) || (${IMG_WIDTH} = /^..9/)" --></noparse>
  <comment>if we have 3 digits and the first one is 6 and the second is 4 and the 3rd is greater than 0</comment> <!--#set var="SCALED" value="on"-->
<!--#else-->
  <comment>we appear to have a number less or equal 640</comment> <!--#set var="SCALED" value="off"-->
<!--#endif-->

And code like this to check the date is 2011/06 or later:

<!--#set var="YEAR" value="${article.creationdate.formatted["yyyy"]}"-->
<!--#set var="MONTH" value="${article.creationdate.formatted["MM"]}"-->
<noparse><!--#if expr="${YEAR} != /^.0/"--></noparse>
  <comment>if the year is greater than 2100</comment> <!--#set var="NEW_IMG" value="on"-->
<noparse><!--#elif expr="${YEAR} != /^..0/"--></noparse>
  <comment>if the year is greater than or equal to 2010</comment>
  <noparse><!--#if expr="${YEAR} != /^...0/"--></noparse>
  <comment>if the year is greater than or equal to 2011</comment>
    <noparse><!--#if expr="${YEAR} = 2011"--></noparse>
      <comment>it's 2011</comment>
      <noparse><!--#if expr="(${MONTH} != 01) && (${MONTH} != 02) && (${MONTH} != 03) && (${MONTH} != 04) && (${MONTH} != 05)"--></noparse>
         <comment>it's 2011/06 or later</comment> <!--#set var="NEW_IMG" value="on"-->
      <!--#else-->
         <comment>it's 2011/05 or earlier</comment> <!--#set var="NEW_IMG" value="off"-->
      <!--#endif-->
    <!--#else-->
      <comment>it's later than 2011</comment> <!--#set var="NEW_IMG" value="on"-->
    <!--#endif-->
  <!--#endif-->
<noparse><!--#elif expr="${YEAR} = /^200./"--></noparse>
  <comment>if the year is less than 2010</comment> <!--#set var="NEW_IMG" value="off"-->
<!--#endif-->

A lot of the above would probably be better off written in Free Marker Classic... if we were running a version that supported numeric operators but it appears we are not...

Script for incron

incron can be set up to run on file creation but you have to be careful not to cause loops by creating new content in the same directory, see:

Update the incron tab at the start of each month, run a script called /usr/local/bin/incron-update which contains:

#!/bin/bash

YEAR=$(date +%Y)
MONTH=$(date +%m)
DIR=/imc/mir/mayday/images/$YEAR/$MONTH

echo "$DIR IN_CLOSE_WRITE /usr/local/bin/exif-strip-resize \$@ \$#" > /etc/incron.d/mayday.conf

Via this crontab:

0 0 1 * * /usr/local/bin/incron-update ; /etc/init.d/incron restart

Save this script as /usr/local/bin/exif-strip-resize:

#!/bin/bash

# this script takes the full path to a jpeg file 
# and the filename, paased from incrond
# it scale big ones and also remove all exif metadata
# from the jpeg

# sub-directory for sacled images
SCALED=scaled

# check for the first command line argument
if [[ $1 ]]; then
  # check it's a directory
  if [[ -d $1 ]]; then
    DIR=$1
  else
    echo "$1 isn't a directory"
    exit
  fi
else
  echo "You need to specify the path to a file as the first argument" 
  exit
fi

# make a directory for the scaled images
if [[ -d $DIR/$SCALED ]]; then
  echo $DIR/$SCALED exists
else
  mkdir $DIR/$SCALED
fi

if [[ $2 ]]; then
  FILE=$2
  echo file is $DIR/$FILE
  # check the file exists
  if [[ -f $DIR/$FILE ]]; then
    # check if it's really a jpg
    TYPE=$(file -bi $DIR/$FILE)
    if [[ $TYPE = "image/jpeg; charset=binary" ]]; then

      # remove exif metadata preserving the image date
      DATE=$(date -r $DIR/$FILE)
      exiv2 rm "$DIR/$FILE"

      # check is a sub-directory for scaled images is writable 
      if [[ -w $DIR/$SCALED ]]; then

        # generate scaled versions of images if they are greater than 640px wide 
        # or 1024px high, maintaining the aspect ratio
        WIDTH=$(identify -format %w $DIR/$FILE)

        if [[ $WIDTH -gt 640 ]]; then
           convert "$DIR/$FILE" -resize 640x1024 -format jpeg -quality 80 "$DIR/$SCALED/$FILE"
           touch -d "$DATE" "$DIR/$SCALED/$FILE"
        fi

        # reset the file date
        touch -d "$DATE" "$DIR/$SCALED/$FILE"

      else
        echo $DIR/$SCALED is not writable
      fi
    else
      echo "$DIR/$FILE is not a jpeg"
    fi
  else
    echo "$DIR/$FILE does not exist"
  fi
else
  echo "$DIR/$FILE isn't a file"
fi

Script to run via cron

This is a script to be run via cron, perhaps once a min to remove exif metadata and to scale jpeg images if they need it.

#!/bin/bash

# this script takes a directory with some jpeg files in and 
# will scale the big ones and also remove all exif metadata
# from the jpegs

# you can set an optional AGE vairable here, if it's set then only 
# files that are newer than AGE will be looked at -- this is handy 
# if the script is running on a cron job, set it to a tile just longer
# than the cron interval, use mins for the value  

AGE=200

# Directory of images is passed to this script via $1, if it's 
# not then we assume that we should run in the current directory.
if [[ $1 ]]; then
  # change to the directory where the images are
  cd $1
  DIR=$(pwd)
else
  DIR=$(pwd)
fi


# get a list of the files, omitting ones that have already been scaled
if [[ $AGE ]]; then
  FILES=$(find -P $DIR -type f -cmin -$AGE -name '*.jpg' ! -name '*\.indyscaled\.jpg')
else
  FILES=$(find -P $DIR -type f -name '*.jpg' ! -name '*\.indyscaled\.jpg')
fi

for file in $FILES; do
#echo file: $file

  # check the file exists
  if [[ -f $file ]]; then

    # check if we can write to the file
    if [[ -w $file ]]; then

      # check if it's really a jpg
      TYPE=$(file -bi $file)
      if [[ $TYPE = "image/jpeg; charset=binary" ]]; then

         # remove exif metadata preserving the image date
         DATE=$(date -r $file)
         exiv2 rm "$file"

         # generate scaled versions of images if they are greater than 640px wide 
         # or 1024px high, maintaining the aspect ratio
         WIDTH=$(identify -format %w $file)
         if [[ $WIDTH -gt 640 ]]; then
            echo scalling $file
            convert "$file" -resize 640x1024 -format jpeg -quality 80 "$file.indyscaled.jpg"
            touch -d "$DATE" "$file.indyscaled.jpg"
         fi

         # reset the file date
         touch -d "$DATE" "$file"

      else

        echo $file is not a jpeg

      fi

    else

      echo $file is not writable

    fi

  else

    echo $file does not exist 

  fi

done