安装基础包

1
pip install pillow

脚本

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
from PIL import Image, ImageFont, ImageDraw, ImageFilter
from math import pi, cos, sin, tan
from random import randint
import random

def is_Chinese(ch):
'''判断字符是否为中文'''
if '\u4e00' <= ch <= '\u9fff':
return True
return False

def pentagram(x, y, R, yDegree=0):
'''
计算五角星各个顶点
int R:五角星的长轴
int x, y:五角星的中心点
int yDegree:长轴与y轴的夹角
'''
rad = pi / 180 # 每度的弧度值
r = R * sin(18 * rad) / cos(36 * rad) # 五角星短轴的长度
# 求取外圈点坐标
RVertex = [(x - (R * cos((90 + k * 72 + yDegree) * rad)), y - (R * sin((90 + k * 72 + yDegree) * rad))) for k in range(5)]
# 求取内圈点坐标
rVertex = [(x - (r * cos((90 + 36 + k * 72 + yDegree) * rad)), y - (r * sin((90 + 36 + k * 72 + yDegree) * rad))) for k in range(5)]
# 顶点左边交叉合并
vertex = [x for y in zip(RVertex, rVertex) for x in y]
return vertex

def circle(x, y, r):
'''计算圆的上下左右切点'''
return (x - r, y - r, x + r, y + r)

def draw_rotated_text(image, angle, xy, r, word, fill, font_size, font_xratio, stroke_width, font_flip=False, *args, **kwargs):
"""
image:底层图片
angle:旋转角度
xy:旋转中心
r:旋转半径
text:绘制的文字
fill:文字颜色
font_size:字体大小
font_xratio:x方向缩放比例(印章字体宽度较标准宋体偏窄)
stroke_width: 文字笔画粗细
font_flip:文字是否垂直翻转(印章下部文字与上部是相反的)
"""
if is_Chinese(word):
font = ImageFont.truetype("fangsong.ttf", font_size, encoding="utf-8")
else:
font = ImageFont.truetype("fangsong.ttf", font_size, encoding="utf-8")

# 获取底层图片的size
width, height = image.size
max_dim = max(width, height)

# 创建透明背景的文字层,大小4倍的底层图片
mask_size = (max_dim * 2, max_dim * 2)
mask_resize = (int(max_dim * 2 * font_xratio), max_dim * 2)
mask = Image.new('L', mask_size, 0)

# 在上面文字层的中心处写字,字的左上角与中心对其
draw = ImageDraw.Draw(mask)

# 获取当前设置字体的宽高
bd = draw.textbbox((max_dim, max_dim), word, font=font, align="center", *args, **kwargs)
font_width = bd[2] - bd[0]
font_hight = bd[3] - bd[1]

# 文字在圆圈上下的方向,需要通过文字所在文字图层的位置修正,保证所看到的文字不会上下颠倒
if font_flip:
word_pos = (int(max_dim - font_width / 2), max_dim + r - font_hight)
else:
word_pos = (int(max_dim - font_width / 2), max_dim - r)

# 写字, 以xy为中心,r为半径,文字上边中点为圆周点,绘制文字
draw.text(word_pos, word, 255, font=font, align="center", stroke_width=stroke_width, *args, **kwargs)

# 调整角度,对于Π*n/2的角度,直接rotate即可,对于非Π*n/2的角度,需要先放大图片以减少旋转带来的锯齿
if angle % 90 == 0:
rotated_mask = mask.resize(mask_resize).rotate(angle)
else:
bigger_mask = mask.resize((int(max_dim * 8 * font_xratio), max_dim * 8), resample=Image.BICUBIC)
rotated_mask = bigger_mask.rotate(angle).resize(mask_resize, resample=Image.LANCZOS)

# 切割文字的图片
mask_xy = (max_dim * font_xratio - xy[0], max_dim - xy[1])
b_box = mask_xy + (mask_xy[0] + width, mask_xy[1] + height)
mask = rotated_mask.crop(b_box)

# 粘贴到目标图片上
color_image = Image.new('RGBA', image.size, fill)
image.paste(color_image, mask)

def create_stamp(words_up, words_mid, words_down, fill=(255, 0, 0, 255), H=160, R=250, border=13, r=90, img_wl_path="bg.png", save_path="output.png"):
img_wl = Image.open(img_wl_path)
img = Image.new("RGBA", (2 * (R + 5), 2 * (R + 5)), (255, 255, 255, 0))
draw = ImageDraw.Draw(img)

