#!/bin/bash
#
# Video/Photo thumbnailer
# ./ffthumb VID|PIC|NUM
# will create default size 180x140 png thumbnails
# 9 photos in 3x3 grid, and one extra on the side of #1
# pictures will be scaled down and fit on a pad or cropped (keeping aspect ratio)
# can be used in CSS to create an animated loop through of 9 picture preview thumbs
#
# WARNING: IF YOU RUN THIS IN 'NUM' MODE IN ANY FOLDER IT WILL MAKE ALL FILES
# NUMBERIZED 1.ext, 2.ext, 3.ext...!!!**WARNING**
#
# Author: Twily 2018
# Website: twily.info
# Uses: ffprobe, ffmpeg, bc, find, sort, cut, rev, zip
#
MODE="$1" # VID %video% %thumbname% | PIC %folder% %thumbname% | NUM %folder%
IN="$2" # Input folder with pictures (numberized) or a video file
TMBOUT="$3" # Thumbs output name
SIZE_W=180 # Width for each frame (grid is x3)
SIZE_H=140 # Height for each frame (grid is x3)
BG="#000000" # Only for scale mode (pads)
CROPORSCALE="CROP" # SCALE | CROP | STRETCH
FORMAT="jpg" # Out format png|jpg
QUALITY="-q:v 1" # Only JPG, leave blank otherwise
case "$MODE" in
"VID") # Create 3x3 + 1 thumbnail for video file
LN=$(ffprobe -i "$IN" -show_entries format=duration -v quiet -of csv='p=0')
WH=$(ffprobe -i "$IN" -show_streams -v quiet|grep "width\|height" | cut -d = -f 2)
WH=(${WH[0]})
W=${WH[0]}
H=${WH[1]}
AMODE=0
if [ $W -gt $H ]; then
AMODE=1
ASPECT=$(echo "$W/$H" | bc -l)
else
AMODE=-1
ASPECT=$(echo "$H/$W" | bc -l)
fi
OUT=$(echo "$IN" | cut -d. -f1)
PAT=$(echo "$OUT" | cut -d/ -f1)
#TMB="$PAT/$TMBOUT"
TMB="$TMBOUT"
if [ -z "$TMBOUT" ]; then TMB=$OUT; fi
case "$CROPORSCALE" in
"SCALE")
if [ $AMODE -eq 1 ]; then
PAD=$(echo "($SIZE_W-($SIZE_W*$ASPECT))/2" | bc)
ffmpeg -i "$IN" -vf "fps=9/$LN,scale=$SIZE_W:-1,pad=$SIZE_W:$SIZE_H:0:$PAD:$BG,tile=3x3" $QUALITY "$TMB""_.$FORMAT" -y
elif [ $AMODE -eq -1 ]; then
PAD=$(echo "($SIZE_H-($SIZE_H*$ASPECT))/2" | bc)
ffmpeg -i "$IN" -vf "fps=9/$LN,scale=-1:$SIZE_H,pad=$SIZE_W:$SIZE_H:$PAD:0:$BG,tile=3x3" $QUALITY "$TMB""_.$FORMAT" -y
fi
;;
"CROP")
if [ $AMODE -eq 1 ]; then
POS=$(echo "(($SIZE_H*$ASPECT)-$SIZE_W)/2" | bc)
ffmpeg -i "$IN" -vf "fps=9/$LN,scale=-1:$SIZE_H,crop=$SIZE_W:$SIZE_H:$POS:0,tile=3x3" $QUALITY "$TMB""_.$FORMAT" -y
elif [ $AMODE -eq -1 ]; then
POS=$(echo "(($SIZE_W*$ASPECT)-$SIZE_H)/2" | bc)
ffmpeg -i "$IN" -vf "fps=9/$LN,scale=$SIZE_W:-1,crop=$SIZE_W:$SIZE_H:0:$POS,tile=3x3" $QUALITY "$TMB""_.$FORMAT" -y
fi
;;
"STRETCH")
ffmpeg -i "$IN" -vf "fps=9/$LN,scale=$SIZE_W:$SIZE_H,tile=3x3" $QUALITY "$TMB""_.$FORMAT" -y
;;
esac
ffmpeg -i "$TMB""_.$FORMAT" -vf "crop=$SIZE_W:$SIZE_H:0:0" "$TMB.$FORMAT" -y
;;
"PIC") # Create 3x3 + all thumbnails for a picture folder (Need to be numbered 1..2..3..)
FILES=()
while IFS= read -r -d $'\0'; do
FILES+=("$REPLY")
done < <(find "$IN" -maxdepth 1 -type f -print0 | sort -z)
PAT=$(echo "$IN"|rev|cut -d/ -f1|rev)
TMB="$IN/$TMBOUT"
if [ -z "$TMBOUT" ]; then TMB="$IN/$PAT"; fi
rm -rf "$IN/thumbs"
zip -j "$TMB".zip "$IN"/*
mkdir -p "$IN/thumbs"
for x in ${FILES[@]}; do
CUR=$(echo $x|rev|cut -d/ -f1|rev)
EXT=$(echo $x|rev|cut -d. -f1|rev)
NAM=$(echo $CUR|rev|cut -d. -f2|rev)
OUT="$IN/thumbs/$NAM"
PIC="$IN/$CUR"
WH=$(ffprobe -i "$PIC" -show_streams -v quiet|grep "width\|height" | cut -d = -f 2)
WH=(${WH[0]})
W=${WH[0]}
H=${WH[1]}
AMODE=0
if [ $W -gt $H ]; then
AMODE=1
ASPECT=$(echo "$W/$H" | bc -l)
else
AMODE=-1
ASPECT=$(echo "$H/$W" | bc -l)
fi
case "$CROPORSCALE" in
"SCALE")
if [ $AMODE -eq 1 ]; then
PAD=$(echo "($SIZE_W-($SIZE_W*$ASPECT))/2" | bc)
ffmpeg -i "$PIC" -vf "scale=$SIZE_W:-1,pad=$SIZE_W:$SIZE_H:0:$PAD:$BG" $QUALITY "$OUT"".$FORMAT" -y
elif [ $AMODE -eq -1 ]; then
PAD=$(echo "($SIZE_H-($SIZE_H*$ASPECT))/2" | bc)
ffmpeg -i "$PIC" -vf "scale=-1:$SIZE_H,pad=$SIZE_W:$SIZE_H:$PAD:0:$BG" $QUALITY "$OUT"".$FORMAT" -y
fi
;;
"CROP")
if [ $AMODE -eq 1 ]; then
POS=$(echo "(($SIZE_H*$ASPECT)-$SIZE_W)/2" | bc)
ffmpeg -i "$PIC" -vf "scale=-1:$SIZE_H,crop=$SIZE_W:$SIZE_H:$POS:0" $QUALITY "$OUT"".$FORMAT" -y
elif [ $AMODE -eq -1 ]; then
POS=$(echo "(($SIZE_W*$ASPECT)-$SIZE_H)/2" | bc)
ffmpeg -i "$PIC" -vf "scale=$SIZE_W:-1,crop=$SIZE_W:$SIZE_H:0:$POS" $QUALITY "$OUT"".$FORMAT" -y
fi
;;
"STRETCH")
ffmpeg -i "$PIC" -vf "scale=$SIZE_W:$SIZE_H" $QUALITY "$OUT"".$FORMAT" -y
;;
esac
done
MAXW=$(echo "$SIZE_W*3" | bc)
MAXH=$(echo "$SIZE_H*3" | bc)
X2=$(echo "$MAXW-$SIZE_W" | bc)
X1=$(echo "$X2-$SIZE_W" | bc)
Y2=$(echo "$MAXH-$SIZE_H" | bc)
Y1=$(echo "$Y2-$SIZE_H" | bc)
T="$IN/thumbs/"
ffmpeg -i "$T""1.$FORMAT" -i "$T""2.$FORMAT" -i "$T""3.$FORMAT" -i "$T""4.$FORMAT" -i "$T""5.$FORMAT" \
-i "$T""6.$FORMAT" -i "$T""7.$FORMAT" -i "$T""8.$FORMAT" -i "$T""9.$FORMAT" -filter_complex \
"nullsrc=size=$MAXW""x""$MAXH [base]; \
[0:v] scale=$SIZE_W""x""$SIZE_H [upperleft]; \
[1:v] scale=$SIZE_W""x""$SIZE_H [uppermiddle]; \
[2:v] scale=$SIZE_W""x""$SIZE_H [upperright]; \
[3:v] scale=$SIZE_W""x""$SIZE_H [left]; \
[4:v] scale=$SIZE_W""x""$SIZE_H [middle]; \
[5:v] scale=$SIZE_W""x""$SIZE_H [right]; \
[6:v] scale=$SIZE_W""x""$SIZE_H [lowerleft]; \
[7:v] scale=$SIZE_W""x""$SIZE_H [lowermiddle]; \
[8:v] scale=$SIZE_W""x""$SIZE_H [lowerright]; \
[base][upperleft] overlay=shortest=1 [tmp1]; \
[tmp1][uppermiddle] overlay=shortest=1:x=$X1 [tmp2]; \
[tmp2][upperright] overlay=shortest=1:x=$X2 [tmp3]; \
[tmp3][left] overlay=shortest=1:y=$Y1 [tmp4]; \
[tmp4][middle] overlay=shortest=1:x=$X1:y=$Y1 [tmp5]; \
[tmp5][right] overlay=shortest=1:x=$X2:y=$Y1 [tmp6]; \
[tmp6][lowerleft] overlay=shortest=1:y=$Y2 [tmp7]; \
[tmp7][lowermiddle] overlay=shortest=1:x=$X1:y=$Y2 [tmp8]; \
[tmp8][lowerright] overlay=shortest=1:x=$X2:y=$Y2" $QUALITY "$TMB""_.$FORMAT" -y
cp "$T""1.$FORMAT" "$TMB.$FORMAT"
;;
"NUM") # Number *ALL* and any pictures/files in a directory (*WARNING*)
echo "*WARNING* This will numberize ALL files located in '$IN'!"
echo "Are you sure you want to continue? Type 'yes':"
read okrun
if [ "$okrun" == "yes" ]; then
FILES=()
while IFS= read -r -d $'\0'; do
FILES+=("$REPLY")
done < <(find "$IN" -maxdepth 1 -type f -print0 | sort -z)
IDX=1
for x in ${FILES[@]}; do
CUR=$(echo $x|rev|cut -d/ -f1|rev)
EXT=$(echo $x|rev|cut -d. -f1|rev)
NEW="$IDX.$EXT"
echo "$IN/$CUR => $IN/$NEW"
mv "$IN/$CUR" "$IN/$NEW"
((++IDX))
done
else
echo "Terminated."
fi
;;
*)
echo "No mode selected, use VID | PIC | NUM"
;;
esac
exit
Top