python - 水印:将旋转的文本粘贴到空图像
问题描述
我想旋转并通过旋转的图像,就像在附加的图像中一样。我的结果没有居中,文字不在图像中。图像尺寸为 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')
解决方案
创建正常的水平水印更容易,因为它需要的工作更少。
您必须创建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')
推荐阅读
- c# - 用于对象表示和托管/非托管交互的结构/类元数据
- php - 在 PHP Web 服务的正文请求中传递 JSON
- azure - 可选客户端证书的应用服务 DNS、CustomDomain 和 TLS 设置
- css - 有没有办法输入检查 CSS 自定义属性(又名 CSS 变量)?
- jmeter - 在另一个变量中调用用户定义的变量
- google-chrome - 如何处理导致我的网站更新延迟的缓存
- neo4j - Neo4j - 无法使用 Neo4J Docker 4.2.5 运行多个密码文件
- angularjs - 在Angular Js中阻止websocket服务器上的新客户端连接
- firebase - php web 的 Firebase 电话验证,无需使用 Google 模板
- laravel - 在 laravel 中使用 model belongsTo 两个 Id 作为关系