How do I draw text at an angle using python's PIL?

后端 未结 6 1353
暗喜
暗喜 2020-12-04 12:19

Using Python I want to be able to draw text at different angles using PIL.

For example, imagine you were drawing the number around the face of a clock. The number <

相关标签:
6条回答
  • 2020-12-04 12:56

    Draw text into a temporary blank image, rotate that, then paste that onto the original image. You could wrap up the steps in a function. Good luck figuring out the exact coordinates to use - my cold-fogged brain isn't up to it right now.

    This demo writes yellow text on a slant over an image:

    # Demo to add rotated text to an image using PIL
    
    import Image
    import ImageFont, ImageDraw, ImageOps
    
    im=Image.open("stormy100.jpg")
    
    f = ImageFont.load_default()
    txt=Image.new('L', (500,50))
    d = ImageDraw.Draw(txt)
    d.text( (0, 0), "Someplace Near Boulder",  font=f, fill=255)
    w=txt.rotate(17.5,  expand=1)
    
    im.paste( ImageOps.colorize(w, (0,0,0), (255,255,84)), (242,60),  w)
    
    0 讨论(0)
  • 2020-12-04 12:59

    Here is a working version, inspired by the answer, but it works without opening or saving images.

    The two images have colored background and alpha channel different from zero to show what's going on. Changing the two alpha channels from 92 to 0 will make them completely transparent.

    from PIL import Image, ImageFont, ImageDraw
    
    text = 'TEST'
    font = ImageFont.truetype(r'C:\Windows\Fonts\Arial.ttf', 50)
    width, height = font.getsize(text)
    
    image1 = Image.new('RGBA', (200, 150), (0, 128, 0, 92))
    draw1 = ImageDraw.Draw(image1)
    draw1.text((0, 0), text=text, font=font, fill=(255, 128, 0))
    
    image2 = Image.new('RGBA', (width, height), (0, 0, 128, 92))
    draw2 = ImageDraw.Draw(image2)
    draw2.text((0, 0), text=text, font=font, fill=(0, 255, 128))
    
    image2 = image2.rotate(30, expand=1)
    
    px, py = 10, 10
    sx, sy = image2.size
    image1.paste(image2, (px, py, px + sx, py + sy), image2)
    
    image1.show()
    
    0 讨论(0)
  • 2020-12-04 13:09

    Here's a fuller example of watermarking diagonally. Handles arbitrary image ratios, sizes and text lengths by calculating the angle of the diagonal and font size.

    from PIL import Image, ImageFont, ImageDraw
    import math
    
    # sample dimensions
    pdf_width = 1000
    pdf_height = 1500
    
    #text_to_be_rotated = 'Harry Moreno'
    text_to_be_rotated = 'Harry Moreno (morenoh149@gmail.com)'
    message_length = len(text_to_be_rotated)
    
    # load font (tweak ratio based on your particular font)
    FONT_RATIO = 1.5
    DIAGONAL_PERCENTAGE = .5
    diagonal_length = int(math.sqrt((pdf_width**2) + (pdf_height**2)))
    diagonal_to_use = diagonal_length * DIAGONAL_PERCENTAGE
    font_size = int(diagonal_to_use / (message_length / FONT_RATIO))
    font = ImageFont.truetype(r'./venv/lib/python3.7/site-packages/reportlab/fonts/Vera.ttf', font_size)
    #font = ImageFont.load_default() # fallback
    
    # target
    image = Image.new('RGBA', (pdf_width, pdf_height), (0, 128, 0, 92))
    
    # watermark
    opacity = int(256 * .5)
    mark_width, mark_height = font.getsize(text_to_be_rotated)
    watermark = Image.new('RGBA', (mark_width, mark_height), (0, 0, 0, 0))
    draw = ImageDraw.Draw(watermark)
    draw.text((0, 0), text=text_to_be_rotated, font=font, fill=(0, 0, 0, opacity))
    angle = math.degrees(math.atan(pdf_height/pdf_width))
    watermark = watermark.rotate(angle, expand=1)
    
    # merge
    wx, wy = watermark.size
    px = int((pdf_width - wx)/2)
    py = int((pdf_height - wy)/2)
    image.paste(watermark, (px, py, px + wx, py + wy), watermark)
    
    image.show()
    

    Here it is in a colab https://colab.research.google.com/drive/1ERl7PiX6xKy5H9EEMulBKPgglF6euCNA?usp=sharing you should provide an example image to the colab.

    0 讨论(0)
  • 2020-12-04 13:10

    for Linux, I was able to get fonts to work on debian using:

    fnt = ImageFont.truetype('LinLibertine_RB.otf', 40)
    

    or any font library you see under

    ls -lR /usr/share/fonts
    

    the names and examples of fonts are also contained in Gimp if you have that installed.

    0 讨论(0)
  • 2020-12-04 13:12

    It's also usefull to know our text's size in pixels before we create an Image object. I used such code when drawing graphs. Then I got no problems e.g. with alignment of data labels (the image is exactly as big as the text).

    (...)
    img_main = Image.new("RGB", (200, 200))
    font = ImageFont.load_default()
    
    # Text to be rotated...
    rotate_text = u'This text should be rotated.'
    
    # Image for text to be rotated
    img_txt = Image.new('L', font.getsize(rotate_text))
    draw_txt = ImageDraw.Draw(img_txt)
    draw_txt.text((0,0), rotate_text, font=font, fill=255)
    t = img_value_axis.rotate(90, expand=1)
    

    The rest of joining the two images together is already described on this page. When you rotate by an "unregular" angle, you have to improve this code a little bit. It actually works for 90, 180, 270...

    0 讨论(0)
  • 2020-12-04 13:17

    I'm not saying this is going to be easy, or that this solution will necessarily be perfect for you, but look at the documentation here:

    http://effbot.org/imagingbook/pil-index.htm

    and especially pay attention to the Image, ImageDraw, and ImageFont modules.

    Here's an example to help you out:

    
    import Image
    im = Image.new("RGB", (100, 100))
    import ImageDraw
    draw = ImageDraw.Draw(im)
    draw.text((50, 50), "hey")
    im.rotate(45).show()
    

    To do what you really want you may need to make a bunch of separate correctly rotated text images and then compose them all together with some more fancy manipulation. And after all that it still may not look great. I'm not sure how antialiasing and such is handled for instance, but it might not be good. Good luck, and if anyone has an easier way, I'd be interested to know as well.

    0 讨论(0)
提交回复
热议问题