本文分享一段利用Python编写的证件照自动排版代码,能够根据用户选择自动调整照片的大小和比例,并自动排版至6寸页面,混合3种类型常用证件照(上面6张1寸,左下2张2寸,右下2张小2寸)
代码中所用到的第三方库包括:Pillow(用于图片处理)
FLASK在线演示:
最终效果图展示:
转载请标明出处
测试图:
目录下准备一个名字为证件照的图片(png or jpg)即可运行
import os
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter
def resize_photo(photo,choice):
if choice == 1:
resized_photo = photo.resize((250,350))
enhancer = ImageEnhance.Sharpness(resized_photo)
resized_photo = enhancer.enhance(2)
return resized_photo
if choice == 2:
resized_photo = photo.resize((350, 500))
enhancer = ImageEnhance.Sharpness(resized_photo)
resized_photo = enhancer.enhance(2)
return resized_photo
if choice == 3:
resized_photo = photo.resize((330, 480))
enhancer = ImageEnhance.Sharpness(resized_photo)
resized_photo = enhancer.enhance(2)
return resized_photo
def cut_photo(photo,choice):
width = photo.size[0]
height = photo.size[1]
rate = height / width
if choice == 1:
if rate < (350/250):
x = (width - int(height / 350 * 250)) / 2
y = 0
cutted_photo = photo.crop((x, y, x + (int(height / 350 * 250)), y + height))
else:
x = 0
y = (height - int(width / 250 * 350)) / 2
cutted_photo = photo.crop((x, y, x + width, y + (int(width / 250 * 350))))
return cutted_photo
if choice == 2:
if rate < (500/350):
x = (width - int(height / 500* 350)) / 2
y = 0
cutted_photo = photo.crop((x, y, x + (int(height / 500* 350)), y + height))
else:
x = 0
y = (height - int(width / 350 * 500)) / 2
cutted_photo = photo.crop((x, y, x + width, y + (int(width / 350 * 500))))
return cutted_photo
if choice == 3:
if rate < (480/330):
x = (width - int(height / 480* 330)) / 2
y = 0
cutted_photo = photo.crop((x, y, x + (int(height / 480* 330)), y + height))
else:
x = 0
y = (height - int(width / 330 * 480)) / 2
cutted_photo = photo.crop((x, y, x + width, y + (int(width / 330 * 480))))
return cutted_photo
try:
photo = Image.open('证件照.jpg')
except:
photo = Image.open('证件照.png')
photo_1 = resize_photo(cut_photo(photo, 1), 1)
width_px, height_px = photo_1.size
txt = str(width_px) + '-' + str(height_px)
print("一寸比列:" + txt)
photo_2 = resize_photo(cut_photo(photo, 2), 2)
width_px, height_px = photo_2.size
txt = str(width_px) + '-' + str(height_px)
print("二寸比列:" + txt)
photo_3 = resize_photo(cut_photo(photo, 3), 3)
width_px, height_px = photo_3.size
txt = str(width_px) + '-' + str(height_px)
print("小二寸比列:" + txt)
# 6寸背景
print_bg = background = Image.new('RGB', (1520, 1020), 'white')
# 1寸证件照布局
print_bg.paste(photo_1, (0, 100))
print_bg.paste(photo_1, (254, 100))
print_bg.paste(photo_1, (508, 100))
print_bg.paste(photo_1, (762, 100))
print_bg.paste(photo_1, (1016, 100))
print_bg.paste(photo_1, (1270, 100))
# 2寸证件照布局
print_bg.paste(photo_2, (40, 500))
print_bg.paste(photo_2, (430, 500))
# 小2寸证件照布局
print_bg.paste(photo_3, (800, 500))
print_bg.paste(photo_3, (1170, 500))
# 证件图框线
draw = ImageDraw.Draw(print_bg)
draw.rectangle((0, 100, 248, 450), outline='black', width=1)
draw.rectangle((254, 100, 502, 450), outline='black', width=1)
draw.rectangle((508, 100, 756, 450), outline='black', width=1)
draw.rectangle((762, 100, 1010, 450), outline='black', width=1)
draw.rectangle((1016, 100, 1264, 450), outline='black', width=1)
draw.rectangle((1270, 100, 1518, 450), outline='black', width=1)
draw.rectangle((40, 500, 390, 1000), outline='black', width=1)
draw.rectangle((430, 500, 780, 1000), outline='black', width=1)
draw.rectangle((800, 500, 1133, 980), outline='black', width=1)
draw.rectangle((1170, 500, 1500, 980), outline='black', width=1)
path = os.getcwd() + "/6寸混合证件照(画质优化).jpeg"
enhancer = ImageEnhance.Sharpness(print_bg)
print_bg = enhancer.enhance(2)
print_bg.save(path)
print_bg.show()
print("完毕!")
FLASK版本:
预览(请上传小质量照片)
python:
from flask import Flask, render_template, request, redirect, url_for, send_file, abort
from werkzeug.utils import secure_filename
from PIL import Image, ImageDraw, ImageEnhance, ImageFilter
import re
import os
app = Flask(__name__)
app.config['MAX_CONTENT_LENGTH'] = 16 * 1024 * 1024 # 限制上传文件的大小为 16MB
# 设置上传文件保存的目录
app.config['UPLOAD_FOLDER'] = os.path.join(app.root_path, 'uploads')
# 如果目录不存在则创建
if not os.path.exists(app.config['UPLOAD_FOLDER']):
os.makedirs(app.config['UPLOAD_FOLDER'])
# 设置处理后的图片保存的目录
app.config['RESULT_FOLDER'] = os.path.join(app.root_path, 'result')
# 如果目录不存在则创建
if not os.path.exists(app.config['RESULT_FOLDER']):
os.makedirs(app.config['RESULT_FOLDER'])
@app.route('/')
def home():
return render_template('home.html')
@app.route('/process_image', methods=['POST'])
def process_image():
# 获取用户上传的文件并保存到本地
file = request.files['file']
filename = secure_filename(file.filename)
file_path = os.path.join(app.config['UPLOAD_FOLDER'], filename)
file.save(file_path)
# 打开上传的图片
photo = Image.open(file_path)
# 处理图片
photo_1 = resize_photo(cut_photo(photo, 1), 1)
photo_2 = resize_photo(cut_photo(photo, 2), 2)
photo_3 = resize_photo(cut_photo(photo, 3), 3)
bg = generate_print_bg(photo_1, photo_2, photo_3)
enhancer = ImageEnhance.Sharpness(bg)
bg = enhancer.enhance(2)
# 将处理后的图片保存到本地
output_filename = 'output.jpg'
output_path = os.path.join(app.config['RESULT_FOLDER'], output_filename)
bg.save(output_path)
# 返回处理后的照片并提供下载链接
return render_template('result.html', filename=output_filename)
@app.route('/show_image/<filename>')
def show_image(filename):
# 定义要显示的图片文件路径和下载链接
photo_url = url_for('show_image', filename=filename)
download_url = url_for('download', filename=filename)
# 将图片路径和下载链接传入模板进行渲染
return render_template('result.html', photo_url=photo_url, download_url=download_url)
@app.route('/download/<filename>')
def download(filename):
path = os.path.join(app.config['RESULT_FOLDER'], filename)
return send_file(path, as_attachment=True)
def resize_photo(photo,choice):
# 处理图片尺寸
if choice == 1:
resized_photo = photo.resize((250,350))
enhancer = ImageEnhance.Sharpness(resized_photo)
resized_photo = enhancer.enhance(2)
return resized_photo
if choice == 2:
resized_photo = photo.resize((350, 500))
enhancer = ImageEnhance.Sharpness(resized_photo)
resized_photo = enhancer.enhance(2)
return resized_photo
if choice == 3:
resized_photo = photo.resize((330, 480))
enhancer = ImageEnhance.Sharpness(resized_photo)
resized_photo = enhancer.enhance(2)
return resized_photo
def cut_photo(photo, choice):
# 剪裁图片
width = photo.size[0]
height = photo.size[1]
rate = height / width
if choice == 1:
if rate < (350 / 250):
x = (width - int(height / 350 * 250)) / 2
y = 0
cutted_photo = photo.crop((x, y, x + (int(height / 350 * 250)), y + height))
else:
x = 0
y = (height - int(width / 250 * 350)) / 2
cutted_photo = photo.crop((x, y, x + width, y + (int(width / 250 * 350))))
return cutted_photo
if choice == 2:
if rate < (500 / 350):
x = (width - int(height / 500 * 350)) / 2
y = 0
cutted_photo = photo.crop((x, y, x + (int(height / 500 * 350)), y + height))
else:
x = 0
y = (height - int(width / 350 * 500)) / 2
cutted_photo = photo.crop((x, y, x + width, y + (int(width / 350 * 500))))
return cutted_photo
if choice == 3:
if rate < (480 / 330):
x = (width - int(height / 480 * 330)) / 2
y = 0
cutted_photo = photo.crop((x, y, x + (int(height / 480 * 330)), y + height))
else:
x = 0
y = (height - int(width / 330 * 480)) / 2
cutted_photo = photo.crop((x, y, x + width, y + (int(width / 330 * 480))))
return cutted_photo
def generate_print_bg(photo_1, photo_2, photo_3):
# 生成6寸混合证件照
print_bg = Image.new('RGB', (1520, 1020), 'white')
# 插入1寸证件照
print_bg.paste(photo_1, (0, 100))
print_bg.paste(photo_1, (254, 100))
print_bg.paste(photo_1, (508, 100))
print_bg.paste(photo_1, (762, 100))
print_bg.paste(photo_1, (1016, 100))
print_bg.paste(photo_1, (1270, 100))
# 插入2寸证件照
print_bg.paste(photo_2, (40, 500))
print_bg.paste(photo_2, (430, 500))
# 插入小2寸证件照
print_bg.paste(photo_3, (800, 500))
print_bg.paste(photo_3, (1170, 500))
# 证件图框线
draw = ImageDraw.Draw(print_bg)
draw.rectangle((0, 100, 248, 450), outline='black', width=1)
draw.rectangle((254, 100, 502, 450), outline='black', width=1)
draw.rectangle((508, 100, 756, 450), outline='black', width=1)
draw.rectangle((762, 100, 1010, 450), outline='black', width=1)
draw.rectangle((1016, 100, 1264, 450), outline='black', width=1)
draw.rectangle((1270, 100, 1518, 450), outline='black', width=1)
draw.rectangle((40, 500, 390, 1000), outline='black', width=1)
draw.rectangle((430, 500, 780, 1000), outline='black', width=1)
draw.rectangle((800, 500, 1133, 980), outline='black', width=1)
draw.rectangle((1170, 500, 1500, 980), outline='black', width=1)
return print_bg
if __name__ == '__main__':
app.run(debug=True)
home.html:
<!doctype html>
<html lang="zh">
<head>
<title>6存照片 - 混合排版1寸、2寸、小2寸证件照 </title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
body {
font-family: Arial, sans-serif;
color: #333;
margin: 0;
padding: 0;
}
h1 {
text-align: center;
margin-top: 30px;
}
form {
display: flex;
flex-direction: column;
align-items: center;
margin-top: 50px;
}
input[type="file"] {
margin-bottom: 20px;
}
button[type="submit"] {
background-color: #007aff;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 5px;
cursor: pointer;
font-size: 16px;
}
footer {
background-color: #eee;
text-align: center;
padding: 10px 0;
margin-top: 50px;
}
footer a {
color: #007aff;
text-decoration: none;
}
</style>
</head>
<body>
<h1> 6存照片 - 混合排版1寸、2寸、小2寸证件照 </h1>
<form action="/process_image" method="post" enctype="multipart/form-data">
<input type="file" name="file" required>
<button type="submit">处理图片</button>
</form>
<footer>
Powered by 派圣. 点击 <a href="https://blog.csdn.net/aimersong69">这里</a> 了解更多信息。
</footer>
</body>
</html>
result.html:
<!DOCTYPE html>
<html lang="zh">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>下载页面</title>
<style>
body {
font-family: Arial, sans-serif;
color: #333;
margin: 0;
padding: 0;
}
h1 {
text-align: center;
margin-top: 30px;
}
img {
display: block;
margin: 50px auto;
max-width: 80%;
height: auto;
box-shadow: 0 5px 10px rgba(0, 0, 0, 0.2);
}
a {
display: block;
text-align: center;
margin: 20px auto;
background-color: #007aff;
color: #fff;
border: none;
padding: 10px 20px;
border-radius: 5px;
text-decoration: none;
font-size: 16px;
width: fit-content;
cursor: pointer;
}
</style>
</head>
<body>
<h1> 请下载... </h1>
<img src="{{ url_for('show_image', filename=filename) }}" alt="Processed image">
<a href="{{ url_for('download', filename=filename) }}"> Download </a>
</body>
</html>