Web 技术研究所

我一直坚信着,Web 将会成为未来应用程序的主流

在线图片裁剪(兼容IE8)

  现在很多网站都需要用户上传头像,而用户电脑里的图片通常不是需求的规格,因此在线图片裁剪功能的需求就诞生了。现代浏览器上很容易实现,但是在IE8上就比较麻烦。首先要接解决图片的本地预览问题,然后再解决操作兼容的问题,最后才是裁剪的问题。
  实际上用IE8做纯前端的裁剪是不现实的,最终裁剪的步骤只能交给后端。但是计算坐标,和图片预览在前端可以做到。IE8上可以使FILE控件的一个BUG来取得本地文件的路径。用AlphaImageLoader滤镜来加载本地图片。然后交给用户操作,最后把缩放、坐标等,一些参数和图片一起传到服务器,由服务器来裁剪。
  现代浏览器可以用Canvas直接在前端做裁剪,最后生成DataURL的。而且图片的本地预览也有FileReader这个API可以用,所以完全没有难点。但这里的例子为了便于和IE8兼容,整个还是使用了IE8的思路。
  这里的服务器端程序用了PHP,裁剪图片用了PHP的GD库。下面是代码: <?
if($f=$_FILES['f']){
  switch($f['type']){
    case 'image/png':
    case 'image/x-png':
      $img=imagecreatefrompng($f['tmp_name']);
      break;
    case 'image/gif':
      $img=imagecreatefromgif($f['tmp_name']);
      break;
    case 'image/jpeg':
    case 'image/pjpeg':
      $img=imagecreatefromjpeg($f['tmp_name']);
      break;
    default:
      die('error');
  };
  extract(array_intersect_key($_POST,array_flip(array('s','x','y','m'))));
  $m>0&&$s>0 or die('error');
  $new=imagecreatetruecolor($m,$m);
  imagefill($new,0,0,imagecolorallocate($new,255,255,255));
  imagecopyresampled($new,$img,0,0,$x/$s,$y/$s,$m,$m,$m/$s,$m/$s);
  ob_clean();
  imagepng($new);
  $data=ob_get_clean();
  $name=md5($data).'.png';
  file_put_contents($name,$data);
  header("Location: $name");
  die;
};
?>
<style>
#panel {
  float:left;
  border:1px solid #CCC;
  position:relative;
  font-size:0px;
  overflow:hidden;
  user-select:none;
  background:#FFF;
  text-align:left;
}
#image {
  border:1px solid red;
  display:inline-block;
  visibility:hidden;
  transform-origin:left top;
}
#mask {
  display:none;
  position:absolute;z-index:1;
  opacity:0.5;
  filter:progid:DXImageTransform.Microsoft.Alpha(opacity=50);
}
#point {
  display:none;
  border:1px solid #CCC;
  margin:-1px;
  position:absolute;z-index:1;
  cursor:move;
}
#display {
  float:left;overflow:hidden;
  border:1px solid #CCC;
  margin-left:12px;
  background:#FFF;
}
</style>
<form target="_blank" method="post" enctype="multipart/form-data">
  <div id="panel">
    <div id="image"></div>
    <div id="mask"></div>
    <div id="point"></div>
  </div>
  <div id="display">
    <div id="wrap"></div>
  </div>
  <input type="file" name="f" />
  <input type="hidden" name="s" />
  <input type="hidden" name="x" />
  <input type="hidden" name="y" />
  <input type="hidden" name="m" /><br/>
  <input type="submit" value="上传" />
