裁剪图片用的是PHP原生的方法,首先将文件上传到后台,再利用jcrop在前台裁剪图片,将裁剪的矩形的四个点的坐标传到后台,后台根据接收到的参数利用imagecopyresampled函数对上传的图片进行裁剪。
我的界面设计效果大概如下:
首先是点击选择图片按钮弹出file对话框,在选定文件后触发文件选择框的change事件,此时用ajaxFileUpload插件(异步上传文件)先将图片上传到后台。
//选择完文件后预览 $('#upload-file').on("change",function(){ ajax_file_upload(); });
function ajax_file_upload(){ if(jcrop_api != null){ jcrop_api.destroy(); } $.ajaxFileUpload({ url: '../ajax/upload_img',//用于文件上传的服务器端请求地址 secureuri: false,//是否需要安全协议,一般设置为false fileElementId: 'upload-file',//文件上传域的ID dataType: 'json',//返回值类型 一般设置为json success: function (data,status) //服务器成功响应处理函数 { if(data.code == 1){ pic_name = data.name; //将上传的图片显示到前台并开启裁剪插件 $("#crop-img").attr("src","../../resouces/pictures_temp/"+data.name); $('#crop-img').Jcrop({ setSelect:[0,100,100],aspectRatio: 1 },function(){ // Store the API in the jcrop_api variable jcrop_api = this; }); }else{ layer.msg('上传失败!',{ offset:"200px",}); } //重新绑定事件 事件失效原因未知 $('#upload-file').on("change",function(){ ajax_file_upload(); }); },}); }有时由于未知原因,在上传后会使file选择框的change事件失效,故若想修改之前上传的图片,得在上传方法执行成功后再次绑定一次change事件。
先附上upload_img方法,我的后台采用的是CI框架,故上传用的是CI框架封装好的方法:
//上传个人头像 public function upload_img(){ $id = $this->session->userdata('uid'); $config['upload_path'] = './resouces/pictures_temp/'; //如果目录不存在则创建 if(!file_exists($config['upload_path'])) { mkdir($config['upload_path'],0700,true); } $config['encrypt_name'] = false; $config['allowed_types'] = 'jpg|png';//文件类型 $config['max_size'] = '10240'; $config['file_name'] = $id.".jpg"; $file = $config['upload_path'].$config['file_name']; if(file_exists($file)){ unlink($file); } $result['name'] = $config['file_name']; $this->load->library('upload',$config); if ($this->upload->do_upload('upload-file')) { $result['code'] = 1; $uploaddata = $this->upload->data(); $result['width'] = $uploaddata['image_width']; $result['height'] = $uploaddata['image_height']; }else{ $result['code'] = 2; $result['error'] = $this->upload->display_errors();//输出错误原因 } echo json_encode($result); }后台图片上传完后,前台对jcrop进行初始化,我这边设定了一个默认的100*100的裁剪框。效果如下:
此时可根据自身需求随意设定需要裁剪的位置和大小,当点击上传时,将获取裁剪矩形的4个点的坐标,将参数传递到后台:
//上传图片 $('#upload-img').on("click",function(){ //获取截取框4点的坐标 var x = jcrop_api.tellSelect().x; var y = jcrop_api.tellSelect().y; var width = jcrop_api.tellSelect().x2 - x; var height = jcrop_api.tellSelect().y2 - y; //将值传到PHP后台 PHP对图片进行处理 $.post('../ajax/crop_img',{ x:x,y:y,width:width,height:height,name:pic_name,},function(data){ var imgStr = "../../resouces/pictures/"+data; $('.show-area > img').attr("src",imgStr); layer.msg('上传成功!',{ offset:"200px",}); },'text'); });由于jcrop提供的方法几乎都只能打印出矩形4个点的坐标,而imagecopyresampled这个方法需要裁剪后的图片的宽高,所以我在前台先做了一遍计算,再将值传递过去。
后台crop_img是我用来处理生成后的图片并入库的方法,它直接调用了get_crop_img()方法对图像进行裁剪:
//裁剪头像并入库 public function crop_img(){ $id = $this->session->userdata('uid'); $x = $this->input->get_post("x"); $y = $this->input->get_post("y"); $width = $this->input->get_post("width"); $height = $this->input->get_post("height"); $name = $this->input->get_post("name"); $filename = './resouces/pictures_temp/' . $name; $newname = './resouces/pictures/' . $name; get_crop_img($filename,$newname,$x,$y,$width,$height); $conditions = array($name,$id); $this->user_model->editPersonImgById($conditions); echo $name; }
//获取裁剪的头像 function get_crop_img($filename,$height){ //如果文件存在则删除 if(file_exists($newname)){ chmod($newname,0755); unlink($newname); } //获取原图的信息 $info = getImageInfo($filename); //计算新生成的图片尺寸 $width = $width * ($info['width']/300); $height = $height * ($info['height']/300); $x = $x * ($info['width']/300); $y = $y * ($info['height']/300); $newimg = imagecreatetruecolor(100,100); //创建新的图层 $img = imagecreatefromjpeg($filename); //把原本的图片读进来 imagecopyresampled($newimg,$img,$height); //画图 imageinterlace($newimg,1); //隔行扫描 imagejpeg($newimg,100); //生成图片 imagedestroy($newimg); imagedestroy($img); }getImageInfo()是随手写的一个获取当前图片部分信息的函数:
//获取图片的信息 function getImageInfo($img){ $imageInfo = getimagesize($img); if( $imageInfo!== false) { $imageType = strtolower(substr(image_type_to_extension($imageInfo[2]),1)); $info = array( "width" =>$imageInfo[0],"height" =>$imageInfo[1],"type" =>$imageType,"mime" =>$imageInfo['mime'],); return $info; }else { return false; } }生成裁剪图片的流程大概如下:
1. 用imagecreatetruecolor($width,$height)方法生成一个新的空白图层,宽高由你自定义。
2. 用imagecreatefromjpeg($src)方法读取原本图片的资源,$src为图片的路径。返回的对象为一个图层对象。
3. 用imagecopyresampled ($dst_image,$src_image,int $dst_x,int $dst_y,int $src_x,int $src_y,int $dst_w,int $dst_h,int $src_w,int $src_h )方法裁剪原图片,然后将新的图片画到之前创建的空白图层上。$dst_image即你裁剪后图片要画到哪个图层对象,$src_image即原图,$dst_x,$dst_y即为从新图层开始绘画的起始点坐标(即矩形左上角,因为我是新创建的图层,所以我是从(0,0)这个点开始画),int $src_x,$src_y 即为从原图上所截取图片的起始点(截图矩形的左上角点坐标)。dst_w,dst_h 即新图层上你所要画的图片的宽高,src_w,src_h即为从原图上所截取图片的宽高。这里我对宽高都进行了一定运算,因为我前台是不限制上传图片的像素的,但固定按300*300显示,而jcrop获取的所有参数都是对300*300这个图层进行操作所获取到的,所以我要知道在原图上裁剪的比例,我必须对图片宽高和xy坐标重新计算一遍,即 (300像素图上裁剪的尺寸/300)*原图尺寸 = 原图裁剪的尺寸。
4.imagejpeg($newimg,$quality),$newimg即为刚刚绘画了的空白图层,$newname即为你要新生成的图片的路径地址(含名字),$quality即为生成图片的质量,默认为75,这里最好填100,不然生成的裁剪图片可能会有瑕疵。
5.imagedestroy($img)销毁图层,释放资源。
注:我为了简便,将上传的图片都做了处理,在后台都生成的是jpg文件,裁剪后的图片我也生成的是jpg文件,如果要生成png文件的话,PHP方法可能会有部分不同,但仅仅只是将适用与jpeg格式的方法换为适用于png格式的方法。
最后附上裁剪后的结果图: