Files
video-thumbnail-generator/generator
2020-11-02 20:39:41 -08:00

119 lines
3.3 KiB
Python
Executable File

#!/usr/bin/env python3
"""Video Thumbnail Generator
Usage:
./generator <video> <interval> <width> <height> <columns> <output>
./generator (-h | --help)
./generator --version
Options:
-h --help Show this screen.
--version Show version.
<video> Video filepath.
<interval> Interval em seconds between frames.
<width> Width of each thumbnail.
<height> Height of each thumbnail.
<columns> Total number of thumbnails per line.
<output> Output.
"""
from docopt import docopt
from moviepy.editor import VideoFileClip
from PIL import Image
from click import progressbar
import glob
import os
import random
import shutil
import math
import tempfile
TMP_FRAMES_PATH = tempfile.mkdtemp()
def generate_video_thumbnails(args):
filepath = args['<video>']
interval = int(args['<interval>'])
size = (int(args['<width>']), int(args['<height>']))
output_prefix = get_output_prefix()
columns = int(args['<columns>'])
output = args['<output>']
video_file_clip = VideoFileClip(filepath)
generate_frames(video_file_clip, interval, output_prefix, size)
generate_sprite_from_frames(output_prefix, columns, size, output)
def generate_frames(video_file_clip, interval, output_prefix, size):
duration = video_file_clip.duration
print("Extracting", int(duration / interval), "frames")
frame_count = 0
with progressbar(range(0, int(duration), interval)) as items:
for i in items:
extract_frame(video_file_clip, i, output_prefix, size, frame_count)
frame_count += 1
print("Frames extracted.")
def extract_frame(video_file_clip, moment, output_prefix, size, frame_count):
output = output_prefix + ("%05d.png" % frame_count)
video_file_clip.save_frame(output, t=int(moment))
resize_frame(output, size)
def resize_frame(filename, size):
image = Image.open(filename)
image = image.resize(size, Image.ANTIALIAS)
image.save(filename)
def generate_sprite_from_frames(frames_path, columns, size, output):
frames_map = sorted(glob.glob(frames_path + "*.png"))
master_width = size[0] * columns
master_height = size[1] * int(math.ceil(float(len(frames_map)) / columns))
line, column, mode = 0, 0, 'RGBA'
try:
final_image = Image.new(
mode=mode,
size=(master_width, master_height),
color=(0, 0, 0, 0)
)
final_image.save(output)
except IOError:
mode = 'RGB'
final_image = Image.new(mode=mode, size=(master_width, master_height))
for filename in frames_map:
with Image.open(filename) as image:
location_x = size[0] * column
location_y = size[1] * line
final_image.paste(image, (location_x, location_y))
column += 1
if column == columns:
line += 1
column = 0
final_image.save(output)
shutil.rmtree(TMP_FRAMES_PATH, ignore_errors=True)
print("Saved!")
def get_output_prefix():
if not os.path.exists(TMP_FRAMES_PATH):
os.makedirs(TMP_FRAMES_PATH)
return TMP_FRAMES_PATH + os.sep + ("%032x_" % random.getrandbits(128))
if __name__ == "__main__":
arguments = docopt(__doc__, version='0.0.2')
generate_video_thumbnails(arguments)