Skip to content

Instantly share code, notes, and snippets.

@denius
Created April 19, 2025 13:22
Show Gist options
  • Save denius/69d0ea95b9977fd2c0ea289abba3fd63 to your computer and use it in GitHub Desktop.
Save denius/69d0ea95b9977fd2c0ea289abba3fd63 to your computer and use it in GitHub Desktop.
Create movie from a set of image files
#!/bin/bash
# parse args
# args=$(getopt -o i:o:vh --long input:,output:,verbose,help -- "$@")
args=$(getopt -o c::g:s:r:o:tvh -l crop::,geom:,scale:,output:,preserve,trim,verbose,help -a -- "$@")
if [ $? -ne 0 ]; then
echo "Error in args"
exit 1
fi
eval set -- "$args"
echo "args: $@"
crop="-"
geom=""
scale=""
foutput="$foutput"
framerate="25"
preserve=0
trim=0
verbose=0
# parse args
while true; do
case "$1" in
-g|--geom)
geom="$2"
shift 2
;;
-c|--crop)
crop="$2"
shift 2
;;
-s|--scale)
scale="$2"
shift 2
;;
-o|--output)
foutput="$2"
shift 2
;;
-r)
framerate="$2"
shift 2
;;
-v|--verbose)
verbose=1
shift
;;
--preserve)
preserve=1
shift
;;
-t|--trim)
trim=1
shift
;;
-h|--help)
echo "Usage: $0 [--crop CROP] [--geom GEOM] [-v|--verbose]"
exit 0
;;
--)
shift
break
;;
*)
echo "Unknown opt: $1"
exit 1
;;
esac
done
# create workdir
TMPDIR=`mktemp --directory --tmpdir=.`
PWD1=`pwd`
cp -v *.png "$TMPDIR"
# enter to workdir
pushd "$TMPDIR"
# # rename files like "mon-0001.png" or "mon_0001.png" into "0001.png"
# rename -v -f 's/.*[_-](\d+.*)/$1/' *.png
counter=0
for fname in *.png; do
new_name=$(printf "%05d.png" "$counter")
mv -v -- "$fname" "$new_name"
((counter++))
done
# mogrify -trim -resize 100% +repage *.png
# # mogrify -trim -resize 100% -bordercolor white -border 8x8 +repage *.png
if [ -n "$scale" ]; then
parallel -j10 mogrify -resize "$scale" ::: *.png
fi
if [ "$trim" -gt 0 ]; then
parallel -j10 mogrify -trim -bordercolor white -border 8x8 +repage ::: *.png
fi
if [ -n "$geom" ]; then
echo "geom: $geom"
else
# evaluate maximum x and y sizes through all images
sizes=$(convert *.png -format '%[fx:16*int((w+15)/16)]x%[fx:16*int((h+15)/16)]\n' info:)
size_x=$(echo "$sizes" | sed -e "s/\([^x]\+\)x.\+/\1/" | sort -n | tail -n1)
size_y=$(echo "$sizes" | sed -e "s/[^x]\+x\(.\+\)/\1/" | sort -n | tail -n1)
geom="${size_x}x${size_y}"
echo "geom: $geom"
fi
if [ -z $crop ]; then
parallel -j10 mogrify -gravity Center -crop "$geom+0+0" +repage -define 'png:color-type=2' ::: *.png
d # mogrify -gravity Center -crop "$geom+0+0" +repage -define 'png:color-type=2' *.png
elif [ "-" = "$crop" ]; then
# mogrify -trim +repage *.png
if [ "$trim" -eq 0 ]; then
parallel -j10 mogrify -trim -bordercolor white -border 8x8 +repage ::: *.png
fi
else
parallel -j10 mogrify -crop "$crop" -gravity Center +repage -define 'png:color-type=2' ::: *.png
fi
parallel -j10 mogrify -resize $geom -background white -gravity Center -extent $geom +repage -define 'png:color-type=2' ::: *.png
ffmpeg -framerate "$framerate" -i '%05d.png' -f lavfi -i aevalsrc=0 -hide_banner -max_muxing_queue_size 9999 -c:v libx264 -crf 19 -maxrate 4.5M -preset veryslow -flags +global_header -pix_fmt yuv420p -profile:v baseline -vf scale=-1:1080 -movflags +faststart -c:a aac -ac 2 -map 0:v -map 1:a -shortest -r "$framerate" -y "$PWD1/$foutput"
# ffmpeg -i '%05d.png' -hide_banner -r "$framerate" -force_fps -c:a copy -c:v libx264 -crf 18 -profile:v main -tune animation -preset veryslow -vf format=yuv420p,scale=-1:1080 -y "$PWD1/$foutput"
# png2yuv -f "$framerate" -Ip -j '%05d.png' | yuv2lav -b 2048 -o "$PWD1/export.avi"
# HandBrakeCLI --preset "Production Standard" --encoder mpeg4 --vfr -i "$PWD1/export.avi" -o "$PWD1/$foutput"
# ffmpeg -r "$framerate" -i "%05d.png" -c:v libx264 -preset veryslow -vf scale=-1:1080 -y "$PWD1/export.m4v"
# HandBrakeCLI --preset "Production Standard" --encoder mpeg4 --vfr -i "$PWD1/export.m4v" -o "$PWD1/$foutput"
# return from workdir
popd
# delete workdir
if [ "$preserve" -eq 0 ]; then
echo "rm \"$TMPDIR\""
rm -rf "$TMPDIR"
fi
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment