利用pyton的PIL,可以很容易的实现印章生成。
但这里细节比较多,例如姓名字数、透明度、噪点、模糊、纹理、旋转角度等等,如果都想齐全了,还得花费一番功夫。
这里记录一下算法的过程,主要过程就是
- 生成要印的四个字
- 绘制圆角矩形
- 在四个位置上绘用魏碑字体绘制四个字
- 用纹理图片上随机截取的片段,来给印章添加纹理
- 用高斯模糊,让印章更加真实
- 在word模板里,更改模板印章的透明度设置,这样后面更改图片后,印章能获得合适的透明度。
from random import randint
from PIL import Image, ImageDraw, ImageFont, ImageFilter
from django.conf import settings
from django.core.exceptions import ValidationError
from django.db import models
def validate_leader(strs):
if len(strs) < 2 or len(strs) > 4:
raise ValidationError(u'姓名长度2~4个中文')
for _char in strs:
if not '\u4e00' <= _char <= '\u9fa5':
raise ValidationError(u'姓名只能为中文')
def seal_cover_path(instance, filename):
return f"human/seal/{instance.id}.png"
class Leave(models.Model):
leader = models.CharField('申报人', max_length=4, validators=[validate_leader, ])
stamp = models.ImageField(verbose_name='呈报人印章', null=True, blank=True, upload_to=seal_cover_path)
def getChars(self):
if len(self.leader) == 2:
chars = self.leader + '之印'
elif len(self.leader) == 3:
chars = self.leader + '印'
else:
chars = self.leader
return chars
def generate_stamp(self):
""" 生成印章算法 """
img = Image.new("RGBA", (200, 200), (255, 255, 255, 0))
draw = ImageDraw.Draw(img)
draw.rounded_rectangle(((0, 0), (200, 200)), 16, outline='red', width=8)
chars = self.getChars()
font = ImageFont.truetype("C:/Windows/Fonts/STXINWEI.TTF", 92, encoding="utf-8")
draw.text((98, 8), chars[0], fill='red', font=font)
draw.text((98, 98), chars[1], fill='red', font=font)
draw.text((2, 8), chars[2], fill='red', font=font)
draw.text((2, 98), chars[3], fill='red', font=font)
wl_path = settings.BASE_DIR / 'human/wl.jpg'
img_wl = Image.open(wl_path)
pos_random = (randint(100, 200), randint(120, 200))
box = (pos_random[0], pos_random[1], pos_random[0] + 400, pos_random[1] + 200)
img_wl_random = img_wl.crop(box)
img_wl_random = img_wl_random.resize(img.size).convert('L').filter(ImageFilter.GaussianBlur(1))
X, Y = img.size
for x in range(X):
for y in range(Y):
dot = (x, y)
img.putpixel(dot,
img.getpixel(dot)[:3] + (int(img_wl_random.getpixel(dot) / 255 * img.getpixel(dot)[3]),))
# 进行一次高斯模糊,提高真实度
self.img = img.filter(ImageFilter.GaussianBlur(0.6))
relative_path = seal_cover_path(self, '')
filename = settings.MEDIA_ROOT / relative_path
if not filename.parent.exists():
filename.parent.mkdir(parents=True, exist_ok=True)
filename = str(filename)
img.save(filename)
self.stamp.name = relative_path
self.save()
def save(self, *args, **kwargs):
""" 需要完成印章生成"""
self.leader = self.leader.replace(' ', '')
super(Leave, self).save(*args, **kwargs)
# 放到后面,这样才有id
if not self.stamp.name:
self.generate_stamp()
wl.jpg
网友评论