In my Script I open a tiff image and have to paste some text on it in the bottom right corner with PIL. So far so good. But the quality of the text is unusable! The the text should be white. Instead it has pixels cut out. It looks as though, when copying the text onto the original image, there is a cutoff on the alpha channel. Even when setting the mask attribute in Image.paste there is no difference.
I thought this is something basic. Is there a way to get usable text on an image in PIL? Or is there a better package?
I am on a MacBook Pro Ventura 13.4.1, PIL 10.0.1, Python 3.8
from PIL import Image as PILImage, ImageDraw, ImageFont
import math
padding = (10, 16)
img = PILImage.open('/path/to/tiff/image.tiff')
draw = ImageDraw.Draw(img)
text = 'Holi Moli, this looks terrible'
font = ImageFont.truetype('/path/to/font/FreeMono.ttf', 24)
text_img = PILImage.new('RGB', img.size, (255, 255, 255))
textImg = ImageDraw.Draw(text_img)
# get size of rendered text
bbox = draw.textbbox((0,0), text, font)
# calculate position of text background
bgX = img.width - padding[0] - bbox[2]
bgY = img.height - padding[1] - bbox[3]
textX = img.width - math.ceil(padding[0] * 0.5) - bbox[2]
textY = img.height - math.ceil( padding[1] * 0.5) - bbox[3]
draw.text(xy=(textX, textY), text=text, font=font, fill=(255, 255, 255, 0))
img.paste(im=draw._image, box=(0, 0), mask=draw._image)
img.show()
SOLVED: Two things have to be considered. As suggested in @MarkSetchell's answer I did not need to draw the text onto another context. But the real problem with the badly rendered text came from using RGBA Mode.
I do not know why, but it seems that there is a problem with the alpha channel when drawing text in rgba mode. No matter if I draw it directly onto the opened image or copy it from another context. But most important: I could solve my issue by using RGB Mode on the image.
Sample images including exif data from this repo: https://github.com/ianare/exif-samples/tree/master/tiff
Not sure why you have these 2 lines:
text_img = PILImage.new('RGB', img.size, (255, 255, 255))
textImg = ImageDraw.Draw(text_img)
Nor am I sure why you are pasting the text onto the image when you have already drawn it. So, if you simplify your code to incorporate the above ideas, you get:
#!/usr/bin/env python3
from PIL import Image as PILImage, ImageDraw, ImageFont
import math
padding = (10, 16)
img = PILImage.open('BSG1.tiff')
draw = ImageDraw.Draw(img)
text = 'Gar nicht übel'
font = ImageFont.truetype('/Users/mark/Library/Fonts/FreeMono.ttf', 24)
bbox = draw.textbbox((0,0), text, font)
# calculate position of text background
bgX = img.width - padding[0] - bbox[2]
bgY = img.height - padding[1] - bbox[3]
textX = img.width - math.ceil(padding[0] * 0.5) - bbox[2]
textY = img.height - math.ceil( padding[1] * 0.5) - bbox[3]
draw.text(xy=(textX, textY), text=text, font=font, fill=(255, 255, 255))
img.show()