np3228
np3228

Reputation: 103

How can I draw a curved text using python? Converting text to curved image?

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:

Final result after processing the image

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

Answers (3)

kaushal
kaushal

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)

Output: output

Upvotes: 0

Sue Donhym
Sue Donhym

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

fmw42
fmw42

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

enter image description here

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)

enter image description here

Thanks to Eric McConville for helping with the label: code.

Upvotes: 4

Related Questions