Reputation: 103
I want to write a python program that converts given text into an image. There are tutorials for it online, but I want to curve the text over a circle.
Let's say I have the text "YOUR CURVED TEXT".
I want to draw this on an image and end up with something like following:
I checked Pillow and OpenCV. I might be making a mistake but I don't think they have any functionality for curving the given text?
What would be the best way to do this?
Thanks in advance.
Upvotes: 1
Views: 4089
Reputation: 73
I have been working on the same problem, and could achieve very crude transparent PNG output just using PIL. This could be a decent starting point if you want to stick to PIL, feel free to optimise it further. Hope this helps someone.
from PIL import Image, ImageDraw, ImageFont, ImagePath
import math
import random
def draw_rotated_text(img, text, position, font, t_angle, fill):
# Create a new blank image with a transparent background
text_image = Image.new("RGBA", (img.width//10,img.height//10), (0, 0, 0, 0))
# Get a new drawing context for the text image
text_draw = ImageDraw.Draw(text_image)
# Draw the text on the text image
text_draw.text((0, 0), text, font=font, fill=fill)
# Rotate the text image
rotated_text_image = text_image.rotate(t_angle, expand=True,center=(15,15))
# Get the transparency mask of the rotated text image
mask = rotated_text_image.split()[3]
# Paste the rotated text image onto the original image
#draw.im.paste(rotated_text_image, position, rotated_text_image)
img.paste(rotated_text_image, (position[0], position[1], position[0] + rotated_text_image.width, position[1] + rotated_text_image.height), rotated_text_image)
#draw.im.paste(mask, (position[0], position[1], position[0] + rotated_text_image.width, position[1] + rotated_text_image.height), rotated_text_image)
#img.paste( ImageOps.colorize(rotated_text_image, (0,0,0), (255,255,84)), (242,60), rotated_text_image)
def draw_text_circular(draw, img, text, font, radius, center_x, center_y, start_angle, text_color):
# Iterate over each character in the text
for char in text:
# Calculate the position of the character along the circular path
angle = math.radians(start_angle)
x = center_x + int(radius * math.cos(angle))
y = center_y + int(radius * math.sin(angle))
#draw.text((x, y), char, font=font, fill=text_color)
char_rotation_angle = 270-start_angle
draw_rotated_text(img, char, (x, y), font, char_rotation_angle, text_color)
# Increment the angle for the next character
start_angle += 180 / len(text)
def circular_design(line, font_path):
# Create a blank image with an RGBA mode for transparency
img = Image.new('RGBA', (800, 800), color=(255, 255, 255, 0))
draw = ImageDraw.Draw(img)
# Center of the circular path
center_x, center_y = img.width // 2, img.height // 2
# Radius of the circular path
radius = 300
# Starting angle for the text
start_angle = 180
# Load the font
font_size = 50 # You can adjust the font size
font = ImageFont.truetype(font_path, size=font_size)
# Get a random light color (pastel colors)
text_color = (25,25,25, 255)
# Draw text in a circular path
draw_text_circular(draw, img, line, font, radius, center_x, center_y, start_angle, text_color)
# Save or display the result
img.save("circular_text.png")
img.show()
# Example usage
line = "Your quote goes here Customize as needed"
font_path = r"c:\windows\fonts\DEADJIM.TTF" # Replace with the actual path to your font file
circular_design(line, font_path)
Upvotes: 0
Reputation: 121
thanks to fmw42 for the answer above. I slightly modified this to allow for a transparent background and to do negative angles as well. My first submission to give back to this wonderful community :)
import wand
def curved_text_to_image(
text: str,
font_filepath: str,
font_size: int,
color: str, #assumes hex string
curve_degree: int):
"""
Uses ImageMagik / wand - so have to ensure its installed.
"""
with wand.image.Image(width=1, height=1, resolution=(600, 600)) as img: # open an image
with wand.drawing.Drawing() as draw: # open a drawing objetc
# assign font details
draw.font = font_filepath
draw.font_size = font_size
draw.fill_color = wand.color.Color(color)
# get size of text
metrics = draw.get_font_metrics(img, text)
height, width = int(metrics.text_height), int(metrics.text_width)
# resize the image
img.resize(width=width, height=height)
# draw the text
draw.text(0, height, text)
draw(img)
img.virtual_pixel = 'transparent'
# curve_degree arc, rotated 0 degrees - ie at the top
if curve_degree >= 0:
img.distort('arc', (curve_degree, 0))
else:
# rotate it 180 degrees, then distory and rotate back 180 degrees
img.rotate(180)
img.distort('arc', (abs(curve_degree), 180))
img.format = 'png'
wand.display.display(img)
return img
Upvotes: 4
Reputation: 53164
You can do something like that in ImageMagick using -distort arc 360.
convert -font Arial -pointsize 20 label:' Your Curved Text Your Curved Text ' -virtual-pixel Background -background white -distort Arc 360 -rotate -90 arc_circle_text.jpg
You can do that also in Python Wand, which uses ImageMagick as follows:
from wand.image import Image
from wand.font import Font
from wand.display import display
with Image() as img:
img.background_color = 'white'
img.font = Font('Arial', 20)
img.read(filename='label: Your Curved Text Your Curved Text ')
img.virtual_pixel = 'white'
# 360 degree arc, rotated -90 degrees
img.distort('arc', (360,-90))
img.save(filename='arc_text.png')
img.format = 'png'
display(img)
Thanks to Eric McConville for helping with the label: code.
Upvotes: 4