</form>
<script>
onload=function(){
  //获取元素
  var panel=document.getElementById("panel");
  var image=document.getElementById("image");
  var mask=document.getElementById("mask");
  var point=document.getElementById("point");
  var display=document.getElementById("display");
  var wrap=document.getElementById("wrap");
  var file=document.querySelector("input[type=file]");
  var submit=document.querySelector("input[type=submit]");
  var form=document.forms[0];
  //基本参数初始化
  var PANELSIZE=300,DISPLAYSIZE=128;
  panel.style.width=PANELSIZE+"px";
  panel.style.height=PANELSIZE+"px";
  mask.style.border=PANELSIZE+"px solid #CCC";
  mask.style.margin=-PANELSIZE+"px";
  display.style.width=DISPLAYSIZE+"px";
  display.style.height=DISPLAYSIZE+"px";
  var pointsize=DISPLAYSIZE,x=0,y=0,mirro;
  //提交
  submit.onclick=function(){
    document.querySelector("input[name=s]").value=mirro.s;
    document.querySelector("input[name=x]").value=-parseFloat(wrap.style.marginLeft);
    document.querySelector("input[name=y]").value=-parseFloat(wrap.style.marginTop);
    document.querySelector("input[name=m]").value=DISPLAYSIZE;
  };
  //事件操作兼容
  var on,off;
  if(-[1,])
    on=function(e,n,f){e.addEventListener(n,f);},
    off=function(e,n,f){e.removeEventListener(n,f);};
  else
    on=function(e,n,f){e.attachEvent("on"+n,f);},
    off=function(e,n,f){e.detachEvent("on"+n,f);};
  //选择文件
  on(file,"change",function(){
    //加载图片文件
    if(file.files){
      //现代浏览器使用FileReader加载
      var reader=new FileReader;
      reader.readAsDataURL(file.files[0]);
      reader.onload=function(){
        var path=reader.result,img=new Image;
        img.onload=function(){
          image.style.background="url("+path+") no-repeat";
          init(img.width,img.height);
        },img.src=path;
      };
    }else{
      //低版本IE使用AlphaImageLoader滤镜加载
      //无法直接获取到文件的本地路径,只能通过选区(这是个IE的BUG)
      file.select(),file.blur(); //不调用blur的话IE9会出错
      var path=document.selection.createRange().text;
      image.style.filter="progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+path+"')";
      setTimeout(function(){
        init(image.offsetWidth-2,image.offsetHeight-2);
      },100);
    };
    //图片加载成功后展示图片
    function init(w,h){
      if(point.offsetWidth==0){
        mask.style.display=point.style.display="block";
        x=0,y=0;
      };
      var m=Math.max(w,h),s=PANELSIZE/m;
      image.w=w,image.h=h,image.s=s;
      scale(image,s);
      image.style.width=w+"px";
      image.style.height=h+"px";
      image.style.borderWidth="0px";
      image.style.visibility="visible";
      resize();
    };
  });
  //拖动裁剪区域
  on(point,"mousedown",function(e){
    var e=e||event;
    var px=x-e.clientX,py=y-e.clientY;
    var mouseup,mousemove;
    on(document,"mouseup",mouseup=function(){
      off(document,"mouseup",mouseup);
      off(document,"mousemove",mousemove);
    }),on(document,"mousemove",mousemove=function(e){
      var e=e||event;
      move(px+e.clientX,py+e.clientY);
    });
  });
  //滚轮控制裁剪区域缩放
  point["onwheel" in point?"onwheel":"onmousewheel"]=function(e){
    var e=e||event;
    var delta=(e.wheelDelta?e.wheelDelta/-120:e.deltaY/3)*4;
    var value=pointsize+delta;
    if(value<32||value>PANELSIZE)return;
    pointsize=value;
    move(x-delta/2,y-delta/2);
    resize();
    if(e.preventDefault)e.preventDefault();
    return false;
  };
  //其它操作函数定义
  function move(ux,uy){
    var m=PANELSIZE-pointsize;
    x=Math.min(Math.max(ux,0),m);
    y=Math.min(Math.max(uy,0),m);
    mask.style.left=point.style.left=x+"px";
    mask.style.top=point.style.top=y+"px";
    var ratio=Math.max(image.w,image.h)*wrap.firstChild.s;
    wrap.style.marginLeft=-(wrap.x=ratio*x/PANELSIZE)+"px";
    wrap.style.marginTop=-(wrap.y=ratio*y/PANELSIZE)+"px";
  };
  function resize(){
    mask.style.width=mask.style.height=
    point.style.width=point.style.height=
      pointsize+"px";
    mirro=image.cloneNode();
    scale(mirro,mirro.s=image.s*DISPLAYSIZE/pointsize);
    wrap.innerHTML="";
    wrap.appendChild(mirro);
    move(x,y);
  };
  function scale(e,s){
    if("zoom" in e.style)e.style.zoom=s;
    else 
      e.style.transform="scale("+s+")",
      e.style.marginRight=-e.w*(1-s)+"px",
      e.style.marginBottom=-e.h*(1-s)+"px";
  };
};
</script>
  
网名:
54.144.24.*
电子邮箱:
仅用于接收通知
提交 悄悄的告诉你,Ctrl+Enter 可以提交哦
神奇海螺
[查看全部主题]
各类Web技术问题讨论区
发起新主题
本模块采用即时聊天邮件通知的模式
让钛合金F5成为历史吧!
次碳酸钴的技术博客,文章原创,转载请保留原文链接 ^_^