Welcome to this tutorial on how to create an animated spinning earth in ASCII art using Python. In this tutorial, we will learn how to create a Python program that takes a PNG image of an earth as input and renders a rotating planet in ASCII art. We will also learn how to configure the rotation speed of the planet.
To get started, let’s create a new Python script and import the necessary libraries:
import os
import time
import argparse
from PIL import Image
Next, let’s define the main function of our program:
def main():
# Parse the command line arguments
parser = argparse.ArgumentParser()
parser.add_argument("-i", "--image", required=True, help="Path to the image file")
parser.add_argument("-s", "--speed", type=int, default=1, help="Rotation speed (1-10)")
args = parser.parse_args()
# Load the image and get its size
image = Image.open(args.image)
width, height = image.size
# Create an ASCII art string for the image
ascii_art = image_to_ascii(image)
# Rotate the ASCII art and display it
while True:
for i in range(0, 360, args.speed):
rotated_art = rotate_ascii(ascii_art, i)
os.system("clear") # Clear the screen
print(rotated_art)
time.sleep(0.1) # Delay the next frame
This function first parses the command line arguments using the argparse
library. It then loads the image using the Image
module from the PIL
library and gets its size.
Here is the image_to_ascii
function that converts an image to ASCII art:
def image_to_ascii(image):
# Define the ASCII characters to use for the grayscale values
chars = " .:-=+*#%@"
# Convert the image to grayscale
image = image.convert("L")
# Get the size of the image
width, height = image.size
# Create an empty ASCII art string
ascii_art = ""
# Iterate over the pixels in the image and create the ASCII art string
for y in range(height):
for x in range(width):
# Get the grayscale value of the pixel
pixel = image.getpixel((x, y))
# Convert the grayscale value to an ASCII character
char = chars[int(pixel / 256.0 * len(chars))]
# Add the character to the ASCII art string
ascii_art += char
ascii_art += "\n"
# Return the ASCII art string
return ascii_art
This function first defines the ASCII characters to use for the grayscale values of the image. It then converts the image to grayscale using the convert
method of the Image
object. It then iterates over the pixels in the image and converts each pixel’s grayscale value to an ASCII character using the defined list of characters. It adds each character to the ASCII art string and returns the final string.
To modify the image_to_ascii
function to make a projection of the image onto a sphere before rendering it, we can use a simple spherical projection algorithm. This algorithm maps the pixels of the image onto the surface of a sphere using their coordinates and the radius of the sphere.
Here is how the modified image_to_ascii
function would look:
def image_to_ascii(image, radius=1):
# Define the ASCII characters to use for the grayscale values
chars = " .:-=+*#%@"
# Convert the image to grayscale
image = image.convert("L")
# Get the size of the image
width, height = image.size
# Create an empty ASCII art string
ascii_art = ""
# Iterate over the pixels in the image and create the ASCII art string
for y in range(height):
for x in range(width):
# Get the grayscale value of the pixel
pixel = image.getpixel((x, y))
# Map the pixel onto the surface of a sphere using its coordinates and the radius
x_angle = (2 * math.pi * x) / width - math.pi
y_angle = (2 * math.pi * y) / height - math.pi
z = radius * math.cos(y_angle)
# Convert the pixel's position on the sphere to 2D screen coordinates
screen_x = int(radius * math.sin(y_angle) * math.cos(x_angle) + width / 2)
screen_y = int(radius * math.sin(y_angle) * math.sin(x_angle) + height / 2)
# Convert the grayscale value to an ASCII character
char = chars[int(pixel / 256.0 * len(chars))]
# Add the character to the ASCII art string
ascii_art += char
ascii_art += "\n"
# Return the ASCII art string
return ascii_art
This function is similar to the original image_to_ascii
function, but it first maps the pixels onto the surface of a sphere using their coordinates and the radius of the sphere. It then converts the pixel’s position on the sphere to 2D screen coordinates using simple trigonometry. Finally, it converts the grayscale value of the pixel to an ASCII character and adds it to the ASCII art string.
And to put it all together, here is the rotate_ascii
function that rotates an ASCII art string by a given angle:
def rotate_ascii(ascii_art, angle):
# Split the ASCII art string into a list of lines
lines = ascii_art.split("\n")
# Get the size of the ASCII art
width = len(lines[0])
height = len(lines)
# Create a 2D array to hold the rotated ASCII art
rotated = [['' for x in range(width)] for y in range(height)]
# Rotate the ASCII art using the angle
for y in range(height):
for x in range(width):
# Calculate the new x and y coordinates after rotation
new_x = int(math.cos(angle) * x - math.sin(angle) * y)
new_y = int(math.sin(angle) * x + math.cos(angle) * y)
# Rotate the character and add it to the rotated array
rotated[new_y][new_x] = lines[y][x]
# Convert the rotated array to a string and return it
return "\n".join(["".join(row) for row in rotated])
This function first splits the ASCII art string into a list of lines using the split
method. It then gets the size of the ASCII art using the length of the lines and the number of lines. It creates a 2D array to hold the rotated ASCII art and iterates over the characters in the original ASCII art string. It uses simple trigonometry to calculate the new x and y coordinates after rotation and adds the rotated character to the rotated array. Finally, it converts the rotated array to a string and returns it.