my python script for changing gif and mp4 into ascii animations (you need python and to save this text as a .py file.) :
import concurrent.futures
import os
import subprocess
import sys
import tempfile
import time
from tqdm import tqdm
import moviepy.editor as mp
import os as os_module
from PIL import Image, ImageSequence
import shutil
ASCII_CHARS = [" ", "@", "#", "$", "%", "?", "*", " ", ";", ":", ",", "."]
def get_float_input(prompt, default_value=0.25):
while True:
user_input = input(prompt)
if not user_input.strip(): # If the user just presses Enter, use the default value
return default_value
try:
return float(user_input)
except ValueError:
print("Invalid input. Please enter a number or press Enter for the default value.")
def convert_color_to_transparent(img, color='w'):
img = img.convert("RGBA")
data = img.getdata()
new_data = []
for item in data:
if color == 'w' and item[0] > 200 and item[1] > 200 and item[2] > 200:
new_data.append((255, 255, 255, 0))
elif color == 'b' and item[0] < 50 and item[1] < 50 and item[2] < 50:
new_data.append((0, 0, 0, 0))
elif color == 'g' and item[1] > item[0] * 4 and item[1] > item[2] * 4 and item[1] > 200:
new_data.append((0, 0, 0, 0))
else:
new_data.append(item)
img.putdata(new_data)
return img
def extract_frames(file_path, output_dir, convert_alpha=False, color='w'):
_, file_extension = os.path.splitext(file_path)
if not os.path.exists(output_dir):
os.makedirs(output_dir)
if file_extension.lower() == '.gif':
with
Image.open(file_path) as im:
for i, frame in enumerate(tqdm(ImageSequence.Iterator(im), total=im.n_frames, desc="Extracting GIF frames")):
if convert_alpha:
frame = convert_color_to_transparent(frame, color)
frame.save(f"{output_dir}/frame_{i:03d}.png")
else: # Assuming it's a video file like mp4
clip = mp.VideoFileClip(file_path)
for i, frame in enumerate(tqdm(clip.iter_frames(), total=int(clip.fps * clip.duration), desc="Extracting video frames")):
img = Image.fromarray(frame)
if convert_alpha:
img = convert_color_to_transparent(img, color)
img.save(f"{output_dir}/frame_{i:03d}.png")
clip.close()
def pixel_to_ascii(image):
pixels = list(image.getdata())
ascii_str = []
for pixel in pixels:
if image.mode == "L": # Grayscale mode
# Use the pixel intensity directly
intensity = pixel
else: # Assume RGBA or RGB mode
if len(pixel) == 4 and pixel[3] < 128: # Check for transparency in RGBA
ascii_str.append(' ') # Use space for transparency
continue
intensity = sum(pixel[:3]) // 3 # Average of RGB for grayscale intensity
# Map intensity to ASCII character
index = int((intensity / 255) * (len(ASCII_CHARS) - 1))
ascii_str.append(ASCII_CHARS[index])
return ''.join(ascii_str)
def resize(image, scale, char_aspect_ratio=0.5):
width, height = image.size
new_width = int(width * scale)
new_height = int(new_width * height / width * char_aspect_ratio)
return image.resize((new_width, new_height))
def to_greyscale(image):
return image.convert("L")
def process_single_frame(frame_info):
i, img_path, scale, convert_alpha, color = frame_info
with
Image.open(img_path) as img:
if convert_alpha:
img = convert_color_to_transparent(img, color)
img = resize(img, scale)
greyscale_img = to_greyscale(img)
ascii_str = pixel_to_ascii(greyscale_img)
img_width = greyscale_img.width
ascii_img = "\n".join(ascii_str[i:i img_width] for i in range(0, len(ascii_str), img_width))
return ascii_img
def process_images_to_ascii(directory, scale, convert_alpha, color):
frames_info = []
for i in range(1000): # Adjust as needed
filename = f"frame_{i:03d}.png"
img_path = os.path.join(directory, filename)
if os.path.exists(img_path):
frames_info.append((i, img_path, scale, convert_alpha, color))
else:
break
with concurrent.futures.ProcessPoolExecutor() as executor:
frames = list(tqdm(
executor.map(process_single_frame, frames_info), total=len(frames_info), desc="Converting frames to ASCII"))
return frames
def get_next_filename(base_name="ascii_", extension=".py"):
"""Find the next available filename with the format ascii_001.py, ascii_002.py, etc."""
i = 1
while True:
filename = f"{base_name}{i:03d}{extension}"
if not os.path.exists(filename):
return filename
i = 1
def save_to_python_file(frames, filename=None):
if filename is None:
filename = get_next_filename()
with open(filename, 'w') as f:
# Write utility functions first
f.write('''
import sys
import time
import os as os_module
PLAYBACK_SPEED = 0.01 # Add this line for playback speed
class ErrorFilter:
# ... (keep the rest as is)
def __init__(self):
super().__init__()
self._original = sys.stderr
def write(self, message):
if not message.startswith("ALSA lib pcm.c"):
self._original.write(message)
def flush(self):
self._original.flush()
def clear_screen():
"""Clear the terminal screen."""
os_module.system('clear' if os_module.name != 'nt' else 'cls')
''')
# Write the frames list
f.write("\nframes = [\n")
for frame in frames:
f.write("'''")
f.write(frame.replace("'", "\\'")) # Escape single quotes
f.write("''',\n")
f.write("]\n")
# Add animation playback code
f.write(f'''
# Redirect stderr to suppress ALSA warnings
sys.stderr = ErrorFilter()
# Play the animation
while True:
for frame in frames:
clear_screen()
#print("\033[2J\033[H")
print(frame)
time.sleep(PLAYBACK_SPEED) # Use the PLAYBACK_SPEED variable here
''')
print(f"ASCII animation has been saved to {filename}")
return filename
def main():
# List available files
files = [f for f in os.listdir('.') if f.lower().endswith(('.gif', '.mp4', '.jpg'))]
for idx, file in enumerate(files, 1):
print(f"{idx}. {file}")
choice = int(input("Enter the number of the file to process: ")) - 1
file_path = files[choice]
output_dir = f"{file_path}_frames"
convert_alpha = input("Convert to alpha? (y/n): ").lower() == 'y'
color = 'w'
if convert_alpha:
color = input("Convert white, black, or green to transparent? (w/b/g): ").lower()
extract_frames(file_path, output_dir, convert_alpha=True, color=color)
else:
extract_frames(file_path, output_dir, convert_alpha=False, color=False)
print(f"Frames extracted to {output_dir}")
dirs = [name for name in os.listdir('.') if os.path.isdir(name)]
if not dirs:
print("No subdirectories found.")
return
for idx, dir in enumerate(dirs, 1):
print(f"{idx}. {dir}")
choice = int(input("Enter the number of the folder to process: ")) - 1
selected_dir = dirs[choice]
scale = get_float_input("Enter the scale value for ASCII conversion (e.g., 0.25 for 25%): \n", 0.25)
convert_alpha = input("Convert to alpha? (y/n): ").lower() == 'y'
color = 'w'
if convert_alpha:
color = input("Convert white, black, or green to transparent? (w/b/g): ").lower()
frames = process_images_to_ascii(selected_dir, scale, convert_alpha, color)
filename = save_to_python_file(frames) # Capture the filename here
# Assuming you've just saved your file with save_to_python_file
if filename:
print(f"Attempting to run: {filename}")
subprocess.run(["python", filename])
else:
print("Failed to get a valid filename for execution.")
if __name__ == "__main__":
main()