Lorenzo
Lorenzo

Reputation: 31

Watermarking: pasting rotated text to empty image

I want to rotate and past the rotated image just like in the image attached. My result is not centered and the text is out of the image. The image size is 794x1096 May you help me please?

This is my code:

x = input('Insert Name Here ')
y = input('Insert full name')
img = Image.open("Path/watermark_example.png")
draw = ImageDraw.Draw(img)
font = ImageFont.truetype('calibri.ttf', 55)
draw.text((30, 300),x,(128, 128, 128, 255), font=font)
draw.text((500, 500),x,(128, 128, 128, 255),font=font)
img1 = img.rotate(15, expand = True, fillcolor = 'white')
img.putalpha(128)
img.paste(img1)
img.show()
img.save(f'Path/watermark_example{y}.png')

Example

Upvotes: 1

Views: 1562

Answers (1)

furas
furas

Reputation: 143057

It is easier to create normal horizontal watermark because it needs less work.

You have to create new empty image RGBA with the same size as original image but with transparent background (..., ..., ..., 0). Next you can draw on this new image text with different transparency and in different place. Finally you have to use Image.alpha_composite(original_image, text_image) to put text on image with expected transparency.

To put text in center you have to calculate its top/left corner using

x = original_image_width/2 - text_width/2
y = original_image_height/2 - text_height/2

enter image description here

from PIL import Image, ImageDraw, ImageFont

#name = input('Name: ')
name = 'example'

# --- original image ---

#original_image_size = (794, 1096)
#original_image = Image.new('RGBA', image_size, 'white')

original_image = Image.open('lenna.png').convert("RGBA")
original_image_size = original_image.size

# --- watermarks image ---

# image with the same size and transparent color (..., ..., ..., 0)
watermarks_image = Image.new('RGBA', original_image_size, (255,255,255,0))

watermarks_draw = ImageDraw.Draw(watermarks_image)

font = ImageFont.truetype('arial.ttf', 55)

# calculate text size in pixels (width, height)
text_size = font.getsize(name) 

# calculate top/left corner for centered text
#x = (image_size[0] - text_size[0])//2
#y = (image_size[1] - text_size[1])//2

x = original_image_size[0]//2 - text_size[0]//2
y = original_image_size[1]//2 - text_size[1]//2

# draw text 
watermarks_draw.text((x, y), name, (255, 255, 255, 192), font=font)

# --- put watermarks image on original image ---

combined_image = Image.alpha_composite(original_image, watermarks_image)

# --- result ---

combined_image.show()
combined_image.save(f'lenna_1_{name}.png')

Now you can put text in different places and you can use for-loop for this

enter image description here

from PIL import Image, ImageDraw, ImageFont

#name = input('Name: ')
name = 'example'

# --- original image ---

#original_image_size = (794, 1096)
#original_image = Image.new('RGBA', image_size, 'white')

original_image = Image.open('lenna.png').convert("RGBA")
original_image_size = original_image.size

# --- watermarks image ---

# image with the same size and transparent color (..., ..., ..., 0)
watermarks_image = Image.new('RGBA', original_image_size, (255,255,255,0))

watermarks_draw = ImageDraw.Draw(watermarks_image)

font = ImageFont.truetype('arial.ttf', 15)

# calculate text size in pixels (width, height)
text_size = font.getsize(name) 

# calculate top/left corner for centered text
parts = 8
offset_x = original_image_size[0]//parts
offset_y = original_image_size[1]//parts

start_x = original_image_size[0]//parts - text_size[0]//2
start_y = original_image_size[1]//parts - text_size[1]//2

for a in range(0, parts, 2):
    for b in range(0, parts, 2):
        x = start_x + a*offset_x
        y = start_y + b*offset_y
        watermarks_draw.text((x, y), name, (255, 255, 255, 240), font=font)
        
# --- put watermarks image on original image ---

combined_image = Image.alpha_composite(original_image, watermarks_image)

# --- result ---

combined_image.show()
combined_image.save(f'lenna_2_{name}.png')

It needs more work to put rotated image because first you have to generate image with text, rotate it and then put it on transparent image using paste(), and finally you put transparent image on original image using alpha_composite().

