Search code examples
pythonmathpython-imaging-library

PIL paste image dead center at position


I'm having a bit of a problem to get an image pasted on the exact wanted position. The biggest problem is because I'm rotating the image I'm pasting.

import math
import sys

from PIL import Image, ImageDraw, ImageFont

def main(argv):
    img = Image.new("RGB", (
        300, 300), (255, 255, 255))
    dr = ImageDraw.Draw(img)
    dr.ellipse((0, 0, 300, 300), fill='white', outline='blue', width=2)
    dr.ellipse((25, 25, 275, 275), fill='white', outline='blue', width=2)
    dr.point((150, 150), fill="red")

    for x in range(6):
        print(x)
        value = (2 * x * math.pi) / 6
        value_x = math.floor(138 * math.cos(value) + 150)
        value_y = math.floor(138 * math.sin(value) + 150)
        print(value_x)
        print(value_y)
        dr.line([150, 150, value_x, value_y], fill='red', width=1, joint=None)
        rotate(str(x), math.ceil(value * (180 / math.pi)), img, value_x, value_y)

    #img.save("output/image.png", "PNG")
    img.show()


def rotate(text: str, degrees, img, x, y):
    ft = ImageFont.truetype('font/Roboto-Regular.ttf', 12)
    tim = Image.new('RGBA', (7*len(str(text)), 12), (100, 100, 100, 100))
    dr = ImageDraw.Draw(tim)
    dr.text([0, 0], text, font=ft, fill='red')
    tim = tim.rotate(360-degrees-90, expand=1)
    #tim.save("output/tim" + str(degrees) + ".png", "PNG")
    img.paste(tim, (x, y), tim)


if __name__ == "__main__":
    main(sys.argv[1:])

or

https://programiz.pro/learn/python/online-ide/EZNBPNRQP1?utm_source=programiz_dot_com_python_compiler_save_button

I can't get this running in the online editor, keeps saying the roboto-regular.ttf file is unknown. However the output if you run it in an IDE is the following

as you can see in the image, the numbers should be put at the end of the radian line dead center. I just can't get my offsets right I'm missing some math thing I believe to calculate the correct position.

enter image description here

I could use any help to try and get the offsets right. It should have something to do with the size of the temporary image, but even if I take the width and length and divide it by two it still goes wrong :( I'm missing something


Solution

  • I fixed it, it was obvious. I had to calculate the offset AFTER the rotation, since the rotation expands the image as well

    import math
    import sys
    
    from PIL import Image, ImageDraw, ImageFont
    
    def main(argv):
        img = Image.new("RGB", (
            300, 300), (255, 255, 255))
        dr = ImageDraw.Draw(img)
        dr.ellipse((0, 0, 300, 300), fill='white', outline='blue', width=2)
        dr.ellipse((25, 25, 275, 275), fill='white', outline='blue', width=2)
        dr.point((150, 150), fill="red")
    
        range_value = 12
    
        for x in range(range_value):
            value = (2 * x * math.pi) / range_value
            value_x = math.floor(138 * math.cos(value) + 150)
            value_y = math.floor(138 * math.sin(value) + 150)
            #dr.line([150, 150, value_x, value_y], fill='red', width=1, joint=None)
            rotate(str(x), math.ceil(value * (180 / math.pi)), img, value_x, value_y)
    
        img.save("output/image.png", "PNG")
    
    
    def rotate(text: str, degrees, img, x, y):
        ft = ImageFont.truetype('font/Roboto-Regular.ttf', 20)
        tim = Image.new('RGBA', (12*len(str(text)), 20), (0, 0, 0, 0))
    
        dr = ImageDraw.Draw(tim)
        dr.text([0, 0], text, font=ft, fill='blue')
        tim.save("output/tim" + str(text) + ".png", "PNG")
        tim = tim.rotate(360-degrees-90, expand=1)
        w, h = tim.size
        img.paste(tim, (x-math.floor(w/2), y-math.floor(h/2)), tim)
    
    
    if __name__ == "__main__":
        main(sys.argv[1:])
    

    enter image description here