首页 > 解决方案 > 水印:将旋转的文本粘贴到空图像

问题描述

我想旋转并通过旋转的图像,就像在附加的图像中一样。我的结果没有居中,文字不在图像中。图像尺寸为 794x1096 可以请您帮帮我吗?

这是我的代码:

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')

例子

标签: pythonpython-imaging-library

解决方案


创建正常的水平水印更容易,因为它需要的工作更少。

您必须创建RGBA与原始图像大小相同但背景透明的新空图像(..., ..., ..., 0)。接下来,您可以在这个新的图像文本上以不同的透明度和不同的位置进行绘制。最后,您必须使用Image.alpha_composite(original_image, text_image)以预期透明度将文本放在图像上。

要将文本放在中心,您必须使用计算其上/左角

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

在此处输入图像描述

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')

现在您可以将文本放在不同的位置,并且可以for为此使用 -loop

在此处输入图像描述

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')

放置旋转图像需要更多的工作,因为首先您必须使用文本生成图像,旋转它,然后使用 将其放在透明图像paste()上,最后使用 将透明图像放在原始图像上alpha_composite()

在此处输入图像描述

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')

这个版本是通用的,因为你也可以使用这个方法来放置水平文本——你只需要跳过rotate()。如果需要,您还可以添加一些重新缩放或其他修改。

但是当文本图像太大并且一个带有文本的矩形与另一个带有文本的矩形重叠时,它可能会出现问题,因为paste()删除了以前的内容。然后它需要更复杂的版本alpha_composite()而不是paste()


顺便说一句:来自维基百科的Lenna的原始图片:

在此处输入图像描述


编辑:

以前的版本存在重叠文本图像的问题

在此处输入图像描述

新版本将每个文本单独组合并解决了这个问题。

在此处输入图像描述

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')

编辑:

我更改代码以使用行中的行数来计算位置。

对于 2 个单词,我将宽度分成 3 个部分。在这个版本中,我使用线条来显示这些部分。文本中心代替交叉线。

在此处输入图像描述

这种计算有一个缺点 - 它会在图像周围产生更大的边距。

它会通过不同的计算来减少它。它必须获得图像宽度并减去 2*text_width ,然后将其分成 3 个部分。然后第一个元素的位置需要1*part_size + 0*text_with,第二个2*part_size + 1*text_with,第n个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')

具有更好计算边距的代码

在此处输入图像描述

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')

推荐阅读