Last active
May 2, 2023 15:13
-
-
Save ikoba/2852944738431d82ebffe6d9e407cc32 to your computer and use it in GitHub Desktop.
Generate a dummy video or an image on macOS
This file contains 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
#!/usr/bin/env bash | |
# | |
# Generate a dummy video or an image. | |
# | |
# The caption text and size (width x height) are drawn on the video or image. | |
# The countdown timer is drawn in the upper right corner of the video. | |
# | |
# This script is intended to be run on macOS. | |
# And it depends on the following packages. | |
# - imagemagick | |
# - ffmpeg | |
# You can install these packages with Homebrew. | |
# `brew install imagemagick ffmpeg` | |
# | |
# To see the usage, execute `dummy -h` | |
# | |
set -euo pipefail | |
output_image="false" | |
size="600x600" | |
caption="Test" | |
font="" | |
default_font1="ヒラギノ角ゴシック-W3" | |
default_font2="Hiragino-Sans-W3" | |
font_size="" | |
foreground="white" | |
background="gray" | |
image_type="png" | |
audio_path="" | |
time="15" | |
out_dir="$(pwd)" | |
function show_usage() { | |
cat << EOS | |
usage: dummy [-i, --image | -v, --video] | |
[-s, --size <geometry>] | |
[-c, --caption <text>] | |
[-f, --font <font_name>] | |
[--list-fonts] | |
[--font-size] | |
[--foreground <color>] | |
[--background <color>] | |
[--image-type <type>] | |
[-a, --audio <file>] | |
[-t, --time <sencond>] | |
[-o, --out <directory>] | |
[-h, --help] | |
options: | |
-i, --image generate an image | |
-v, --video generate a video (default) | |
-s, --size <geometry> specify width and height (default: 600x600) | |
-c, --caption <text> specity caption text (default: Test) | |
-f, --font <name> specify font name (default: "ヒラギノ角ゴシック-W3" or "Hiragino-Sans-W3") | |
--list-fonts list available fonts and exit | |
--font-size <number> specify font point size | |
(default: appropriate value depending on the size) | |
--foreground <color> specify caption text color (default: white) | |
--background <color> specify background color (default: gray) | |
examples of color formats: | |
'lime', '#0f0', '#00ff00', 'rgb(0,255,0)', 'rgb(0,100%,0)' | |
--image-type <type> specify image type (default: png) | |
-a, --audio <file> specify an audio file if you want to merge it with the video | |
-t, --time <second> specify video length in seconds (default: 15) | |
-o, --out <directory> specify output directory (default: working directory) | |
-h, --help show usage and exit | |
EOS | |
} | |
function err() { | |
echo "$*" >&2 | |
} | |
while getopts ivs:c:f:a:t:o:h-: opt; do | |
if [[ -n "${OPTARG+x}" ]]; then | |
optarg="${OPTARG}" | |
if [[ "${opt}" == "-" ]]; then | |
opt="-${OPTARG%%=*}" | |
optarg="${OPTARG/${OPTARG%%=*}/}" | |
optarg="${optarg#=}" | |
if [[ -z "${optarg}" ]] && [[ -n "${!OPTIND+x}" ]] && [[ "${!OPTIND}" != -* ]]; then | |
optarg="${!OPTIND}" | |
shift | |
fi | |
fi | |
fi | |
case "-${opt}" in | |
-i|--image) | |
output_image="true" | |
;; | |
-v|--video) | |
output_image="false" | |
;; | |
-s|--size) | |
size="${optarg}" | |
;; | |
-c|--caption) | |
caption="${optarg}" | |
;; | |
-f|--font) | |
font="${optarg}" | |
;; | |
--list-fonts) | |
convert -list font | grep 'Font:' | sed 's/^ *Font: //' | |
exit | |
;; | |
--font-size) | |
font_size="${optarg}" | |
;; | |
--foreground) | |
foreground="${optarg}" | |
;; | |
--background) | |
background="${optarg}" | |
;; | |
--image-type) | |
image_type="${optarg}" | |
;; | |
-a|--audio) | |
audio_path="${optarg}" | |
;; | |
-t|--time) | |
time="${optarg}" | |
;; | |
-o|--out) | |
out_dir=${optarg%/} | |
;; | |
-h|--help) | |
show_usage | |
exit | |
;; | |
--) | |
break | |
;; | |
-\?) | |
exit 1 | |
;; | |
--*) | |
err "$0: illegal option -- ${opt##-}" | |
exit 1 | |
;; | |
esac | |
done | |
shift $((OPTIND - 1)) | |
if [[ -z "${font}" ]]; then | |
found=$(convert -list font | grep 'Font:' | sed 's/^ *Font: //' | grep -E "${default_font1}|${default_font2}") | |
if [[ "${found}" == "${default_font1}" ]]; then | |
font="${default_font1}" | |
elif [[ "${found}" == "${default_font2}" ]]; then | |
font="${default_font2}" | |
else | |
err "Default font not found. Please specify --font option." | |
exit 1 | |
fi | |
fi | |
if [[ -z "${font_size}" ]] && [[ "${size}" =~ ^([0-9]+)x([0-9]+)$ ]]; then | |
width="${BASH_REMATCH[1]}" | |
height="${BASH_REMATCH[2]}" | |
if (( height < width )) ; then | |
font_size=$((height / 10)) | |
else | |
font_size=$((width / 10)) | |
fi | |
fi | |
escaped_caption="${caption//[:./\\¥*?\"<>|]/_}" | |
file="${escaped_caption}_${size}" | |
temp_dir=$(mktemp -d) | |
if [[ "${output_image}" == "true" ]]; then | |
image_path="${out_dir}/${file}.${image_type}" | |
else | |
image_path="${temp_dir}/${file}.${image_type}" | |
fi | |
# generate an image | |
convert \ | |
-size "${size}" -gravity center \ | |
-font "${font}" -pointsize "${font_size}" \ | |
-fill "${foreground}" -background "${background}" \ | |
caption:"${caption}\n${size}" "${image_path}" | |
if [[ "${output_image}" == "true" ]]; then | |
echo "image generated: ${image_path}" | |
exit | |
fi | |
video_path="${out_dir}/${file}.mp4" | |
video_cmd="ffmpeg -y -loglevel error -loop 1 -i '${image_path}' \ | |
-pix_fmt yuv420p -t ${time} -r 30 '${video_path}' \ | |
-filter_complex \"drawtext=fontfile=/System/Library/Fonts/Menlo.ttc:text='%{eif\:(${time}*1000+999-t*1000)/1000\:d}':fontcolor=white:fontsize=30:x=w-tw-30:y=30:box=1:boxcolor=black@0.5:boxborderw=10:enable='between(t,0,${time})'\"" | |
if [[ -n "${audio_path}" ]]; then | |
video_cmd+=" -stream_loop -1 -i ${audio_path}" | |
fi | |
video_cmd+=" < /dev/null" | |
# generate a video | |
eval "${video_cmd}" | |
echo "video generated: ${video_path}" |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment