Last active
August 28, 2023 12:18
-
-
Save ScribbleGhost/b15084955edd7d9adc0efbda3e42466b to your computer and use it in GitHub Desktop.
Generate GIFs from either PNG image sequences or video files.
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 python3 | |
# -*- coding: utf-8 -*- | |
""" | |
Script to generate GIFs from PNG sequences, video files, or folders containing PNGs. | |
Requirements: | |
- FFmpeg and Gifski in PATH. | |
Usage: | |
1. Drag and drop files/folders onto this script. | |
2. Follow the on-screen instructions. | |
3. A GIF will be generated in the script's directory. | |
""" | |
import os | |
import sys | |
import shutil | |
import subprocess | |
from pathlib import Path | |
# Script version | |
__version__ = '1.1.0' | |
def is_tool_available(name): | |
"""Check if a given tool is available.""" | |
return shutil.which(name) is not None | |
def is_png(file): | |
"""Check if a file is a PNG.""" | |
return file.lower().endswith('.png') | |
def is_video(file): | |
"""Check if a file is a video.""" | |
exts = ['.mp4', '.avi', '.mkv', '.flv', '.mov', '.wmv', '.webm'] | |
return any(file.lower().endswith(ext) for ext in exts) | |
def find_png_files(folder): | |
"""Find all PNG files in a given folder.""" | |
return [str(f) for f in Path(folder).rglob("*.png")] | |
def generate_gif(files, fps, width, quality, output): | |
"""Generate a GIF using gifski.""" | |
cmd = [ | |
'gifski', '-o', output, '--fps', str(fps), '--quality', str(quality) | |
] | |
if width: # If width is not blank | |
cmd.extend(['--width', str(width)]) | |
cmd.extend(files) | |
subprocess.run(cmd) | |
print(f"Generated {output}") | |
def process_folder(folder, fps, width, quality): | |
"""Handle folder input.""" | |
png_files = find_png_files(folder) | |
if png_files: | |
folder_name = os.path.basename(folder) | |
output = f"{folder_name}_gifski-q{quality}.gif" | |
generate_gif(png_files, fps, width, quality, output) | |
else: | |
print(f"No PNG files found in folder {folder}") | |
def get_common_inputs(): | |
"""Get common inputs for generating GIFs.""" | |
quality = get_integer_input("Enter gifski quality (1-100): ", 1, 100) | |
fps = get_integer_input("Enter FPS: ", 1, 60) | |
width = input("Enter width (leave blank for original): ").strip() | |
return quality, fps, width | |
def get_integer_input(prompt, min_val=None, max_val=None): | |
"""Get integer input within the range [min_val, max_val].""" | |
while True: | |
try: | |
value = int(input(prompt).strip()) | |
if (min_val is not None and value < min_val) or (max_val is not None and value > max_val): | |
print(f"Please enter a value between {min_val} and {max_val}.") | |
continue | |
return value | |
except ValueError: | |
print("Invalid input. Please enter an integer.") | |
def main(files): | |
"""Main function.""" | |
try: | |
if not (is_tool_available("ffmpeg") and is_tool_available("gifski")): | |
print("Install ffmpeg and gifski and try again.") | |
return | |
# Get common settings for all GIFs | |
quality, fps, width = get_common_inputs() | |
for file_or_folder in files: | |
if os.path.isdir(file_or_folder): | |
process_folder(file_or_folder, fps, width, quality) | |
elif is_png(file_or_folder): | |
# Collect PNGs and process them (existing code) | |
pass # You can insert your existing PNG processing code here | |
elif is_video(file_or_folder): | |
# Process video files (existing code) | |
pass # You can insert your existing video processing code here | |
except Exception as e: | |
print(f"Unexpected error: {e}") | |
if __name__ == "__main__": | |
try: | |
dropped_files = sys.argv[1:] | |
if not dropped_files: | |
print("Drag and drop PNG or video files or folders.") | |
else: | |
main(dropped_files) | |
except Exception as e: | |
print(f"Unexpected error: {e}") | |
input("Press Enter to continue...") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Example GIF from an 8K webm video. 90% quality and downscaled to 25fps at 720px.