enter image description here

from PIL import Image, ImageDraw, ImageFont

#name = input('Name: ')
name = 'example'

# --- original image ---

#original_image_size = (794, 1096)
#original_image = Image.new('RGBA', image_size, 'white')

original_image = Image.open('lenna.png').convert("RGBA")
original_image_size = original_image.size

# --- text image ---

font = ImageFont.truetype('arial.ttf', 55)

# calculate text size in pixels (width, height)
text_size = font.getsize(name) 

# create image for text
text_image = Image.new('RGBA', text_size, (255,255,255,0))

text_draw = ImageDraw.Draw(text_image)

# draw text on image
text_draw.text((0, 0), name, (255, 255, 255, 129), font=font)

# rotate text image and fill with transparent color
rotated_text_image = text_image.rotate(45, expand=True, fillcolor=(0,0,0,0))

rotated_text_image_size = rotated_text_image.size

#rotated_text_image.show()

# --- watermarks image ---

# image with the same size and transparent color (..., ..., ..., 0)
watermarks_image = Image.new('RGBA', original_image_size, (255,255,255,0))

# calculate top/left corner for centered text
x = original_image_size[0]//2 - rotated_text_image_size[0]//2
y = original_image_size[1]//2 - rotated_text_image_size[1]//2

# put text on watermarks image
watermarks_image.paste(rotated_text_image, (x, y))

# --- put watermarks image on original image ---

combined_image = Image.alpha_composite(original_image, watermarks_image)

# --- result ---

combined_image.show()
combined_image.save(f'lenna_3_{name}.png')

This version is universal because you can use this method also to put horizontal text - you have to only skip rotate(). You can also add some rescaling or other modifiacation to if you need.

But it may have problem when text images are too big and one rectangle with text overlap onother rectangel with text because paste() remove previous content. And then it would need more complex version with alpha_composite() instead of paste()


BTW: Original image of Lenna from Wikipedia:

enter image description here


EDIT:

Previous version has problem with overlapping text images

enter image description here

New version combines every text separatelly and it resolves this problem.

enter image description here

from PIL import Image, ImageDraw, ImageFont

#name = input('Name: ')
name = 'example'

# --- original image ---

#original_image_size = (794, 1096)
#original_image = Image.new('RGBA', image_size, 'white')

original_image = Image.open('lenna.png').convert("RGBA")
original_image_size = original_image.size

# --- text image ---

font = ImageFont.truetype('arial.ttf', 55)

# calculate text size in pixels (width, height)
text_size = font.getsize(name) 

# create image for text
text_image = Image.new('RGBA', text_size, (255,255,255,0))

text_draw = ImageDraw.Draw(text_image)

# draw text on image
text_draw.text((0, 0), name, (255, 255, 255, 129), font=font)

# rotate text image and fill with transparent color
rotated_text_image = text_image.rotate(45, expand=True, fillcolor=(0,0,0,0))

rotated_text_image_size = rotated_text_image.size

#rotated_text_image.show()

# --- watermarks image ---

combined_image = original_image

# calculate top/left corner for centered text
parts = 8
offset_x = original_image_size[0]//parts
offset_y = original_image_size[1]//parts

start_x = original_image_size[0]//parts - rotated_text_image_size[0]//2
start_y = original_image_size[1]//parts - rotated_text_image_size[1]//2

for a in range(0, parts, 2):
    for b in range(0, parts, 2):
        x = start_x + a*offset_x
        y = start_y + b*offset_y
        # image with the same size and transparent color (..., ..., ..., 0)
        watermarks_image = Image.new('RGBA', original_image_size, (255,255,255,0))
        # put text in expected place on watermarks image
        watermarks_image.paste(rotated_text_image, (x, y))
        # put watermarks image on original image
        combined_image = Image.alpha_composite(combined_image, watermarks_image)
        
#combined_image.show()

# --- result ---

combined_image.show()
combined_image.save(f'lenna_4b_{name}.png')

EDIT:

I change code to use nubmer of rows in row to calculate position.

For 2 words I split width on 3 parts. In this version I use lines to show these parts. Center of text is in place of crossing lines.

enter image description here

This calculation has one disadvanget - it creates bigger margin around image.

