Last active
June 3, 2025 14:27
-
-
Save denius/69d0ea95b9977fd2c0ea289abba3fd63 to your computer and use it in GitHub Desktop.
Create movie from a set of image files
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
sname=$(basename "$0") | |
# 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 "$sname: Error in args" | |
exit 1 | |
fi | |
eval set -- "$args" | |
echo "$sname: 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 "$sname: Usage: $0 [--crop CROP] [--geom GEOM] [-v|--verbose]" | |
exit 0 | |
;; | |
--) | |
shift | |
break | |
;; | |
*) | |
echo "$sname: 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 | |
echo "$sname: Processing scale: \"$scale\"" | |
parallel -j10 mogrify -resize "$scale" ::: *.png | |
fi | |
if [ "$trim" -gt 0 ]; then | |
echo "$sname: Processing trim wborder8:" | |
parallel -j10 mogrify -trim -bordercolor white -border 8x8 +repage ::: *.png | |
fi | |
if [ -n "$geom" ]; then | |
echo "$sname: Evaluated geom from args: $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 "$sname: $sizes" | sed -e "s/\([^x]\+\)x.\+/\1/" | sort -n | tail -n1) | |
size_y=$(echo "$sname: $sizes" | sed -e "s/[^x]\+x\(.\+\)/\1/" | sort -n | tail -n1) | |
geom="${size_x}x${size_y}" | |
echo "$sname: Evaluated geom from files: $geom" | |
fi | |
if [ -z $crop ]; then | |
echo "$sname: Processing (from Center) crop = geom: \"$geom+0+0\"" | |
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 | |
echo "$sname: Processing trim wborder8:" | |
parallel -j10 mogrify -trim -bordercolor white -border 8x8 +repage ::: *.png | |
fi | |
else | |
echo "$sname: Processing (from Center) crop: \"$crop\"" | |
parallel -j10 mogrify -crop "$crop" -gravity Center +repage -define 'png:color-type=2' ::: *.png | |
fi | |
echo "$sname: Processing (from Center) geom (resize + extent): \"$geom\"" | |
parallel -j10 mogrify -resize $geom -background white -gravity Center -extent $geom +repage -define 'png:color-type=2' ::: *.png | |
echo "$sname: Processing ffmpeg:" | |
echo "$sname: 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 -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 "$sname: rm \"$TMPDIR\"" | |
rm -rf "$TMPDIR" | |
fi |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment