在网站中需要一个图片上传裁剪的功能,借鉴这篇文章 Ajax+PHP+jQuery图片截图上传 的指点,找到了jquery.imgAreaSelect这个不错插件,能对图片进行自定义区域选择并给出坐标,类似微博等同类网站上传头像要求按比例裁剪的功能,正合适就自己做了个。

文件上传类经常使用到一个叫uploadify的插件,上面提到的文章也结合了uploadify插件的使用,只是现在版本的uploadify一些配置和方法已经改变了(3.2.1版本)。包括jquery.imgareaselect的一些API也有新的变化,在做的过程中通过查询文档才确认了一些功能和配置的用法。
下面是两个插件的地址
uploadify: http://www.uploadify.com/ ( 有 uploadifive(HTML5) 版本和 Flash 版本,顾及不支持HTML5的浏览器,目前建议选择Flash版本 )
jquery.imgareaselect: http://odyniec.net/projects/imgareaselect ( 需先有 jQuery )
具体的流程都相似,客户端uploadify替代表单接收原图,异步上传到服务器,服务器端接收后存储并返回图片文件名,取得文件名后可在浏览器显示出原图,这时在图片元素上配置imgareaselect使其可划定裁剪区域,划定结束后坐标传回服务器,PHP脚本接收换算后的坐标对原图进行裁剪。上面提到的文章中有详细的流程图,作者非常细心。
下面说说我写的过程
上细节:首先是前端的配置
demo.php:
[javascript] view plain copy
- $field = $("input[type='file']");
- $field.uploadify({
- 'buttonText': '选择图片',
- 'swf' : '/uploadify/uploadify.swf',
- 'uploader' : '/receivePic.php',
- 'cancelImg' : '/uploadify/uploadify-cancel.png',
- 'folder' : '/picture',
- 'auto' : false,
- 'multi' : false,
- 'method' : 'post',
- 'queueSizeLimit' : 1,
- 'fileTypeExts': '*.gif; *.jpg; *.png',
- 'fileTypeDesc': 'Image Files',
-
- 'onSelect': function(file) {
- $("a.xtPicSubmit").show().click(function(){
- $field.uploadify('upload','*');
- });
- $wrap.find("p.picInfo span").text(file.name);
- },
-
- 'onUploadSuccess' : function(file, data, response) {
- $field.uploadify('disable', true);
- data = JSON.parse(data);
-
-
-
- var orignW = data.width,
- orignH = data.height,
- aspectRatio = JSON.parse(picFormat)[index].width/JSON.parse(picFormat)[index].height,
- frameW = 260,
- frameH = 0,
- prevFrameW = 140,
- prevFrameH = 140/aspectRatio,
- rangeX = 1,
- rangeY = 1,
- prevImgW = prevFrameW,
- prevImgH = prevFrameW;
-
- $imgTar = $wrap.find("img.pic"),
- $imgCut = $cut.find("img.cutImg");
-
- $imgTar.attr("src","/Picture/"+data.filename);
- frameH = Math.round(frameW*orignH/orignW);
- $cut.find(".preview").css('height',Math.round(prevFrameH)+"px");
-
-
- CutJson.name = data.filename;
- CutJson.position = {};
-
-
- var imgArea = $imgTar.imgAreaSelect({
- instance: true,
- handles: true,
- fadeSpeed: 300,
- aspectRatio:'1:'+(1/aspectRatio),
-
- onSelectChange: function(img,selection){
-
- rangeX = selection.width/frameW;
- rangeY = selection.height/frameH;
- prevImgW = prevFrameW/rangeX;
- prevImgH = prevFrameH/rangeY;
-
-
- $imgCut.css({
- 'width' : Math.round(prevImgW)+"px",
- 'height' : Math.round(prevImgH)+"px",
- 'margin-left':"-"+Math.round((prevFrameW/selection.width)*selection.x1)+"px",
- 'margin-top' :"-"+Math.round((prevFrameH/selection.height)*selection.y1)+"px"
-
- });
- },
- onSelectEnd: function(img,selection){
-
- CutJson.position.x1 = Math.round(orignW*selection.x1/frameW);
- CutJson.position.y1 = Math.round(orignH*selection.y1/frameH);
- CutJson.position.width = Math.round(rangeX*orignW);
- CutJson.position.height = Math.round(rangeY*orignH);
- }
- });
- }
- });
此时已经取得了裁剪的坐标,只需将坐标传回服务器交给脚本处理
使用jQuery的ajax方法回传数据:
[javascript] view plain copy
- $("a.getCut").click(function(){
- $.ajax({
- type: "POST",
- url : "cutPic.php",
- data: { name:data.filename,position:JSON.stringify(CutJson.position) },
- success: function(data){
- $imgTar.attr('src',"/picture/cut/"+data);
- }
- });
- });
至此前端的处理就基本完成了(代码省去了一些状态显示,元素变化的处理细节),下面是后端的两个脚本:
首先是接收上传图片的脚本,接收并存储图片后返回图片数据:
receivePic.php
-
-
- $arr = getimagesize('/picture/'.$file['name']);
- $strarr = explode("\"",$arr[3]);
- $data = array(
- 'filename'=>$file['name'],
- 'width'=>$strarr[1],
- 'height'=>$strarr[3]
- );
- echo json_encode($data);
接下来是裁剪,其中也用到了PIPHP_ImageCrop裁剪函数
cutPic.php:
- function PIPHP_ImageCrop($image, $x, $y, $w, $h){
- $tw = imagesx($image);
- $th = imagesy($image);
-
- if ($x > $tw || $y > $th || $w > $tw || $h > $th)
- return FALSE;
-
- $temp = imagecreatetruecolor($w, $h);
- imagecopyresampled($temp, $image, 0, 0, $x, $y,
- $w, $h, $w, $h);
- return $temp;
- }
-
- $pic = '/picture/'.$_POST['name'];
- $cutPosition = json_decode($_POST['position']);
- $x1 = $cutPosition->x1;
- $y1 = $cutPosition->y1;
- $width = $cutPosition->width;
- $height = $cutPosition->height;
-
- $type=exif_imagetype($pic);
- $support_type=array(IMAGETYPE_JPEG , IMAGETYPE_PNG , IMAGETYPE_GIF);
- if(!in_array($type, $support_type,true)) {
- echo "this type of image does not support! only support jpg , gif or png";
- exit();
- }
- switch($type) {
- case IMAGETYPE_JPEG :
- $image = imagecreatefromjpeg($pic);
- break;
- case IMAGETYPE_PNG :
- $image = imagecreatefrompng($pic);
- break;
- case IMAGETYPE_GIF :
- $image = imagecreatefromgif($pic);
- break;
- default:
- echo "Load image error!";
- exit();
- }
-
- $copy = PIPHP_ImageCrop($image, $x1, $y1, $width, $height);
-
- $targetPic = '/picture/cut/'.$_POST['name'];
-
- imagejpeg($copy, $targetPic);
-
- @unlink($pic);
-
- echo $_POST['pic'].'?'.time();
整个过程就完成了。上个效果图:

开始的部分很多参考了Ajax+PHP+jQuery图片截图上传 此篇详细的文章,这里再次说明。
后端的交互很轻松,任务主要在于前端两个插件之间的搭建和使用,我的代码写的比较仓促,应该需要更加结构化一点。另外上传文件的各方面控制也是一个风险(类型,大小等),值得更多的考虑。