最近项目里面需要用到上传和裁剪头像的功能,一开始采用的是美图秀秀,这是一款功能非常强大的插件,而且集成起来非常简单和方便,但是因为一个美女同事电脑跟该款软件不协调以及领导认为它的功能过于强大,所以该方案就被cut掉了,在网上查找了N多资料后,花费一天时间终于用uploadify + Jcrop + php 完整实现该功能,,特此mark一下!
这套方案的思路是先用uploadify将图片上传到服务器上面,然后前台得到Ajax中图片的路径显示到前台,然后通过jcrop进行裁剪并将裁剪后的参数传递到后台通过php裁剪干刚刚上传的图片,并删除以前上传的图片。
Uploadify
Uploadify是JQuery的一个上传插件,实现的效果非常不错,带进度显示,用起来也非常简单,我用的是当前最新版本ver3.2.1, 用过的同学应该知道它和以前的版本有一些区别,它添加了一个swf的参数用来设置上传按钮的样式,该样式可以通过修改uploadify.css文件来进行修改,所以如果程序中出现图片资源找不到的情况可以在里面进行修改。
- 支持单文件或多文件上传,可控制并发上传的文件数
- 在服务器端支持各种语言与之配合使用,诸如PHP,.NET,Java……
- 通过参数可配置上传文件类型及大小限制
- 通过参数可配置是否选择文件后自动上传
- 易于扩展,可控制每一步骤的回调函数(onSelect, onCancel……)
- 通过接口参数和CSS控制外观
html代码:
<div class="avatarEditor" >
<input type="file" name="file" class="uploadify" id="uploadify"/><a class="hide-info btn btn-primary js-avatar-edit avatar__setting-submit">确认编辑</a><img src="" class="js-file-jcrop">
</div>
js程序代码如下:
$('#uploadify').uploadify({
auto: true,
swf: themePath + '/css/resource/uploadify.swf',
uploader: 'saveAvatar',
buttonText: '图片上传',
fileObjName: 'userAvatarUrl',
fileSizeLimit: '2048KB',
onUploadSuccess: _handleUploadResponse,
});
auto: true,
swf: themePath + '/css/resource/uploadify.swf',
uploader: 'saveAvatar',
buttonText: '图片上传',
fileObjName: 'userAvatarUrl',
fileSizeLimit: '2048KB',
onUploadSuccess: _handleUploadResponse,
});
function _handleUploadResponse(file, data, response) {
var imageUrl = JSON.parse(data).url;$('.js-avatar-container img').attr('src', imageUrl);cropImage.url = imageUrl;$('.js-file-jcrop').Jcrop({allowResize: false,aspectRatio: 1,setSelect: [0, 0, 110, 110],onSelect: _setImageParams});$('.js-avatar-edit').show();}
function _setImageParams(coords) {
cropImage.height = coords.h;
cropImage.width = coords.w;
cropImage.x = coords.x;
cropImage.y = coords.y;
}
function _sendCropParams() {
//用Ajax把cropImage传送的后台并处理response
}
这是初始化Uploadify插件,有一点要注意,一定要用id选择器,因为在它的源代码中:
id : $this.attr('id'), // The ID of the DOM object
swf : 'uploadify.swf', // The path to the uploadify SWF file
uploader : 'uploadify.php', // The path to the server-side upload script
大家可以看到也是运用了id当作选择的核心元素来使用的,如果不是id的话会报一个类似于 null element的错误!
swf : 'uploadify.swf', // The path to the uploadify SWF file
uploader : 'uploadify.php', // The path to the server-side upload script
大家可以看到也是运用了id当作选择的核心元素来使用的,如果不是id的话会报一个类似于 null element的错误!
uploadify参数:
- auto
- buttonClass
- buttonCursor
- buttonImage
- buttonText
- checkExisting
- debug
- fileObjName
- fileSizeLimit
- fileTypeDesc
- fileTypeExts
- formData
- height
- itemTemplate
- method
- multi
- overrideEvents
- preventCaching
- progressData
- queueID
- queueSizeLimit
- removeCompleted
- removeTimeout
- requeueErrors
- successTimeout
- swf
- uploader
- uploadLimit
- width
jcrop参数:
allowSelect true 允许新选框 allowMove true 允许选框移动 allowResize true 允许选框缩放 trackDocument true baseClass "jcrop" 基础样式名前缀。说明:class="jcrop-holder",更改的只是其中的 jcrop。 addClass null 添加样式会。例:假设值为 "test",那么会添加样式到 class="test jcrop-holder" bgColor "black" 背景颜色。颜色关键字、HEX、RGB 均可。 bgOpacity 0.6 背景透明度 bgFade false 使用背景过渡效果 borderOpacity 0.4 选框边框透明度 handleOpacity 0.5 缩放按钮透明度 handleSize 9 缩放按钮大小 handleOffset 5 缩放按钮与边框的距离 aspectRatio 0 选框宽高比。说明:width/height keySupport true 支持键盘控制。按键列表:上下左右(移动)、Esc(取消)、Tab(跳出裁剪框,到下一个) cornerHandles true 允许边角缩放 sideHandles true 允许四边缩放 drawBorders true 绘制边框 dragEdges true 允许拖动边框 fixedSupport true touchSupport null boxWidth 0 画布宽度 boxHeight 0 画布高度 boundary 2 边界。说明:可以从边界开始拖动鼠标选择裁剪区域 fadeTime 400 过度效果的时间 animationDelay 20 动画延迟 swingSpeed 3 过渡速度 minSelect [0,0] 选框最小选择尺寸。说明:若选框小于该尺寸,则自动取消选择 maxSize [0,0] 选框最大尺寸 minSize [0,0] 选框最小尺寸 onChange function(){} 选框改变时的事件 onSelect function(){} 选框选定时的事件 onRelease function(){} 取消选框时的事件 api方法
名称 说明 setImage(string) 设定(或改变)图像。例:jcrop_api.setImage("newpic.jpg") setOptions(object) 设定(或改变)参数,格式与初始化设置参数一样 setSelect(array) 创建选框,参数格式为:[x,y,x2,y2] animateTo(array) 用动画效果创建选框,参数格式为:[x,y,x2,y2] release() 取消选框 disable() 禁用 Jcrop。说明:已有选框不会被清除。 enable() 启用 Jcrop destroy() 移除 Jcrop tellSelect() 获取选框的值(实际尺寸)。例子:console.log(jcrop_api.tellSelect()) tellScaled() 获取选框的值(界面尺寸)。例子:console.log(jcrop_api.tellScaled()) getBounds() 获取图片实际尺寸,格式为:[w,h] getWidgetSize() 获取图片显示尺寸,格式为:[w,h] getScaleFactor() 获取图片缩放的比例,格式为:[w,h]
php 代码:
public function actionSaveAvatar()
{
$response = array();
if (!$this->_user->isGuest)
{
$uploadFile = $_FILES['userAvatarUrl'];
$result = $this->_moveAvatar($uploadFile, $this->_user->id);
if ($result['response'])
{
$response['status'] = STATUS_SUCCESS;
$response['url'] = $this->_getUserAvatar($result['url']);
}
else
{
$response['status'] = STATUS_FAIL;
}
}
else
{
$response['status'] = 'timeout';
}
$this->responseJSON($response);
}
private function _moveAvatar($file, $userId)
{
$imageFormat = array('image/gif', 'image/jpeg', 'image/pjpeg');
$result = array();
// if (in_array($file['type'], $imageFormat)
// && ($file['size'] < 2048000)
// && ($file['error'] === 0))
if ($file['size'] < 2048000)
{
$fileType = $this->_getUploadfileType($file['name']);
$newName = 'upload/' .md5($userId) .'_tmp' . $fileType;
$moveResult = move_uploaded_file($file['tmp_name'], $newName);
if ($moveResult)
{
$result['response'] = true;
$result['url'] = $newName;
}
else
{
$result['response'] = false;
}
}
else
{
$result['response'] = false;
}
return $result;
}
private function _getUploadfileType($fileName)
{
$num = strrpos($fileName, '.');
$len = strlen($fileName);
return substr($fileName, $num, $len - 1);
}
private function _genarateImageUrl($fileUrl)
{
$basePath = dirname(Yii::app()->BasePath) . 'upload/';
$num = strrpos($fileUrl, '/upload');
return substr($fileUrl, $num, strlen($fileUrl) - 1);
}
public function actionSaveCropAvatar()
{
if (!$this->_user->isGuest && $this->_request->isPostRequest)
{
$cropImage = $this->_request->getPost('data');
$imageBasePath = dirname(Yii::app()->BasePath) . $this->_genarateImageUrl($cropImage['url']);
$newImageUrl = str_ireplace('_tmp.', '.', $imageBasePath);
$thisimage = imagecreatetruecolor($cropImage['width'], $cropImage['height']);
$oldimg = imagecreatefromjpeg($imageBasePath);
imagecopy($thisimage, $oldimg, 0, 0, $cropImage['x'], $cropImage['y'], $cropImage['width'], $cropImage['height']);
$result = imagejpeg($thisimage, $newImageUrl, 100);//完成剪切后将裁剪后的图片复制到指定目录中
{
$response = array();
if (!$this->_user->isGuest)
{
$uploadFile = $_FILES['userAvatarUrl'];
$result = $this->_moveAvatar($uploadFile, $this->_user->id);
if ($result['response'])
{
$response['status'] = STATUS_SUCCESS;
$response['url'] = $this->_getUserAvatar($result['url']);
}
else
{
$response['status'] = STATUS_FAIL;
}
}
else
{
$response['status'] = 'timeout';
}
$this->responseJSON($response);
}
private function _moveAvatar($file, $userId)
{
$imageFormat = array('image/gif', 'image/jpeg', 'image/pjpeg');
$result = array();
// if (in_array($file['type'], $imageFormat)
// && ($file['size'] < 2048000)
// && ($file['error'] === 0))
if ($file['size'] < 2048000)
{
$fileType = $this->_getUploadfileType($file['name']);
$newName = 'upload/' .md5($userId) .'_tmp' . $fileType;
$moveResult = move_uploaded_file($file['tmp_name'], $newName);
if ($moveResult)
{
$result['response'] = true;
$result['url'] = $newName;
}
else
{
$result['response'] = false;
}
}
else
{
$result['response'] = false;
}
return $result;
}
private function _getUploadfileType($fileName)
{
$num = strrpos($fileName, '.');
$len = strlen($fileName);
return substr($fileName, $num, $len - 1);
}
private function _genarateImageUrl($fileUrl)
{
$basePath = dirname(Yii::app()->BasePath) . 'upload/';
$num = strrpos($fileUrl, '/upload');
return substr($fileUrl, $num, strlen($fileUrl) - 1);
}
public function actionSaveCropAvatar()
{
if (!$this->_user->isGuest && $this->_request->isPostRequest)
{
$cropImage = $this->_request->getPost('data');
$imageBasePath = dirname(Yii::app()->BasePath) . $this->_genarateImageUrl($cropImage['url']);
$newImageUrl = str_ireplace('_tmp.', '.', $imageBasePath);
$thisimage = imagecreatetruecolor($cropImage['width'], $cropImage['height']);
$oldimg = imagecreatefromjpeg($imageBasePath);
imagecopy($thisimage, $oldimg, 0, 0, $cropImage['x'], $cropImage['y'], $cropImage['width'], $cropImage['height']);
$result = imagejpeg($thisimage, $newImageUrl, 100);//完成剪切后将裁剪后的图片复制到指定目录中
$response = array();
if ($result)
{
$userId = $this->_user->id;
$user = User::model()->findByPk($userId);
$user->picture = str_ireplace('_tmp.', '.', $cropImage['url']);
$this->saveData($user);
$response['status'] = STATUS_SUCCESS;
}
else
{
$response['status'] = STATUS_FAIL;
}
$this->responseJSON($response);
}
}
if ($result)
{
$userId = $this->_user->id;
$user = User::model()->findByPk($userId);
$user->picture = str_ireplace('_tmp.', '.', $cropImage['url']);
$this->saveData($user);
$response['status'] = STATUS_SUCCESS;
}
else
{
$response['status'] = STATUS_FAIL;
}
$this->responseJSON($response);
}
}