# 绘制圆弧
draw.arc(circle(R + 5, R + 5, R), start=0, end=360, fill=fill, width=border)

# 绘制五角星
draw.polygon(pentagram(R + 5, R + 5, r), fill=fill, outline=fill)

# 绘制上圈文字
angle_word = 270 / len(words_up)
angle_word_curr = ((len(words_up) - 1) / 2) * angle_word
for word in words_up:
draw_rotated_text(img, angle_word_curr, (R + 5, R + 5), R - border * 2, word, fill, 80, 0.66, 2)
angle_word_curr -= angle_word

# 绘制中圈文字
angle_word = 72 / len(words_mid)
angle_word_curr = -((len(words_mid) - 1) / 2) * angle_word
for word in words_mid:
draw_rotated_text(img, 0, (R + 5 + H * tan(angle_word_curr * pi / 180), R + 5), H, word, fill, 60, 0.7, 1, font_flip=True)
angle_word_curr += angle_word

# 绘制下圈文字
angle_word = 60 / len(words_down)
angle_word_curr = -((len(words_down) - 1) / 2) * angle_word
for word in words_down:
draw_rotated_text(img, angle_word_curr, (R + 5, R + 5), R - border * 2, word, fill, 20, 1, 1, font_flip=True)
angle_word_curr += angle_word

# 随机圈一部分纹理图
pos_random = (randint(0, 200), randint(0, 100))
box = (pos_random[0], pos_random[1], pos_random[0] + 300, pos_random[1] + 300)
img_wl_random = img_wl.crop(box).rotate(randint(0, 360))
img_wl_random = img_wl_random.resize(img.size).convert('L').filter(ImageFilter.GaussianBlur(1))

L, H = img.size
for h in range(H):
for l in range(L):
dot = (l, h)
img.putpixel(dot, img.getpixel(dot)[:3] + (int(img_wl_random.getpixel(dot) / 255 * img.getpixel(dot)[3]),))

# 高斯模糊
img = img.filter(ImageFilter.GaussianBlur(0.6))
img.save(save_path)

def add_varied_noise(image_path, output_path, noise_size=5, noise_prob=0.05):
"""
给图片添加不同形状和大小的透明噪点
:param image_path: 输入图片路径
:param output_path: 输出图片路径
:param noise_size: 噪点的最大大小(像素为单位)
:param noise_prob: 噪点出现的概率
"""
image = Image.open(image_path).convert("RGBA") # 确保图片有透明通道
draw = ImageDraw.Draw(image)

width, height = image.size
for _ in range(int(width * height * noise_prob)): # 根据概率生成噪点数量
# 随机生成噪点的形状和位置
shape_type = random.choice(['circle', 'rectangle', 'line']) # 随机选择形状

# 随机选择噪点的位置
x0 = random.randint(0, width - 1)
y0 = random.randint(0, height - 1)

# 随机选择噪点的大小
size = random.randint(1, noise_size)

# 使用透明颜色(透明度设置为随机值,RGB固定为0)
noise_color = (0, 0, 0, 0) # 透明噪点,透明度随机

# 绘制噪点
if shape_type == 'circle':
draw.ellipse([x0, y0, x0 + size, y0 + size], fill=noise_color)
elif shape_type == 'rectangle':
x1 = x0 + size
y1 = y0 + size
draw.rectangle([x0, y0, x1, y1], fill=noise_color)
elif shape_type == 'line':
# 随机绘制一条线段
x1 = x0 + size
y1 = y0 + size
draw.line([x0, y0, x1, y1], fill=noise_color, width=size)

# 保存带有噪点的图片
image.save(output_path)

def create_white_bg(file_path):
white_image = Image.new("RGB", (1080, 1080), "white")
white_image.save(file_path)

# 示例使用
company_name = "符十三郎云技术工作室"
user_for = "fushisanlang"
company_num = "123"
img_wl_path = "bg.png"
temp_path = f'{company_name}_temp.png'
save_path = f"{company_name}.png"

create_white_bg(img_wl_path)

create_stamp(words_up=company_name, words_mid=user_for, words_down=company_num, img_wl_path=img_wl_path, save_path=temp_path)
add_varied_noise(temp_path, save_path, noise_size=2, noise_prob=0.01)
print(f"{save_path} created..")