• 【Web】前端裁剪图片,并上传到服务器(Jcrop+canvas)


      web网站中常常有的功能:上传头像、上传封面等;一般图片都有一定的比例限制,所以需要前端在上传图片时,进行裁剪,并把裁剪后的图片进行上传。

      本例采用Jcrop插件实现裁剪效果,canvas裁剪图片,并把base64位的toDataURL图片转换成blob(二进制数据),最后使用XMLHttpRequest上传到服务器。

      Jcrop演示及下载地址:http://code.ciaoca.com/jquery/jcrop/demo/

    Jcrop的使用

      本例做Jcrop的简单预览功能(同理可以实现网页的放大镜功能)

    • 载入 CSS 文件
      1 <link rel="stylesheet" href="jquery.Jcrop.css">
    • 载入 JavaScript 文件
      1 <script src="jquery.js"></script>
      2 <script src="jquery.Jcrop.js"></script>
    • 给 IMG 标签加上 ID
      1 <img id="element_id" src="pic.jpg">
    • 调用 Jcrop
      1 $('#element_id').Jcrop();

    实例代码

      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8">
      5     <title>图像裁剪-Jcrop</title>
      6     <link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
      7     <style>
      8         img {
      9             border: 0px;
     10         }
     11         * {
     12             margin: 0;
     13             padding: 0;
     14         }
     15         .head {
     16             width: 600px;
     17             height: 600px;
     18             background-color: gray;
     19         }
     20         #target{
     21             max-width: 600px;
     22             max-height: 600px;
     23         }
     24 
     25         #preview-pane {
     26             position: fixed;
     27             top: 0;
     28             right: 0;
     29             width: 300px;
     30             height: 300px;
     31             overflow: hidden;
     32             border: 1px solid purple;
     33         }
     34         #preview-pane .preview-container {
     35             width: 100%;
     36             height: 100%;
     37         }
     38         #preview-pane .preview-container img{
     39             max-width: 100%;
     40             max-height: 100%;
     41 
     42         }
     43     </style>
     44 </head>
     45 <body>
     46     
     47     <!-- 头像 -->
     48     <div class="head" >
     49         <img src="images/IMG_0109.JPG"  id="target" alt="[Jcrop Example]" />
     50     </div>
     51 
     52     <!-- 预览盒子 -->
     53     <div id="preview-pane">
     54         <div class="preview-container">
     55             <img src="images/IMG_0109.JPG" class="jcrop-preview" alt="Preview"  id="Preview"/>
     56         </div>
     57     </div>
     58 
     59     <script src="js/jquery.min.js"></script>
     60     <script src="js/jquery.Jcrop.js"></script>
     61     <script type="text/javascript">
     62 
     63         // 定义一些使用的变量
     64         var     jcrop_api,//jcrop对象
     65                 boundx,//图片实际显示宽度
     66                 boundy,//图片实际显示高度
     67                 realWidth,// 真实图片宽度
     68                 realHeight, //真实图片高度
     69 
     70                 // 使用的jquery对象
     71                 $target = $('#target'),
     72                 $preview = $('#preview-pane'),
     73                 $pcnt = $('#preview-pane .preview-container'),
     74                 $pimg = $('#preview-pane .preview-container img'),
     75 
     76                 xsize = $pcnt.width(),
     77                 ysize = $pcnt.height();
     78 
     79         //初始化Jcrop插件
     80         function initJcrop(){
     81              
     82             console.log('init',[xsize,ysize]);
     83             $target.removeAttr("style");//清空上一次初始化设置的样式
     84             $target.Jcrop({
     85               onChange: updatePreview,
     86               onSelect: updatePreview,
     87               aspectRatio: xsize / ysize
     88             },function(){
     89             //初始化后回调函数
     90             // 获取图片实际显示的大小
     91             var bounds = this.getBounds();
     92             boundx = bounds[0];//图片实际显示宽度
     93             boundy = bounds[1];//图片实际显示高度
     94 
     95             // 保存jcrop_api变量
     96             jcrop_api = this;
     97               
     98             });  
     99         }
    100 
    101         //更新显示预览内容
    102         function updatePreview(c){
    103             if (parseInt(c.w) > 0)
    104             {
    105                 var rx = xsize / c.w;
    106                 var ry = ysize / c.h;
    107 
    108                 $pimg.css({
    109                     maxWidth:  Math.round(rx * boundx) + 'px',
    110                     maxHeight: Math.round(ry * boundy) + 'px',
    111                        Math.round(rx * boundx) + 'px',
    112                     height: Math.round(ry * boundy) + 'px',
    113                     marginLeft: '-' + Math.round(rx * c.x) + 'px',
    114                     marginTop: '-' + Math.round(ry * c.y) + 'px'
    115                 });                
    116             }
    117         }
    118 
    119         window.onload = function () {
    120             initJcrop();
    121         };
    122 
    123     </script>
    124 </body>
    125 </html>

      预览效果

        

    Canvas的使用

      定义:<canvas> 标签定义图形,比如图表和其他图像。

      注意:canvas标签的宽高与标签样式的宽高问题,把Canvas 比作是一个画板和一张画纸,标签宽高相当于画板,样式宽高相当于画纸。

      canvas裁剪图片,准备上传

     1 <!DOCTYPE html>
     2 <html lang="en">
     3 <head>
     4     <meta charset="UTF-8">
     5     <title>图像裁剪-Jcrop</title>
     6     <link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
     7     <style>
     8         img {
     9             border: 0px;
    10         }
    11         * {
    12             margin: 0;
    13             padding: 0;
    14         }
    15         .head {
    16             width: 600px;
    17             height: 600px;
    18             background-color: gray;
    19         }
    20         #target{
    21             max-width: 600px;
    22             max-height: 600px;
    23         }
    24         canvas {
    25             position: fixed;
    26             top: 0;
    27             right: 0;
    28             border: 1px solid red;
    29             width: 200px;
    30             height: 200px;
    31         }
    32     </style>
    33 
    34     
    35 </head>
    36 <body>
    37     
    38     <!-- 头像 -->
    39     <div class="head" >
    40         <img src="images/IMG_0109.JPG"  id="target" alt="[Jcrop Example]" />    
    41     </div>
    42 
    43 
    44     <!-- 画板 -->
    45     <canvas id="myCan" width="200" height="200"></canvas>
    46 
    47     <script src="js/jquery.min.js"></script>
    48     <script type="text/javascript">
    49 
    50         
    51         initCanvas();
    52 
    53         //初始化canvas画板内容
    54         function initCanvas(){
    55             //更新canvas画板内容
    56             var img= document.getElementById("target");
    57             var ct= document.getElementById("myCan");
    58             var ctx = ct.getContext("2d");
    59 
    60             //清空画板
    61             ctx.clearRect(0,0, ct.width, ct.height); 
    62             //.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
    63             //矩形框[150,150,200,200]--原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度
    64             ctx.drawImage(img, 150, 150, 200, 200, 0,0,  ct.width , ct.height);
    65         }
    66 
    67     </script>
    68 </body>
    69 </html>

      预览
        

    完整代码展示

      html代码

      1 <!DOCTYPE html>
      2 <html lang="en">
      3 <head>
      4     <meta charset="UTF-8">
      5     <title>图像裁剪-Jcrop</title>
      6     <link rel="stylesheet" href="css/jquery.Jcrop.css" type="text/css" />
      7     <style>
      8         img {
      9             border: 0px;
     10         }
     11         * {
     12             margin: 0;
     13             padding: 0;
     14         }
     15         .head {
     16             width: 600px;
     17             height: 600px;
     18             background-color: gray;
     19         }
     20         #target{
     21             max-width: 600px;
     22             max-height: 600px;
     23         }
     24 
     25         #preview-pane {
     26             position: fixed;
     27             top: 0;
     28             right: 0;
     29             width: 300px;
     30             height: 300px;
     31             overflow: hidden;
     32             border: 1px solid purple;
     33         }
     34         #preview-pane .preview-container {
     35             width: 100%;
     36             height: 100%;
     37 
     38         }
     39 
     40         
     41         canvas {
     42             position: fixed;
     43             top: 400px;
     44             right: 0;
     45             border: 1px solid red;
     46             width: 200px;
     47             height: 200px;
     48         }
     49     </style>
     50 
     51     
     52 </head>
     53 <body>
     54     
     55     <!-- 头像 -->
     56     <div class="head" >
     57         <img src=""  id="target" alt="[Jcrop Example]" />
     58         <input type="file" id="file" onchange="changeFile()" style="display: none;"/>
     59     </div>
     60     <button onClick="openBrowse()">上传图片</button>
     61     <button onClick="uploadFile()">确认</button>
     62 
     63     <!-- 预览盒子 -->
     64     <div id="preview-pane">
     65         <div class="preview-container">
     66             <img src="" class="jcrop-preview" alt="Preview"  id="Preview"/>
     67         </div>
     68     </div>
     69 
     70     <!-- 画板 -->
     71     <canvas id="myCan" width="200" height="200"></canvas>
     72 
     73      <script src="js/jquery.min.js"></script>
     74     <script src="js/jquery.Jcrop.js"></script>
     75     <script type="text/javascript">
     76 
     77         // 定义一些使用的变量
     78         var     jcrop_api,//jcrop对象
     79                 boundx,//图片实际显示宽度
     80                 boundy,//图片实际显示高度
     81                 realWidth,// 真实图片宽度
     82                 realHeight, //真实图片高度
     83 
     84                 // 使用的jquery对象
     85                 $target = $('#target'),
     86                 $preview = $('#preview-pane'),
     87                 $pcnt = $('#preview-pane .preview-container'),
     88                 $pimg = $('#preview-pane .preview-container img'),
     89 
     90                 xsize = $pcnt.width(),
     91                 ysize = $pcnt.height();
     92 
     93 
     94 
     95         //1、打开浏览器
     96         function openBrowse(){
     97             var ie=navigator.appName=="Microsoft Internet Explorer" ? true : false; 
     98             if(ie){ 
     99                 document.getElementById("file").click(); 
    100             }else{
    101                 var a=document.createEvent("MouseEvents");
    102                 a.initEvent("click", true, true);  
    103                 document.getElementById("file").dispatchEvent(a);
    104             } 
    105         }
    106 
    107         //2、从 file 域获取 本地图片 url 
    108         function getFileUrl(sourceId) { 
    109             var url; 
    110             if (navigator.userAgent.indexOf("MSIE")>=1) { // IE 
    111             url = document.getElementById(sourceId).value; 
    112             } else if(navigator.userAgent.indexOf("Firefox")>0) { // Firefox 
    113             url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0)); 
    114             } else if(navigator.userAgent.indexOf("Chrome")>0) { // Chrome 
    115             url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0)); 
    116             } else if(navigator.userAgent.indexOf("Safari")>0) { // Chrome 
    117             url = window.URL.createObjectURL(document.getElementById(sourceId).files.item(0)); 
    118             } 
    119             return url; 
    120         } 
    121         //选择文件事件
    122         function changeFile() {
    123             var url = getFileUrl("file");//根据id获取文件路径
    124             preImg(url);
    125             return false;
    126         }
    127 
    128         //3、将本地图片 显示到浏览器上 
    129         function preImg(url) { 
    130 
    131             console.log('url===' + url);
    132             //图片裁剪逻辑
    133             if(jcrop_api)//判断jcrop_api是否被初始化过
    134             {
    135                 jcrop_api.destroy();
    136             }
    137 
    138             //初始化预览div内容
    139             initPreview();
    140             var p = document.getElementById('Preview');
    141             p.src = url;
    142 
    143             //初始化图片
    144             initTarget();
    145             var image = document.getElementById('target');
    146             image.onload=function(){//图片加载是一个异步的过程
    147                     //获取图片文件真实宽度和大小
    148                     var img = new Image();
    149                     img.onload=function(){
    150                         realWidth = img.width;
    151                         realHeight = img.height;
    152                       
    153                         //获取图片真实高度之后
    154                         initJcrop();//初始化Jcrop插件
    155                         initCanvas();//初始化Canvas内容
    156                     };
    157                     img.src = url;
    158             };
    159             image.src = url;
    160         } 
    161 
    162         //初始化Jcrop插件
    163         function initJcrop(){
    164              
    165             console.log('init',[xsize,ysize]);
    166             $target.removeAttr("style");//清空上一次初始化设置的样式
    167             $target.Jcrop({
    168               onChange: updatePreview,
    169               onSelect: updatePreview,
    170               aspectRatio: xsize / ysize
    171             },function(){
    172             //初始化后回调函数
    173             // 获取图片实际显示的大小
    174             var bounds = this.getBounds();
    175             boundx = bounds[0];//图片实际显示宽度
    176             boundy = bounds[1];//图片实际显示高度
    177 
    178             // 保存jcrop_api变量
    179             jcrop_api = this;
    180               
    181             });  
    182         }
    183 
    184         
    185         //更新显示预览内容
    186         function updatePreview(c){
    187             if (parseInt(c.w) > 0)
    188             {
    189                 var rx = xsize / c.w;
    190                 var ry = ysize / c.h;
    191 
    192                 $pimg.css({
    193                     maxWidth:  Math.round(rx * boundx) + 'px',
    194                     maxHeight: Math.round(ry * boundy) + 'px',
    195                        Math.round(rx * boundx) + 'px',
    196                     height: Math.round(ry * boundy) + 'px',
    197                     marginLeft: '-' + Math.round(rx * c.x) + 'px',
    198                     marginTop: '-' + Math.round(ry * c.y) + 'px'
    199                 });
    200 
    201                 //更新canvas画板内容
    202                 var img=document.getElementById("target");
    203                 var ct=document.getElementById("myCan");
    204                 var ctx=ct.getContext("2d");
    205                 //清空画板
    206                 ctx.clearRect(0,0, ct.width, ct.height); 
    207                 //.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
    208                 ctx.drawImage(img, c.x/boundx * realWidth,c.y/boundy * realHeight, c.w/boundx * realWidth, c.h/boundy * realHeight,0,0, ct.width, ct.height);
    209             }
    210         }
    211 
    212         //初始化预览div内容
    213         function initTarget(){
    214             $target.removeAttr("style");//清空上一次初始化设置的样式
    215             $target.css({
    216                   maxWidth:  '100%',
    217                 maxHeight: '100%'
    218               });
    219         }
    220         //初始化预览div内容
    221         function initPreview(){
    222             $pimg.removeAttr("style");//清空上一次初始化设置的样式
    223             $pimg.css({
    224                   maxWidth:  xsize + 'px',
    225                 maxHeight: ysize + 'px'
    226               });
    227         }
    228 
    229         //初始化canvas画板内容
    230         function initCanvas(){
    231             //更新canvas画板内容
    232             var img= document.getElementById("target");
    233             var ct= document.getElementById("myCan");
    234             var ctx = ct.getContext("2d");
    235            
    236             var myCanWidth = $('#myCan').width();
    237             var myCanHeight = $('#myCan').height();
    238 
    239             //清空画板
    240             ctx.clearRect(0,0, ct.width, ct.height); 
    241 
    242              //.drawImage(图像对象,原图像截取的起始X坐标,原图像截取的起始Y坐标,原图像截取的宽度,原图像截取的高度,绘制图像的起始X坐标,绘制图像的起始Y坐标,绘制图像所需要的宽度,绘制图像所需要的高度);
    243             var dWidth = realWidth;//绘制实际宽度
    244             var dHeight = realHeight;//绘制实际高度
    245             if(dWidth > myCanWidth)
    246             {
    247                 dHeight = myCanWidth / dWidth *  dHeight;
    248                 dWidth = myCanWidth;
    249             }
    250             if(dHeight > myCanHeight)
    251             {
    252                 dWidth = myCanHeight / dHeight * dWidth ;
    253                 dHeight = myCanHeight;
    254             }
    255             ctx.drawImage(img,0,0, realWidth, realHeight, 0,0,  dWidth, dHeight);
    256         }
    257 
    258         //文件上传
    259         function uploadFile(){
    260             //获取裁剪完后的base64图片url,转换为blob
    261             var data=document.getElementById("myCan").toDataURL();
    262             var formData=new FormData();
    263             formData.append("imageName",dataURLtoBlob(data));
    264             var httprequest= null;
    265             if (window.XMLHttpRequest) {
    266                 httprequest = new XMLHttpRequest();
    267             } else {
    268                 httprequest = new ActiveXObject('MicroSoft.XMLHTTP');
    269             }
    270             var apiurl= ""; //上传图片的api接口,自行填写
    271             httprequest.open('POST',apiurl,true);
    272             httprequest.send(formData);
    273             httprequest.onreadystatechange= function () {
    274                 
    275                 if(httprequest.readyState == 4 ){
    276                     
    277                     if(httprequest.status == 200)
    278                     {
    279                         var json=JSON.parse(httprequest.responseText);
    280                         console.log(json);
    281                         
    282                     }else
    283                     {
    284                         alert('获取数据错误,错误代码:' + httprequest.status + '错误信息:' + httprequest.statusText);
    285                     }
    286                 }
    287             };
    288         }
    289         
    290         //把base64位的toDataURL图片转换成blob
    291         function dataURLtoBlob(dataurl) {  
    292             var arr = dataurl.split(','), mime = arr[0].match(/:(.*?);/)[1],  
    293                     bstr = atob(arr[1]), n = bstr.length, u8arr = new Uint8Array(n);  
    294             while (n--) {  
    295                 u8arr[n] = bstr.charCodeAt(n);  
    296             }  
    297             return new Blob([u8arr], { type: mime });  
    298         } 
    299 
    300         window.onload = function () {
    301             //初始化图片
    302             preImg('images/IMG_0109.JPG');
    303         };
    304 
    305     </script>
    306 </body>
    307 </html>
    View Code

       图片上传接口可以参照:【Java】JavaWeb文件上传和下载

      注意:canvas在裁剪图片的时候有跨域的问题,如果裁剪网络图片,会报异常:Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported.

      本例服务端采用的方法是:服务器转发网络图片,进行图片访问。

        页面上访问:<img src="img/getImg?imgUrl=http://test.example.net/a/b/c/123456.jpg"/>

        服务端JAVA代码:

     1 @RequestMapping(value = "/getImg")
     2     public void getImg(HttpServletRequest request, HttpServletResponse response, String imgUrl) throws Exception
     3     {
     4         // 统一资源
     5         URL url = new URL(imgUrl);
     6         // 连接类的父类,抽象类
     7         URLConnection urlConnection = url.openConnection();
     8         // http的连接类
     9         HttpURLConnection httpURLConnection = (HttpURLConnection) urlConnection;
    10         // 设定请求的方法,默认是GET
    11         httpURLConnection.setRequestMethod("POST");
    12         // 设置字符编码
    13         httpURLConnection.setRequestProperty("Charset", "UTF-8");
    14         // 打开到此 URL 引用的资源的通信链接(如果尚未建立这样的连接)。
    15         httpURLConnection.connect();
    16 
    17         BufferedInputStream bin = new BufferedInputStream(httpURLConnection.getInputStream());
    18         ServletOutputStream outputStream = response.getOutputStream();
    19         
    20         int size = 0;
    21         byte[] buf = new byte[1024*10];
    22         while ((size = bin.read(buf)) != -1) {
    23             outputStream.write(buf, 0, size);
    24         }
    25         bin.close();
    26         outputStream.close();
    27     }

      预览效果

        

  • 相关阅读:
    QTableView表格控件区域选择-自绘选择区域
    Qt高仿Excel表格组件-支持冻结列、冻结行、内容自适应和合并单元格
    QRowTable表格控件(三)-效率优化之-合理使用QStandardItem
    QRowTable表格控件(二)-红涨绿跌
    QRowTable表格控件-支持hover整行、checked整行、指定列排序等
    Qt实现表格控件-支持多级列表头、多级行表头、单元格合并、字体设置等
    Asp.net MVC利用Ajax.BeginForm实现bootstrap模态框弹出,并进行前段验证
    Bootstrap:弹出框和提示框效果以及代码展示
    Bootstrap treeview增加或者删除节点
    bootstrap-treeview 如何实现全选父节点下所有子节点及反选
  • 原文地址:https://www.cnblogs.com/h--d/p/7801230.html
Copyright © 2020-2023  润新知