• 前台利用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,
                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 "+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({
               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(""+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 {
       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


  • 相关阅读:
    JavaScript 中,定义函数时用 var foo = function () {} 和 function foo() 有什么区别?
    Vue报错 [Vue warn]: Cannot find element
    一个android样本的过保护
    cve-2015-1635漏洞分析
    一个linux的样本分析
    ios透明代理抓包
    各浏览器抗uaf机制
    面试知识点总结之Nginx
    面试知识点总结之redis
    面试知识点总结之I/O流IO/BIO/NIO/AIO区别
  • 原文地址:https://www.cnblogs.com/james1207/p/3283324.html
Copyright © 2020-2023  润新知