用Django加PIL做一个证件照模板生成器网页
最近在整理自己的简历,发现简历上面的ID照有些太老了,所以就准备重新准备一些证件照,刚好最近在弄自己的博客网站,想着直接做一个网页工具出来,直接生成证件照模板,这样还可以省去PS的麻烦。而且照片涉及到个人隐私,把照片存储到服务器后端会有诸多问题,所以我就直接全部在内存中处理了
下面是我的处理过程
上传ID照,选择需要的尺寸和底板的大小,然后保存到本地,直接打印即可。
后台主要用到的是PIL和Django。
PIL这块,我用了比较原始的方法,先处理原始照片为对应的尺寸,然后加边框,算出总的长宽,再用地板的长宽相除,算出横竖版本的张数,再用单张乘以张数算出宽高,再粘贴到背景板上。然后就是完整的照片了
我单独写了一个函数处理照片生成的过程,下面附上代码:
#!/usr/bin/env python
# -*- coding: utf-8 -*-
from PIL import Image def preview_pic(img,photo_size,bk_size,bk_color,photo_size_background_dict,photo_size_dict):
try:
# id照尺寸
idsize = photo_size
# 底板尺寸
bgsize = bk_size
# 底板颜色
bgcol = bk_color
# 原始照片
photopath = img
photo = Image.open(photopath)
#处理底板和照片的长宽,将CM转化为像素,我是以300dpi转化的,这个基本就是照片的标准了
back_ground_hight = round(
photo_size_background_dict[bgsize]["h"] *
round(
photo_size_background_dict[bgsize]["dpi"] /
2.54))
back_ground_width = round(
photo_size_background_dict[bgsize]["w"] *
round(
photo_size_background_dict[bgsize]["dpi"] /
2.54))
photo_hight = round(
photo_size_dict[idsize]["h"] *
round(
photo_size_dict[idsize]["dpi"] /
2.54))
photo_width = round(
photo_size_dict[idsize]["w"] *
round(
photo_size_dict[idsize]["dpi"] /
2.54))
#创建空白底板
img_bk = Image.new(
"RGB", (back_ground_width, back_ground_hight), bgcol)
#处理原始照片,将原始照片处理成ID照尺寸
img_photo = photo.resize((photo_width, photo_hight))
img_photo_width = img_photo.size[0]
img_photo_hight = img_photo.size[1]
#给id照加边框,左右上下各10像素
img_photo_with_side = Image.new(
"RGB", (img_photo_width + 20, img_photo_hight + 20), bgcol)
img_photo_with_side.paste(img_photo, (10, 10))
img_photo_with_side_width = img_photo_with_side.size[0]
img_photo_with_side_hight = img_photo_with_side.size[1]
#算出底板横向和纵向的id照张数
width_num = divmod(back_ground_width, img_photo_with_side_width)
hight_num = divmod(back_ground_hight, img_photo_with_side_hight)
#创建带边框的id照的总长和总宽的空白照
img_photo_with_side_total = Image.new(
"RGB",
(img_photo_with_side_width *
width_num[0],
img_photo_with_side_hight *
hight_num[0]),
bgcol)
#开始往空白照上面粘贴id照
for i in range(0, width_num[0]):
for k in range(0, hight_num[0]):
img_photo_with_side_total.paste(
img_photo_with_side, (img_photo_with_side_width * i, img_photo_with_side_hight * k))
#之前已经粘贴好了id照的模板,现在要往总底板上面粘贴了,粘贴好之后会在上下左右空出空间来
img_bk.paste(
img_photo_with_side_total, (int(width_num[1] / 2), int(hight_num[1] / 2)))
return img_bk except BaseException as e:
print(e) def Hex_to_RGB(hex):
r = int(hex[1:3],16)
g = int(hex[3:5],16)
b = int(hex[5:7], 16)
rgb =(r,g,b)
return rgb
还有前端传递到后端的代码:
<div class="jumbotron">
<div class="container">
<div class="row">
<div class="col-12">
<h3 class="text-center">照片生成工具</h3>
</div>
<div class="col-12 mt-3">
<p class="text-wrap">该工具用于批量生成证件照,只需要上传需要生成模板的照片,然后选择想要的参数,系统会自动排版照片,
生成新的照片,模板背景颜色也可以自由选择,目前支持的格式仅限于1寸和2寸,背景照片为A4,6寸和Letter。</p>
<p>照片模板</p>
<span>1寸证件照6寸底片</span>
<img class="img-fluid w-25" alt="" src={% static 'images/pic_tem1.jpg' %} >
<span>1寸证件照A4底片</span>
<img class="img-fluid w-25" alt="" src={% static 'images/pic_tem2.jpg' %} >
<p>使用方法:</p>
<form id="photo_info" role="form" enctype="multipart/form-data" action="">
<ol>
<li class="m-3">
<div class="col-4">
<input class="btn form-control" type="file" accept=".jpg" id="photo">
</div>
</li>
<li class="m-3">
<div class="col-4">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text bg-light">选择照片大小</span>
</div>
<select class="form-control" id="photo_size" name="photo_size">
{% for p_size in photo_size %}
<option value="{{ p_size }}">{{ p_size }}</option>
{% endfor %}
</select>
</div>
</div>
</li>
<li class="m-3">
<div class="col-4">
<div class="input-group">
<div class="input-group-prepend">
<span class="input-group-text bg-light">选择背景大小</span>
</div>
<select class="form-control" id="bk_size" name="bk_size">
{% for p_s_b_k,p_s_b_v in photo_size_background.items %}
<option value="{{ p_s_b_k}}">{{ p_s_b_k }}</option>
{% endfor %}
</select>
</div>
</div>
</li>
<li class="m-3">
<div class="col-4">
<span>选择背景颜色:</span>
<label for="w">白色</label>
<input id="w" type="radio" name="bk_color" value="#ffffff" checked="checked">
<label for="g">灰色</label>
<input id="g" type="radio" name="bk_color" value="#808080">
</div>
</li>
<li class="m-3">
<div class="col-4">
<button type="button" class="btn-primary rounded" onclick="build_photo()">预览</button>
</div>
</li>
<li class="m-3">
<div id="pic" class="col-6"> </div>
</li>
</ol>
</form>
</div>
</div>
</div>
</div>
<script type="text/javascript">
function build_photo() {
var photo_size = document.getElementById("photo_size").value;
var bk_size = document.getElementById("bk_size").value;
var photo = document.getElementById("photo").files[0];
var bk_color = $("input[name='bk_color']:checked").val();
var formdata = new FormData();
formdata.append("photo",photo);
formdata.append("photo_size",photo_size);
formdata.append("bk_size",bk_size);
formdata.append("bk_color",bk_color);
$.ajax({
url:"/tools/photo_builder/",
type:"POST",
data:formdata,
processData:false,
contentType:false,
success:function (data) {
document.getElementById("pic").innerHTML = '<img class="img-thumbnail" src="data:image/jpg;base64,'+data["data"]+'">\n'+ //img直接用二进制表示,不指定路径
'<a class="btn btn-primary m-3 float-right" href="/download_photo" download>下载</a>'
}
})
} </script>
主要是上传图片的处理,我用了ajax上传,另外注意,form一定要加 enctype="multipart/form-data",不然django会报错
之后就是后端Django的处理了,分为照片生成和照片下载
from io import StringIO,BytesIO
from base64 import b64encode
from django.views.decorators.csrf import csrf_exempt
from Web_Demo.photo_builder import preview_pic,Hex_to_RGB
from django.shortcuts import HttpResponse, render, redirect,HttpResponseRedirect
@csrf_exempt
def photo_builder(request):
#声明一个全局变量,后面会用到
global byte_data
#底板和id照类型的字典,可以自己加,我用了通用模板,加了之后会直接传递到前端
photo_size_background_dict = {
"6寸": {"h": 10.16, "w": 15.24, "dpi": 300},
"A4": {"h": 21.0, "w": 29.7, "dpi": 300},
}
photo_size_dict = {"1寸": {"h": 3.21, "w": 2.4, "dpi": 300},
"2寸": {"h": 4.9, "w": 3.4, "dpi": 300}
}
if request.method == "GET":
return render(request,'../templates/photo_builder.html',{"photo_size_background":photo_size_bac
"photo_size":photo_size_dict})
else:
#获取ajax传递到后端的信息
photo = request.FILES.get("photo")
photo_size = request.POST.get("photo_size")
bk_size = request.POST.get("bk_size")
bk_color_hex = request.POST.get("bk_color")
#这里把16进制颜色处理成RGB模式的,后续会用到
bk_color = Hex_to_RGB(bk_color_hex)
#这个用BytesIO把前端传递过来的数据转化为二进制,方便PIL读取
img = BytesIO(photo.read())
#引入之前创建的函数,参数都已经给定,返回一个Image对象,过程参考前面的代码
pic = preview_pic(img,photo_size,bk_size,bk_color,photo_size_background_dict,photo_size_dict)
#把返回的Image对象转化为二进制代码,再转化为base64
output_buffer = BytesIO()
pic.save(output_buffer, format='JPEG')
byte_data = output_buffer.getvalue()
base64_bytes = b64encode(byte_data)
#把base64代码转化为utf8的字符串,并用Json序列化传递到前端,前端img直接引用base64码显示
base64_string = base64_bytes.decode('utf-8')
raw = {"data":base64_string}
json_data = json.dumps(raw,ensure_ascii=False)
return HttpResponse(json_data,content_type='application/json; charset=utf-8')
下载照片代码,这里处理起来很坑,我试了下,用数据流处理的话,下载下来的会提示文件损坏,
def download_photo(request):
#还是声明全局变量,调用之前生成的二进制数据,这样省掉了读取本地文件的过程
global byte_data
try:
response = HttpResponse(byte_data)
#这里一定要注意,千万不能用FileResponse和StreamingHttpResponse,而且type直接指定jpg就可以了,因为不是从后端读取的文件,是直接获取的二进制代码,用数据流的话一定会报错
response['Content-Type'] = 'application/jpg'
response['Content-Disposition'] = 'attachment;filename="ID.JPG"'
except:
return HttpResponse("Not Found the File")
return response
最后就是处理之后的显示了
然后是下载到本地的照片,大功告成,把模板保存起来打印的时候选择对应的底板尺寸就可以大了,再也不需要去用PS花一堆时间贴图了
用Django加PIL做一个证件照模板生成器网页的更多相关文章
- 使用Vue+Django+Ant Design做一个留言评论模块
使用Vue+Django+Ant Design做一个留言评论模块 1.总览 留言的展示参考网络上参见的格式,如掘金社区: 一共分为两层,子孙留言都在第二层中 最终效果如下: 接下是数据库的表结构,如下 ...
- 尝试做一个.NET模板填充导出Excel工具
园友好,最近晚辈延续上篇后尝试进阶做成Excel模板填充数据生成工具 MiniExcel Template. 主要特点 同样以Stream流.延迟查询避免全部数据载入内存情况,做到1GB内存降低到只需 ...
- css3加js做一个简单的3D行星运转效果
前几天在园子里看到一篇关于CSS3D行星运转的文章,原文在这里,感觉这个效果也太酷炫了,于是自己也就心血来潮的来尝试的做了一下.因为懒得去用什么插件了,于是就原生的JS写,效果有点粗超,还有一些地方处 ...
- 用CSS3的transform来做一个立方体
有一次上数据结构课老师布置了一个用队列的思想通过js和Html来做一个“跳舞配对”的网页,当时那个跳舞的部分用了css3里面transform的相关属性做了个个让图片无限翻转的效果,可能正是由于这个效 ...
- Python练习-一个简单的生成器
今天我们学习了生成器,怎么理解生成器呢,其实就是使用函数的方式自己建立一个迭代器 # 编辑者:闫龙 #做一个简单的生成器 def EasyGene(*args): #建立一个生成器方法并传递多个参数 ...
- 这几天有django和python做了一个多用户博客系统(可选择模板)
这几天有django和python做了一个多用户博客系统(可选择模板) 没完成,先分享下 断断续续2周时间吧,用django做了一个多用户博客系统,现在还没有做完,做分享下,以后等完善了再慢慢说 做的 ...
- Django(十六)基于模板的登录案例:登录装饰器、csrf攻击方式及防护、ajax的Post 的csrf开启写法、生成验证码、加验证码登录、反向解析+传参
一.csrf攻击 1.1 csrf攻击(跨站请求伪造) [csrf攻击即]:通过第3方网站,伪造请求(前提条件是你已经登录正常网站,并保存了session或cookie登录信息且没有退出),第三方网站 ...
- 前台利用jcrop做头像选择预览,后台通过django利用Uploadify组件上传图最终使用PIL做图像裁切
之前一直使用python的PIL自定义裁切图片,今天有需求需要做一个前端的选择预览页面,索性就把这个功能整理一下,分享给大家. 实现思路: 1.前端页面: 用户选择本地一张图片,然后通过鼠标缩放和移动 ...
- 用Django做一个省份选择器
做一个省份选择器 使用django做后端, mysql数据库, jQuery 列出结构主要的文件, 其它配置比较简单 models.py 因为所有数据的结构基本一致, 把所有省份, 市和区全部存储一张 ...
随机推荐
- TCP/IP 、HTTP和SOCKET
TCP/IP协议概念 TCP/IP(Transmission Control Protocol/Internet Protocol)的简写,中文译名为传输控制协议/因特网互联协议,又叫网络通讯协议,这 ...
- es6 默认参数、rest参数、扩展运算符
1.默认值 现在可以在定义函数的时候指定参数的默认值了,而不用像以前那样通过逻辑或操作符来达到目的了. function sayHello(name){ //传统的指定默认参数的方式 var name ...
- [***]HZOI20190714 T2熟练剖分
这题真的神仙,蒟弱表示看题解看不懂……std看了几个小时大概看懂,还有一些细节的东西没有思考. 最难受的是题解和std好像并不是同一个人写的……数组状态不一样……看了好久才看出来f也是前缀和. F[i ...
- H3C 分页显示
- H3C 命令行历史记录功能
- g++ 编译单个文件和多个文件
转载:https://www.cnblogs.com/battlescars/p/cpp_linux_gcc.html 1.单个源文件生成可执行程序 下面是一个保存在文件 helloworld.cpp ...
- mybatis plus3.1.0 热加载mapper
今天又开始写业务代码了,每次修改SQL都要重启服务,实在是浪费时间. 想起之前研究过的<mybatis plus3.1.0 热加载mapper>,一直没有成功,今天静下心来分析了问题,终于 ...
- [转]关于SSH与SSM的组成及其区别
前言 当下SpringBoot盛行,咱再聊聊SpringBoot盛行之前的框架组合,当做复习巩固哈. 在聊之前,得先说说MVC,MVC全名是Model View Controller,是模型(mode ...
- HDU 2871"Memory Control"(线段树区间和并+set.lower_bound)
传送门 •题意 有 n 个内存单元(编号从1开始): 给出 4 种操作: (1)Reset :表示把所有的内存清空,然后输出 "Reset Now". (2)New x :表示申请 ...
- [转]ASP.NET WebApi OWIN 实现 OAuth 2.0
OAuth(开放授权)是一个开放标准,允许用户让第三方应用访问该用户在某一网站上存储的私密的资源(如照片,视频,联系人列表),而无需将用户名和密码提供给第三方应用. OAuth 允许用户提供一个令牌, ...