It would different calculations to reduce it. It would have to get image width and substract 2*text_width and then divide it on 3 parts. And then position for first element would need 1*part_size + 0*text_with, for second 2*part_size + 1*text_with, for n-th n*part_size + (n-1)*text_with

from PIL import Image, ImageDraw, ImageFont

#name = input('Name: ')
name = 'example'

# --- original image ---

#original_image_size = (794, 1096)
#original_image = Image.new('RGBA', image_size, 'white')

original_image = Image.open('lenna.png').convert("RGBA")
original_image_size = original_image.size

# --- watermarks image ---

# image with the same size and transparent color (..., ..., ..., 0)
watermarks_image = Image.new('RGBA', original_image_size, (255,255,255,0))

watermarks_draw = ImageDraw.Draw(watermarks_image)

font = ImageFont.truetype('arial.ttf', 35)

# calculate text size in pixels (width, height)
text_size = font.getsize(name) 

# calculate 
words_in_row = 2
words_in_col = 2

parts_x  = words_in_row + 1  # 3
size_x   = original_image_size[0]//parts_x
offset_x = text_size[0]//2  # half of text's width

parts_y  = words_in_col + 1  # 3
size_y   = original_image_size[1]//parts_y
offset_y = text_size[1]//2  # half of text's height

for a in range(1, parts_x, 1):
    line_x = a*size_x
    line_heigth = original_image.size[1]
    watermarks_draw.line((line_x, 0, line_x, line_heigth))
    
    for b in range(1, parts_y, 1):
        line_y = b*size_y
        line_width = original_image.size[0]
        watermarks_draw.line((0, line_y, line_width, line_y))
        
        x = a*size_x - offset_x
        y = b*size_y - offset_y
        watermarks_draw.text((x, y), name, (255, 255, 255, 240), font=font)

# --- put watermarks image on original image ---

combined_image = Image.alpha_composite(original_image, watermarks_image)

# --- result ---

combined_image.show()
combined_image.save(f'lenna_2_{name}.png')

Code with better calculate margins

enter image description here

from PIL import Image, ImageDraw, ImageFont

#name = input('Name: ')
name = 'example'

# --- original image ---

#original_image_size = (794, 1096)
#original_image = Image.new('RGBA', image_size, 'white')

original_image = Image.open('lenna.png').convert("RGBA")
original_image_size = original_image.size

# --- watermarks image ---

# image with the same size and transparent color (..., ..., ..., 0)
watermarks_image = Image.new('RGBA', original_image_size, (255,255,255,0))

watermarks_draw = ImageDraw.Draw(watermarks_image)

font = ImageFont.truetype('arial.ttf', 35)

# calculate text size in pixels (width, height)
text_size = font.getsize(name) 
text_width, text_height = text_size

# calculate 
words_in_row = 2
words_in_col = 4

parts_x  = words_in_row + 1 # 3
margin_x = (original_image_size[0] - words_in_row*text_width)//parts_x
offset_x = text_width//2  # half of text's width

parts_y  = words_in_col + 1  # 3
margin_y = (original_image_size[1] - words_in_col*text_height)//parts_y
offset_y = text_size[1]//2  # half of text's height

for a in range(0, parts_x, 1):
    line_height = original_image.size[1]

    line_x = (a+1) * margin_x + a * text_width
    watermarks_draw.line((line_x, 0, line_x, line_height))

    line_x += text_width
    watermarks_draw.line((line_x, 0, line_x, line_height))
    
    for b in range(0, parts_y, 1):
        line_width = original_image.size[0]

        line_y = (b+1) * margin_y + b * text_height
        watermarks_draw.line((0, line_y, line_width, line_y))

        line_y += text_height
        watermarks_draw.line((0, line_y, line_width, line_y))
        
        x = (a+1) * margin_x + a * text_width
        y = (b+1) * margin_y + b * text_height
        watermarks_draw.text((x, y), name, (255, 255, 255, 240), font=font)

# --- put watermarks image on original image ---

combined_image = Image.alpha_composite(original_image, watermarks_image)

# --- result ---

combined_image.show()
combined_image.save(f'lenna_7_{name}.png')

Upvotes: 7

Related Questions