设为首页 收藏本站
查看: 1128|回复: 0

[经验分享] Ajax+PHP+jQuery图片截图上传

[复制链接]

尚未签到

发表于 2015-8-22 18:09:14 | 显示全部楼层 |阅读模式
  一、功能分析
  用户直接上传图片,点击"上传"按钮之后,在图片预览图内可预览图片,然后进行图片的裁剪前预览,当点击"裁剪"按钮时确定裁剪图片,并在"裁剪结果"区域显示裁剪后的效果。
  (说明:我是将上传文件保存在"/uploads"文件夹中,而截图结果放在"/avatar"文件夹里)
  实现效果预览:
    http://player.56.com/v_NjM0OTMzNTM.swf

  
  二、解决方案
   1、插件的选择


  • jQuery:这个是必备的一个插件可以到官网上下载
  http://docs.jquery.com/Downloading_jQuery


  • imgAreSselect:这个是实现客户端上图片区域选择的
  http://odyniec.net/projects/imgareaselect/


  • uploadify:实现文件的上传的功能,支持多文件上传,且可定制性非常强。
  http://www.uploadify.com/download/
  上面的插件是用在客户端上,其实在我这个程序里写PHP时也用了一些插件。其实我之所以写"图像剪裁上传"的起源是因为我看了《PHP快速开发工具箱》想自己练习一下的。该书是有一个网址(http://www.pluginphp.com/),里面有整本书的代码,而且每个插件都相应的demo,非常不错。下面是用到的PHP插件:


  • PIPHP_UploadFile.php:这是一个文件上传功能的php文件
  http://www.pluginphp.com/plug-in11.php


  • PIPHP_ImageCrop.php:这个php文件是具有对图片进行裁剪的功能
  http://www.pluginphp.com/plug-in15.php
  
   2、客户端与服务器之间的交互图
  为了便于理解,我先把交互图放在这里。其中绿色部分是客户端的主要步骤、粉红色是服务器端的主要步骤,服务器与客户端之间的交互通过AJAX完成。可以发现,大部分的操作在客户端进行,服务器端与客户端之间的交流只是简单的JSON数据,因此这样给用户的体验是非常高的。
DSC0000.png
  截图 1 客户端与服务器之间交互图
  
   3、客户端文件
  展示给用户的是html页面,为了学习并巩固CSS知识,就和DIV+CSS搭建了下面这样一个前台页面,见截图 2。
DSC0001.png
  截图 2 前台页面
  跟客户端有关的文件主要是一个index.html,而在这个文件里面会引用其他的插件文件,因此可以说,客户端方面只有一个html文件。
  另外,由于这里主要讨论客户端与浏览器之间的交互,因此略过CSS方面的内容。这里只列出HTML的代码,首先是<head>部分:
  <head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <link rel="stylesheet" type="text/css" href="/imgareaselect/css/imgareaselect-default.css" />
  <link rel="stylesheet" type="text/css"  href="layout.css" />
  <link href="/uploadify/uploadify.css" type="text/css" rel="stylesheet" />
  
  <script type="text/javascript" src="/js/jquery-1.6.2.min.js"></script>
  <script type="text/javascript" src="/imgareaselect/scripts/jquery.imgareaselect.pack.js"></script>
  <script type="text/javascript" src="/uploadify/swfobject.js"></script>
  <script type="text/javascript" src="/uploadify/jquery.uploadify.v2.1.4.min.js"></script>
  <title>图片剪切上传</title>
  </head>
  可以看得出来主要是引用一些插件的文件。上面的文件(包括CSS文件与js文件)都可以从我给的链接里下载到,只是样式表layout.css是我自己写的样式表,大家可以根据自己的CSS知识写出。
  接下来是body部分,也许这么看代码比较乱,推荐使用一些带有高亮显示的工具来查看这些代码,比如DreamWeaver等IDE,实在不行,也可以用火狐的"查看源代码"来看。(火狐不仅是一个好浏览器,更是一个极棒的调试器!)
  为了方便起见,我去掉诸如"导航条"、页脚版权声明等点缀部分,只给出必要的html代码。
  <body class="home">
      <form>
          <fieldset>
              <legend>图片上传</legend>
                   <div id="queue"></div>
                   <input type="file" name="file" id="pic_upload"/><br />
                   <a id='uploadLink' href="javascript:$('#pic_upload').uploadifyUpload();">上传图片 </a>
                   <div id="uploadInfo"></div>
          </fieldset>        
      </form>
  
      <div id="twoColLayout">
          <div id="primaryContent">
  <div >
                  <h3>图片预览</h3>
                   <div id='oriImage' class="img_v">
  
   </div>                   
              </div>
  
  <div >
  裁剪结果:
  <div id="cropResult" class="cbb" >
  
   </div>
              </div>
          </div>
  
  <div id="sideContent">   
  裁剪预览:
              <div id="preview">
  
   </div>
          </div>
      </div>   
  </body>
  上面我用颜色区分开主要DIV区,这三块分别代表"上传图片区"、"大图展示区"、"截图结果区"与"选择预览区"。其中三个粗体部分是带有ID属性的空DIV,用来放图片用的。(到时时候动态加载图片到这些DIV中),因此这段代码形成的HTML框架如截图 2所示。(蓝色线条是block元素边界,此效果较是由火狐的插件制作而成):
DSC0002.png
  截图 3 页面大体框架
  基本的准备工作已经完成,待会儿再继续在这个框架上添加代码。咱们先介绍一下服务器上的PHP是怎么个情况。
  
   4、服务器文件
  服务器上主要用到两个PHP文件,一个用来处理上传图片的process.php,另外一个则是处理图片截图用的crop.php。不过,process.php文件包括插件PIPHP_UploadFile.php,而crop.php中包括PIPHP_ImageCrop.php插件。(这些插件的地址我在上面已经给出了)
  =======
  process.php主要接收上传图片,设置限制(比如文件的大小与格式),处理一些上传错误等,最后返回给客户端JSON,里面包含了所上传文件的一些信息(比如路径、大小等);当在客户端点击"上传"按钮的时候,会用异步(AJAX)的方式调用这个php文件。
  =======
  crop.php主要负责真正裁剪上传的图片,当在客户端返回裁剪的位置后(点击"裁剪"按钮后),以异步方式将数据以JSON的方式传递给服务器,crop.php真正裁剪图片后,将图片另存到网络的目录下,同时返回此图片的存储路径,然后再让客户端显示图片即可
  
  三、用到的技术摘要
  现在根据上面的交互图继续完善代码。因此我这节会交叉地完善html、js与php代码,并不会单独分开完善,这样在逻辑上会更好理解。
  声明:新增的代码部分用粗体表示
  
   1、uploadify上传
  在html的head部分加入<script>标签,里面开始写主要的处理程序:
  …
  <script type="text/javascript" src="/uploadify/swfobject.js"></script>
  <script type="text/javascript"  src="/uploadify/jquery.uploadify.v2.1.4.min.js"></script>
      <script type="text/javascript">
    $(document).ready(function(){
          //uploadify设置
              $('#pic_upload').uploadify({
                  'uploader' : '/uploadify/uploadify.swf',
                  'script' : 'process.php',         
                  'cancelImg' : '/uploadify/cancel.png',
              });
    }
      </script>
  </head>
  …
  上面的代码只是uploadify这一个插件的配置项而已。为了增强用户体验可以详细配置其他选项,这参考这个插件的官方文档:http://www.uploadify.com/documentation/。上面的'script'选项就是选择服务器的处理脚本,我们这里就使用process.php了。上传文件到服务器后会让服务器自动调用这个程序。那么客户端怎么知道服务器的process.php调用完了呢?如何获取process.php反馈回来的信息呢?——其实uploadify它提供了一个"触发"选项onComplete,就是用来处理服务器的反馈信息的,我们稍后再写这个选项的内容,先看看process.php是返回哪些内容的呢。
  
   2、process.php反馈上传信息
  process.php的任务就是给浏览器返回JSON数据(至于什么是JSON请参考其它教程,把JSON想像成"键/值"对就可以了,它很方便数据的传输与读取)。在PHP里,一般是先把数据整理成数组的形式,然后使用json_encode()把数据转换成JSON。那process.php应该给浏览器返回什么样的数据呢?


  • 文件是否成功上传        ->    message

  • 文件的上传状态代码        ->    code

  • 文件上传的存放路径        ->    path

  • 图片的宽度                ->    width

  • 图片的高度                 ->    height

  • 图片的缩放比例            ->    scale

  • 图片的名称                ->    name
  其中之所以设置图片的缩放比例scale,是因为如果用户上传的图片尺寸太大(比如800x800),浏览器中的DIV会被"撑开",布局会被打乱。因此我们限定在浏览器显示图片的时候任何一边长不能超过400px,否则在显示的时候以等比例缩放。(比如上面的800x800的图上会显示成400x400的,然后浏览器同时设置scale为0.5)。
      另外,这个php文件是调用了PIPHP_UploadFile.php这个插件,用来将上传的文件进行"鉴别"与"搬移"。
  下面是process.php的程序:
  <?php
  require_once(dirname(__FILE__)."/../PIPHP_UploadFile.php");
      $response=array(
          'message'=>'未知上传错误',
          'path'=>'',
          'code'=>-4,   //上传结果代码,0表示成功,-1表示失败
          'width'=>100,
          'height'=>100,
          'scale'=>1,        //比例尺
          'name'=>''
      );
  if (!empty($_FILES))
  {
      $name='picture';
      $uploadFile='uploads/';
      $maxLen=9*1024*1024;
  
      $result=PIPHP_UploadFile($name,$uploadFile,$maxLen);
     
     
      $response['code']=$result[0];
      //简单汇报成功情况
      if($result[0]==0)
      {
          $response['message']='上传成功!';
          //$response['message']=$result[2];
          $response['path']=$result[1];
          $response['name']=$result[2];
          
          //获取图像的高度与宽度
          $fileName=iconv("utf-8","gb2312",$result[2]);
          list($width,$height)=getimagesize($_SERVER['DOCUMENT_ROOT'].$uploadFile.$fileName);
          $response['width']=$width;
          $response['height']=$height;
      }
      else
      {            
          switch($result[0])
          {
              case -1: $response['message']="上传失败"; break;
              case -2: $response['message']="文件类型错误";break;
              case -3: $response['message']="文件大小超过限制";break;
              default: $response['message']="错误代码:$result[0]";   
          }   
      }
  }
  else{
       $response['message']="上传文件出现错误!"."<br/>";
  }
      $json_str=json_encode($response);
      echo $json_str;
  ?>
  其实这个程序因为有了if判断语句而显示有点大,其实逻辑还是挺简单的。无论如何,这个程序返回的我上面说的有关图片的上传信息(放在$json_str这变量里了)
  
  3、继续改进uplodify的配置
  从上面知道,process.php返回的是一个$json_str变量,它里面有图像的路径,这样我们就可以在浏览器中显示图片啦!(注意此时显示的图片已经是在服务器上了)
  现在添加uploadify的'onComplete'选项,它告诉浏览器当process.php返回数据时应该怎么做。
  $('#pic_upload').uploadify({
      'uploader'  : '/uploadify/uploadify.swf',
      'script'    : 'process.php',        
      'cancelImg' : '/uploadify/cancel.png',
  
    'onComplete': function(event, ID, fileObj, response, data) {
          json_str=JSON.parse(response);
          var maxSize=400;
          var width=json_str.width;
          var height=json_str.height;
          var scale=json_str.scale;
          if(json_str.code == 0)
          {
               $('#uploadInfo').html(json_str.message+'<br/>平均上传速度:'+ data.speed.toFixed(2) + 'Kb/s');
               //对图像进行缩放
               if(json_str.width > maxSize || json_str.height >maxSize){
                  if( json_str.width > json_str.height)
                  {
                      width = maxSize;
                      height = maxSize / json_str.width * json_str.height;
                      json_str.scale = maxSize / json_str.width;
                  }
                  else
                  {
                      height = maxSize;
                      width = maxSize / json_str.height * json_str.width;
                      json_str.scale = maxSize / json_str.height;
                  }
               }
  
               $('#oriImage').html('<img src="/'+json_str.path+'" width=+'+width+' height='+height+' />');            
               //同时插入预览图
               $('#preview').empty().html('<img src="/'+json_str.path+'" width=+'+width+' height='+height+' />').css({
                      overflow:'hidden',
                      width:'150px',
                      height:'150px'
               });                          
          }
          else{
              $('#uploadInfo').html('错误代码['+json_str.code+']:<p>'+json_str.message+'</p>');
          }
    },
  });
  …   
  这里的程序主要做两件事,首先(第一种颜色标志处)显示上传的图,不过如果图片太大的话就应该显示缩放后的图,同时将缩放的比例保存到scale变量中;然后(第二处颜色标志处)再初始化裁剪预览图(用jQuery方法),注意这里只是初始化并没有动态显示裁剪预览图,动态显示部分要用imgAreaSelection这个插件完成。下面就开始讲这个插件吧
  
   4、用imgAreaSelection获取截图点坐标
  关于imgAreaSelection的使用说明请到官方上查看,这里就不再细讲。
  由于图片是动态加载的,所以不能事先将这个插件应用到图像上。我们可以设置一个按钮,当图片上传显示后,我们点击这个"加载裁剪框"按钮,将这个插件绑定到图像上。所以我们先在html上添加一个按钮,我是加载那个"图像预览"的DIV里:
              <div >
                  <h3>图片预览</h3>
  <button id="initCrop">加载裁剪框</button>   
                      <div id='oriImage' class="img_v">                 
  
                      </div>                    
              </div>
  然后在head中的<script>标签中写点击事件处理程序:
  $(document).ready(function(){
          $('#pic_upload').uploadify({
                  …
          });
          //加载裁剪框   
          $('#initCrop').click(function(e){
                  ias=$('#oriImage img').imgAreaSelect({instance:true});
                  ias.setOptions({ aspectRatio: '1:1', handle:true,
                                   hide:false,
                                   onSelectChange:preview2,
                                   onSelectEnd: function (img, selection) {
                                      json_str.x1=selection.x1;
                                      json_str.y1=selection.y1;
                                      json_str.cropWidth=selection.x2-selection.x1;
                                      json_str.cropHeight=selection.y2-selection.y1;
                                   },
                                  });                     
          });
  }
  </script>
  </head>
  这里的onSelectChange选项就是当改变裁剪框时所要调用的函数,这里使用preview2函数名作为值,这个函数我是另外写在下面的,当然你也可以使用匿名函数的。我是为了强调这个函数,所以写成实名函数:
  //图像预览函数
      function preview2(img, selection) {
          realWidth=json_str.width * json_str.scale;
          realHeight=json_str.height * json_str.scale;
          sizeWidth=150;sizeHeight=150;
          var scaleX = sizeWidth / selection.width ;
          var scaleY = sizeHeight / selection.height ;
        
          $('#preview img').css({
              width: Math.round(scaleX * realWidth) + 'px',
              height: Math.round(scaleY * realHeight) + 'px',
              marginLeft: - Math.round(scaleX * selection.x1) + 'px',
              marginTop: -Math.round(scaleY * selection.y1) + 'px'
          });
      };
  这个函数的功能是实现动态显示截图区域图像的,这个区域大小是150x150像素的一个小框,这里它动态加载css,注意要跟上一节中的uploadify中onComplete中预加载此截图框要联系起来。那里它是这么设置的:
   //同时插入预览图
               $('#preview').empty().html('<img src="/'+json_str.path+'" width=+'+width+' height='+height+' />').css({
                      overflow:'hidden',
                      width:'150px',
                      height:'150px'
               });                          
          }
  注意overflow:hidden的含义是将图像里超过这150x150像素的图像隐藏起来。其实这种方法借鉴自:http://odyniec.net/projects/imgareaselect/examples-callback.html
  另外的这插件中的onSelectEnd选项配置:当鼠标离开拖选框时,将此裁剪区域的左上角坐标与裁剪区的长、宽存储到json_str变量中,到时候传送给crop.php函数。
  
   5、将json_str数据传送给crop.php
  使用jQuery中的ajax()方法将json_str变量传送给服务器。先在html中添加一个"裁剪"按钮:
   <form id="cropData" >
             <input type="submit" name="submit" id="crop" value="裁剪" />
   </form>
  这里我使用了<form>元素,其实没有必要,可以是任何元素,因为我们使用的是强大的jQuery的ajax()方法。
  当用户确定要裁剪时,按下此按钮就会调用ajax()方法。我们将处理程序写在head部分的<script>元素中:
  //加载裁剪框   
      $('#initCrop').click(function(e){
                  …
      });
  //裁剪动作,将数据传给服务器,同时ajax返回图片
      $("#crop").click(function(e){
          if(!(typeof json_str == 'undefined'))
          {                    jsondata='data='+JSON.stringify(json_str);
                      $.ajax({
                              type:"POST",
                              url:"crop.php",
                              data:jsondata,//$('#cropData').serialize(),
                              success:function(msg){
                                  $("#cropResult").html('<img src="/'+msg+'"/>');//成功之后就清除发表内容
                                  //$("#cropResult").html(msg);                                                         
                              }            
                          });
                  }
                  else
                  {
                      alert('please load image first');
                  }
                  //关闭默认的提交动作   
                  return false;
              });
  //图像预览函数
      function preview2(img, selection) {…};
  上面的代码就等待着crop.php把文件路径传送回来,一旦传送回来,'success'选项所配置的函数就会将图片显示在id为'cropResult'的DIV里面了。
  
   6、crop.php对上传图片真正裁剪
  这个crop.php文件功能也很简单,通过浏览器返回给的json_str变量,由于该变量包含截图需要的起点坐标与裁剪的高度、宽度信息,然后调用PIPHP_ImageCrop.php插件,对图像进行真正的裁剪。然后将裁剪后的图像保存在另外文件夹中(我是将上传文件保存在uploads文件夹中,而截图结果放在avatar文件夹里),并将目标文件夹的路径返回给浏览器,让浏览器显示裁剪后的图片。
  这个程序的源代码:
  <?php
  require_once('../PIPHP_ImageCrop.php');
      $json_str=json_decode($_POST['data']);
      $x=$json_str->x1;
      $y=$json_str->y1;
      $scale=$json_str->scale;
      $cropWidth=$json_str->cropWidth;
      $cropHeight=$json_str->cropHeight;
      $path=$json_str->path;
      $filename=$json_str->name;
      $tofilename=iconv("utf-8","gb2312",$filename);
     
      $realX=$x/$scale;
      $realY=$y/$scale;
      $realWidth=$cropWidth/$scale;
      $realHeight=$cropHeight/$scale;
     
      $cropedImage=PIPHP_ImageCrop('http://'.$_SERVER['SERVER_NAME'].'/'.$path, $realX, $realY, $realWidth, $realHeight);
     
      $targetDir='avatar/';
      $targetFile=$targetDir.$tofilename;
     
      imagejpeg($cropedImage,$_SERVER['DOCUMENT_ROOT'].$targetFile);
     
      echo $targetDir.$filename.'?'.time();
      ?>
  需要注意的,最后返回的数据后加上'?'.time();是为了防止浏览器的缓存,如果不加此句,当用户完成截图后,重要再裁剪图片时,并不会马上更新裁剪得到的图片。
   好了,至此基本功能已经实现了,至于细节方面可以自己修改。

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-102745-1-1.html 上篇帖子: PHP Extension的开发基础 下篇帖子: PHP生成条形码
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表