前台利用jcrop做头像选择预览,后台通过django利用Uploadify组件上传图最终使用PIL做图像裁切
之前一直使用python的PIL自定义裁切图片,今天有需求需要做一个前端的选择预览页面,索性就把这个功能整理一下,分享给大家。
实现思路:
1、前端页面:
用户选择本地一张图片,然后通过鼠标缩放和移动,确定自己所需要的图片切块,最终把图片切块的 左边距,上边距,长,宽这些个参数传给后台
2、后台:
使用的django,主要实现2部分的功能,第一:图片上传,第二:图片裁切
先看一张图片:
前端页面:
后台最后得到的图片:
对于该demo中,我用到了以下js插件:
jquery-webox:弹出图层(你可以不关心)
jcrop:在线裁切预览图片 http://deepliquid.com/content/Jcrop_Implementation_Theory.html
jquery.uploadify:上传附件
html页面:
a)用户信息页面:userinfo.html
b)弹出页面用于用户选择、上传、预览图片:index.html
django程序:
UploadImage模块下有以下几个文件:
c)urls.py
d)views.py
下面就开始贴代码了
a)的代码:
- {% extends "kidcrate/base.html" %}
- {%block contentBar%}
- <link href="/site_media/uploadify/uploadify.css" type="text/css" rel="stylesheet" />
- <script type="text/javascript" src="/site_media/uploadify/jquery.uploadify.min.js"></script>
- <script type="text/javascript" src="/site_media/js/thickbox.js"></script>
- <link rel='stylesheet' type='text/css' href='/site_media/css/thickbox.css' />
- <link href="/site_media/common/jquery_webox/jquery-webox.css" rel="stylesheet" type="text/css">
- <script src="/site_media/common/jquery_webox/jquery-webox.js"></script>
- <script type="text/javascript">
- $(document).ready(function(){
- //iframe弹出层调用
- $('#outside').click(function(){
- $.webox({
- height:500,
- width:800,
- bgvisibel:true,
- title:'修改头像',
- iframe:'/uploadify?uuid='+$('#uuid').val()+'&rd='+Math.random()
- });
- });
- })
- </script>
- <DIV class="yyh-page grid_9">
- <DIV class=widget>
- <DIV class=widget-content>
- <!-- basic form -->
- <FORM id=basic class="yyh-form tabs-rel tabs-info on" method=post
- action="/account/userinfo/">
- <input type="hidden" id="uuid" name="uuid" value="{{uuid}}" />
- <DL class=required>
- <DT>
- <LABEL for=producer>
- 账号
- </LABEL>
- </DT>
- <DD>
- <INPUT class=inputText style="color: #400080;font - size: 16px;" readonly="true" value="{{username}}">
- <SPAN>
- <B class=error>
- </B>
- </SPAN>
- <P class=hint>
- </P>
- </DD>
- <DT>
- <LABEL for=producer>
- 联系人真实姓名
- </LABEL>
- </DT>
- <DD>
- <INPUT class=inputText name=devName value="{{devName}}">
- <SPAN>
- <B class=error>
- </B>
- </SPAN>
- <P class=hint>
- </P>
- </DD>
- </DL>
- <DL class=required>
- <DT>
- <LABEL for=phone>
- 联系电话
- </LABEL>
- </DT>
- <DD>
- <INPUT class=inputText name=contactPhone value="{{contactPhone}}">
- <SPAN>
- <B class=error>
- </B>
- </SPAN>
- <P class=hint>
- </P>
- </DD>
- </DL>
- <DL class=required>
- <DT>
- <LABEL for=address>
- 联系地址
- </LABEL>
- </DT>
- <DD>
- <INPUT class=inputText name=contactAddress value="{{contactAddress}}">
- <SPAN>
- <B class=error>
- </B>
- </SPAN>
- <P class=hint>
- 请填写真实的联系地址
- </P>
- </DD>
- </DL>
- <DL class=required>
- <DT>
- <LABEL for=zipcode>
- 邮政编码
- </LABEL>
- </DT>
- <DD>
- <INPUT class="inputText NumberValidate" name=contactZipCode value="{{contactZipCode}}">
- <SPAN>
- <B class=error>
- </B>
- </SPAN>
- </DD>
- </DL>
- <DL>
- <DT>
- <LABEL for=headimg>
- 头像
- </LABEL>
- </DT>
- <DD>
- <img id="screenshot_img" name="screeshot_img" src="/site_media/images/account_head/femail.jpg" width="120" height="120" /><br><br/>
- <div id="upload_div" style="display:visible;">
- <a class="Button blueButton Button18" href="javascript:void(0);" id="outside"><strong>点我修改</strong></a>
- </div>
- </DD>
- </DL>
- <DL class=submit>
- <DT>
- </DT>
- <DD>
- <INPUT class="inputSubmit blue" value=保存 type=button onclick="this.form.submit();
- ">
- </DD>
- </DL>
- </FORM>
- <!-- end of basic form -->
- </DIV>
- </DIV>
- </DIV>
- {%endblock%}"
b)的代码:
- <!DOCTYPE html>
- <html>
- <head>
- <meta charset="UTF-8">
- <title>Django下利用Uploadify组件上传图片</title>
- <link rel="stylesheet" href="/site_media/jcrop/demos/demo_files/main.css" type="text/css" />
- <link rel="stylesheet" href="/site_media/jcrop/demos/demo_files/demos.css" type="text/css" />
- <link rel="stylesheet" href="/site_media/jcrop/css/jquery.Jcrop.css" type="text/css" />
- <script src="/site_media/jcrop/js/jquery.min.js"></script>
- <script src="/site_media/jcrop/js/jquery.Jcrop.js"></script>
- <script type="text/javascript">
- var img_top_margin,img_left_margin,img_width,img_height;//最后使用的2个变量
- jQuery(function($){
- // Create variables (in this scope) to hold the API and image size
- var jcrop_api,
- boundx,
- boundy,
- topw,
- leftw,
- // Grab some information about the preview pane
- $preview = $('#preview-pane'),
- $pcnt = $('#preview-pane .preview-container'),
- $pimg = $('#preview-pane .preview-container img'),
- xsize = $pcnt.width(),
- ysize = $pcnt.height();
- console.log('init',[xsize,ysize]);
- $('#target').Jcrop({
- onChange: updatePreview,
- onSelect: updatePreview,
- aspectRatio: xsize / ysize
- },function(){
- // Use the API to get the real image size
- var bounds = this.getBounds();
- boundx = bounds[0];
- boundy = bounds[1];
- // Store the API in the jcrop_api variable
- jcrop_api = this;
- // Move the preview into the jcrop container for css positioning
- $preview.appendTo(jcrop_api.ui.holder);
- });
- function updatePreview(c)
- {
- if (parseInt(c.w) > 0)
- {
- var rx = xsize / c.w;
- var ry = ysize / c.h;
- console.log("new width:"+Math.round(rx * boundx) );
- console.log("new height:"+Math.round(ry * boundy) );
- console.log("marginTop:"+Math.round(ry * c.y));
- console.log("marginLeft:"+Math.round(rx * c.x));
- img_top_margin=c.y;
- img_left_margin=c.x;
- img_width=c.w;
- img_height=c.h;
- $pimg.css({
- width: Math.round(rx * boundx) + 'px',
- height: Math.round(ry * boundy) + 'px',
- marginLeft: '-' + Math.round(rx * c.x) + 'px',
- marginTop: '-' + Math.round(ry * c.y) + 'px'
- });
- }
- };
- });
- </script>
- <link href="/site_media/uploadify/uploadify.css" type="text/css" rel="stylesheet" />
- <script type="text/javascript" src="/site_media/uploadify/swfobject.js"></script>
- <script type="text/javascript" src="/site_media/uploadify/jquery.uploadify.v2.1.4.min.js"></script>
- <script type="text/javascript" charset="utf-8" async defer>
- function go() {
- alert(2);
- }
- function replace_image(flag,path,uuid) {
- console.log("==========replace_image=======");
- console.log("marginTop:"+img_top_margin);
- console.log("marginLeft:"+img_left_margin);
- console.log("width:"+img_width);
- console.log("height:"+img_height);
- var params="&marginTop="+img_top_margin+"&marginLeft="+img_left_margin+"&width="+img_width+"&height="+img_height;
- $.ajax({
- type: "GET",
- url: "?replace_flag="+flag+"&savepath="+path+params,
- dataType: "json",
- success: function (json) {
- alert(json.message);
- //document.getElementById("btnquery").click();
- document.getElementById("echo_href_msg").innerHTML = json.message;
- }
- })
- }
- </script>
- <script type="text/javascript">
- $(document).ready(function() {
- $('#file_upload').uploadify({
- 'uploader' : '/site_media/uploadify/uploadify.swf',
- 'script' : '{%url uploadify_script %}',
- 'cancelImg' : '/site_media/uploadify/cancel.png',
- 'folder' : '/upload',
- 'auto' : false,//
- 'multi': true,//设置可以上传多个文件
- 'queueSizeLimit':20,//设置可以同时20个文件
- 'removeCompleted':false,//
- 'sizeLimit':10240000,//设置上传文件大小单位kb
- 'fileExt':'*.jpg;*.gif;*.png',//设置上传文件类型为常用图片格式
- 'fileDesc':'Image Files',
- 'onInit': function () {},
- 'onError' : function (event,ID,fileObj,errorObj) {
- $('#id_span_msg').html("上传失败,错误码:"+errorObj.type+" "+errorObj.info);
- },
- 'onSelect': function (e, queueId, fileObj) {
- $('#id_span_msg').html("");
- },
- 'onAllComplete': function (event, data) {
- if(data.filesUploaded>=1){
- $('#id_span_msg').html("上传成功!");
- }
- }
- });
- });
- </script>
- <style type="text/css">
- /* Apply these styles only when #preview-pane has
- been placed within the Jcrop widget */
- .jcrop-holder #preview-pane {
- display: block;
- position: absolute;
- z-index: 2000;
- top: 10px;
- right: -280px;
- padding: 6px;
- border: 1px rgba(0,0,0,.4) solid;
- background-color: white;
- -webkit-border-radius: 6px;
- -moz-border-radius: 6px;
- border-radius: 6px;
- -webkit-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
- -moz-box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
- box-shadow: 1px 1px 5px 2px rgba(0, 0, 0, 0.2);
- }
- /* The Javascript code will set the aspect ratio of the crop
- area based on the size of the thumbnail preview,
- specified here */
- #preview-pane .preview-container {
- width: 180px;
- height: 180px;
- overflow: hidden;
- }
- </style>
- </head>
- <body>
- <h1>请选择图片上传</h1>
- <div class="demo-box">
- <form action="." method="post" enctype="multipart/form-data">{% csrf_token %}
- <input type="file" name="Filedata"/>
- <input type="submit" value="上传"/> {%if message%}{{message}}{%endif%}
- {% ifequal upload_flag 1 %}
- <img id="target" src="/site_media/upload/tmp/{{savepath}}"/>
- <div id="preview-pane">
- <div class="preview-container">
- <img src="/site_media/upload/tmp/{{savepath}}" class="jcrop-preview" alt="Preview" />
- </div>
- </div>
- <br/><br/>
- <div id="echo_href_msg" >
- <a href="#" onclick="replace_image('1','{{savepath}}');" >你确定要替换原来的图片?</a>
- </div>
- {%endifequal%}
- </form>
- </div>
- <!--
- <p></p>
- <h1>Uploadify组件上传方式</h1>
- <div class="demo-box">
- <input id="file_upload" type="file" name="Filedata">
- <div id="file_uploadQueue" class="uploadifyQueue"></div>
- <p><a href="javascript:$('#file_upload').uploadifyUpload()">上传图片</a>
- <a href="javascript:$('#file_upload').uploadifyClearQueue()">取消上传</a>
- </p>
- <p><span id="id_span_msg"></span></p>
- //-->
- </div>
- </body>
- </html>
c)的代码:
- from django.conf.urls.defaults import patterns, url
- urlpatterns = patterns('xue_wan_le.UploadImage.views',
- url(r'^$', 'index', name='uploadify'),
- url(r'^index/', 'index',name="uploadify_index"),
- url(r'^uploadify_script/', 'uploadify_script',name="uploadify_script"),
- )
d)的代码:
- #coding=utf-8
- from django.http import HttpResponse
- from django.template import RequestContext
- from django.shortcuts import render_to_response
- import os,ImageFile,uuid,shutil
- from django.conf import settings
- from django.views.decorators.csrf import csrf_exempt
- from django.utils import simplejson
- from xue_wan_le.Common.CookieUtil import CookieUtil
- def index(request):
- ctx=dict()
- uuid=''
- marginTop=0
- marginLeft=0
- width=0
- height=0
- if request.GET.get('marginTop'):
- marginTop=int(request.GET.get('marginTop'))
- if request.GET.get('marginLeft'):
- marginLeft=int(request.GET.get('marginLeft'))
- if request.GET.get('width'):
- width=int(request.GET.get('width'))
- if request.GET.get('height'):
- height=int(request.GET.get('height'))
- if request.GET.get('uuid'):
- uuid=request.GET.get('uuid')
- print '===uuid:'+request.GET.get('uuid')
- request.session['replace_site_icon_uuid'] = uuid#保存UUID
- if request.GET.get('replace_flag'):
- filepath=request.GET.get('savepath')
- olduuid=request.session['replace_site_icon_uuid']
- print '===filepath:'+filepath
- print '===olduuid:'+olduuid
- print '====uuid:'+uuid
- path=os.path.join(settings.MEDIA_ROOT,settings.SOURCE_IMAGE_TMP)
- if filepath and olduuid:
- if os.path.isfile(os.path.join(path,filepath)):
- #先把新文件,换成旧文件名字
- try:
- print 'olduuid:'+olduuid
- newname=os.path.join(settings.MEDIA_ROOT,settings.SOURCE_IMAGE_TMP,olduuid+'.jpg')
- print 'newname:'+newname
- os.rename(os.path.join(path,filepath),newname)
- #覆盖
- shutil.move(os.path.join(settings.MEDIA_ROOT,settings.SOURCE_IMAGE_TMP,olduuid+'.jpg'),
- os.path.join(settings.MEDIA_ROOT,'urls','sitethumbs',olduuid+'.jpg'))
- #裁切
- try:
- from PIL import Image
- path=os.path.join(settings.MEDIA_ROOT,'urls','sitethumbs',olduuid+'.jpg')
- f = Image.open(path)
- xsize,ysize=f.size
- print 'image size:'+str(xsize)+":"+str(ysize)
- #box变量是一个四元组(左,上,右,下)。
- box=(marginLeft,marginTop,marginLeft+width,marginTop+height)
- print box
- print '----1'
- f.crop(box).save(path)
- print '----2'
- print 'crop image:'+path
- except Exception,e:
- print e
- return HttpResponse(simplejson.dumps({'message':'替换成功,关闭窗口'}))
- except Exception,e:
- print e
- else:
- print 'error.=='
- if request.method=="POST":
- file = request.FILES.get("Filedata",None)
- (upload_flag,savepath)=_upload(file)
- if upload_flag:
- ctx["message"]=u"上传成功!"
- ctx["upload_flag"]=1
- else:
- ctx["message"]=u"上传出错!"
- ctx["upload_flag"]=0
- ctx["savepath"]=savepath
- return render_to_response("uploadpic/index.html",ctx,RequestContext(request))
- @csrf_exempt
- def uploadify_script(request):
- response=HttpResponse()
- response['Content-Type']="text/javascript"
- ret="0"
- file = request.FILES.get("Filedata",None)
- if file:
- if _upload(file):
- ret="1"
- ret="2"
- response.write(ret)
- return response
- def _upload(file):
- '''图片上传函数'''
- if file:
- path=os.path.join(settings.MEDIA_ROOT,settings.SOURCE_IMAGE_TMP)
- if not os.path.exists(path): #如果目录不存在创建目录
- os.makedirs(path)
- file_name=str(uuid.uuid1())+".jpg"
- path_file=os.path.join(path,file_name)
- parser = ImageFile.Parser()
- for chunk in file.chunks():
- parser.feed(chunk)
- img = parser.close()
- try:
- if img.mode != "RGB":
- img = img.convert("RGB")
- img.save(path_file, 'jpeg',quality=100)
- print 'img.save:'+path_file
- except Exception,e:
- print e
- return (False,"")
- return (True,file_name)
- return (False,"")
index.html和view.py是功能实现的主要部分,如果有疑问可以发评论给我,或者新浪微博私信给我http://weibo.com/changeself
前台利用jcrop做头像选择预览,后台通过django利用Uploadify组件上传图最终使用PIL做图像裁切的更多相关文章
- [App Store Connect帮助]四、添加 App 图标、App 预览和屏幕快照(3)上传 App 预览和屏幕快照
请上传至多三个 App 预览和至多十张屏幕快照.如果您的 App 在不同设备尺寸和本地化内容间都相同,仅提供所要求的最高分辨率的屏幕快照即可. 对于 iPhone,必须提供用于 5.5 英寸设备(iP ...
- 利用tornado实现表格文件预览
项目介绍 本文将介绍笔者的一个项目,主要是利用tornado实现表格文件的预览,能够浏览的表格文件支持CSV以及Excel文件.预览的界面如下: 下面我们将看到这个功能是如何通过tornado ...
- 如何利用Python实现Office在线预览
目前,市场对于Office在线预览功能的需求是很大的.对于我们用户本身来说,下载Office文件后再实现预览是极其不方便的,何况还有一些不能打开的专业文档.压缩文件等.此时,能提供在线预览服务的软件就 ...
- javascript 利用FileReader和滤镜上传图片预览
FileReader 对象允许Web应用程序异步读取存储在用户计算机上的文件(或原始数据缓冲区)的内容,使用 File或 Blob对象指定要读取的文件或数据. 1.FileReader接口的方法 Fi ...
- 纯javascript代码实现浏览器图片选择预览、旋转、批量上传
工作中遇到的业务场景,和同事一起研究了下,主要是为了兼容IE版本 其实就是一些琐碎的知识点在网上搜集下解决方式,然后集成了下,主要有以下点: 1. IE input type=file的图片预览要用I ...
- DAY19-上传头像并预览
一个简单的注册页面: <!DOCTYPE html> <html lang="en"> <head> <meta charset=&quo ...
- 表单提交学习笔记(三)—利用Request.Files上传图片并预览
一.html页面如下 <div id="container"> <form id="myForm"> <p class=" ...
- django 上传头像并预览 3选1
注册页面的头像上传 register.html<!DOCTYPE html> <html lang="en"> <head> <meta ...
- MUI 单个图片上传预览(拍照+系统相册):先选择->预览->上传提交
1 html部分 <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> < ...
随机推荐
- leetcode_question_114 Flatten Binary Tree to Linked List
Given a binary tree, flatten it to a linked list in-place. For example, Given 1 / \ 2 5 / \ \ 3 4 6 ...
- Lucene.net常见功能实现知识汇总
在开发SearchEasy Site SearchEngine(搜易站内搜索引擎)的时候,经常会遇到一些搜索引擎的常见功能如何实现的问题,比如实现相关度百分比显示?如何实现在结果中搜索等等诸如此类常见 ...
- SEO的URL如何优化才是最佳
原文地址:http://www.chinaz.com/web/2007/0413/6841.shtml 很多人都知道URL对SEO的重要之处,但是很多站点却忽略了站点的路径优化.今天本人在这里写几点关 ...
- UGUI 帧动画插件
最近在开发一款功夫猫游戏,本来使用Unity Sprite制作,但是发现Sprite对各种分辨率不支持. 看着游戏很简单就使用UGUI制作,在中途发现有很多帧动画播放,使用了Animation调整使用 ...
- mycat实例(3)
配置MyCat 4. 配置schema.xml schema.xml里面管理着MyCat的逻辑库.表,每张表使用的分片规则.分布在哪个DataNode以及DataSource上. 之前的例子: < ...
- POJ 3254 炮兵阵地(状态压缩DP)
题意:由方格组成的矩阵,每个方格可以放大炮用P表示,不可以放大炮用H表示,求放最多的大炮,大炮与大炮间不会互相攻击.大炮的攻击范围为两个方格. 分析:这次当前行的状态不仅和上一行有关,还和上上行有关, ...
- 第04章-VTK基础(4)
[译者:这个系列教程是以Kitware公司出版的<VTK User's Guide -11th edition>一书作的中文翻译(出版时间2010年,ISBN: 978-1-930934- ...
- [置顶] 正则表达式应用:匹配IP地址
都知道iP地址有四个数值,三个点号组成.三个数值的具体范围为0到255,为了使用正则表达式匹配就必须分析IP地址的组成 1先分析数值,2再组合数值和点号 1先分析数值 IP地址的数字范围从0到255, ...
- [跟我学spring学习笔记][DI循环依赖]
循环依赖 什么是循环依赖? 循环依赖就是循环引用,就是两个或多个Bean相互之间的持有对方. Spring容器循环依赖包括构造器循环依赖和setter循环依赖,那Spring容器如何解决循环依赖呢? ...
- ToString()和Convert.ToString()的区别
ToString()和Convert.ToString()的区别 一般情况下,这两种方法都可以通用,但是当返回的数据类型中有可能出现null值时如果调用ToString方法了,就会返回NullRefe ...