In this post, we shall use the image created in the previous post and create a series of images one slightly rotated with respect to the previous. We then use these frames to create the GIF file which provides the animation.
Here is the code for creating the GIF file using the image created in the previous post:
==================
WheelRotator.py
from PIL import Image, ImageDraw
import os
def rotate_image_around_center(image_path, output_path, rotation_angle):
"""Rotates an image around its center without expanding the canvas."""
try:
original_image = Image.open(image_path).convert("RGBA")
#important to convert to RGBA
except FileNotFoundError:
print(f"Error: Image not found at {image_path}")
return None
rotated_image = original_image.rotate(rotation_angle, resample=Image.BICUBIC,\
expand=False) #expand=False
# Create a mask to keep the original image's shape.
mask = Image.new("L", rotated_image.size, 0)
draw = ImageDraw.Draw(mask)
draw.ellipse((0, 0, rotated_image.width, rotated_image.height), fill=255)
#create a circle mask
# Create a new transparent image and paste the rotated image using the mask.
final_image = Image.new("RGBA", rotated_image.size, (0, 0, 0, 0))
#transparent image
final_image.paste(rotated_image, mask=mask)
final_image.save(output_path)
return final_image
def create_rotated_frames_from_image(image_path, output_folder="rotated_frames", \
num_frames=9, rotation_step=25):
"""Creates a series of rotated frames from an existing image."""
if not os.path.exists(output_folder):
os.makedirs(output_folder)
for i in range(num_frames):
output_path = os.path.join(output_folder, f"frame_{i:03d}.png")
rotated_image = rotate_image_around_center(image_path, output_path, \
i * rotation_step)
if rotated_image:
print(f"Created frame: {output_path}")
def create_gif_from_frames(image_folder, output_gif_path="rotated_image.gif"):
"""Creates a GIF from a series of images in a folder."""
images = []
filenames = sorted([f for f in os.listdir(image_folder) if f.endswith(".png")])
for filename in filenames:
filepath = os.path.join(image_folder, filename)
try:
images.append(Image.open(filepath))
except FileNotFoundError:
print(f"Error: Image not found at {filepath}")
return
if images:
images[0].save(output_gif_path, save_all=True, append_images=images[1:], \
duration=100, loop=0)
print(f"GIF created: {output_gif_path}")
else:
print(f"No images found in {image_folder}")
# Example usage:
image_file_path = r"C:\Users\hoden\PycharmProjects\exploreImage\Images\
five_spokes.png"
# Replace with your image path.
create_rotated_frames_from_image(image_file_path)
create_gif_from_frames("rotated_frames")
Here are some notes:
The expand=False
argument in original_image.rotate()
ensures that the canvas size remains the same, preventing the white background from being added.
original_image = Image.open(image_path).convert("RGBA")
converts the image to RGBA (Red, Green, Blue, Alpha). This is crucial for handling transparency
A mask image (mask
) is created with the same size as the rotated image.
ImageDraw.Draw(mask)
is used to draw an ellipse (circle) on the mask, filling it with white (255). This creates a circular mask that will be used to cut out the rotated image.
final_image = Image.new("RGBA", rotated_image.size, (0, 0, 0, 0))
creates a new transparent image with the same size as the rotated image.
final_image.paste(rotated_image, mask=mask)
pastes the rotated image onto the transparent image, using the mask to define the visible area. This effectively removes the unwanted background.
Here is the rotated_jmage.gif
Without using the mask and using expand==true, the effect would have been less satisfactory: