基本原理:JS裁切头像,生成头像预览图,并获取图像坐标,相对缩放的宽高! 然后通过表单提交,将图片上传,并提交原点坐标,以及缩放后的相对宽高,然后在服务端再次裁切,通过服务器脚本语言的图像处理库,如php的gd库!!
php图像裁切函数代码:
private function uploadImageFile() { // Note: GD library is required for this function
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
$iWidth = $iHeight = 200; // desired image result dimensions
$iJpgQuality = 90;
//$ext = end(explode('.',$_FILES['image_file']['name']));
if ($_FILES) {
// if no errors and size less than 250kb
if (! $_FILES['image_file']['error']) {
if (is_uploaded_file($_FILES['image_file']['tmp_name'])) {
// new unique filename
$sTempFileName = $_SERVER['DOCUMENT_ROOT'].'/upload/avatar/' . md5(time().rand());
// move uploaded file into cache folder
move_uploaded_file($_FILES['image_file']['tmp_name'],$sTempFileName);
// change file permission to 644
@chmod($sTempFileName, 0644);
if (file_exists($sTempFileName) && filesize($sTempFileName) > 0) {
$aSize = getimagesize($sTempFileName); // try to obtain image info
if (!$aSize) {
@unlink($sTempFileName);
return;
}
// check for image type
switch($aSize[2]) {
case IMAGETYPE_JPEG:
$sExt = '.jpg';
// create a new image from file
$vImg = @imagecreatefromjpeg($sTempFileName);
break;
case IMAGETYPE_PNG:
$sExt = '.png';
// create a new image from file
$vImg = @imagecreatefrompng($sTempFileName);
break;
default:
@unlink($sTempFileName);
return;
}
// create a new true color image
$vDstImg = @imagecreatetruecolor( $iWidth, $iHeight );
// copy and resize part of an image with resampling
imagecopyresampled($vDstImg, $vImg, 0, 0, (int)$_POST['dx'],(int)$_POST['dy'], $iWidth, $iHeight, (int)$_POST['dw'], (int)$_POST['dh']);
// define a result image filename
$sResultFileName = $sTempFileName . $sExt;
// output image to file
imagejpeg($vDstImg, $sResultFileName, $iJpgQuality);
@unlink($sTempFileName);
$returnurl = '/upload/avatar/'.end(explode('/',$sResultFileName));
return $returnurl;
}
}
}
}
}
}
js插件可以使用cropbox或者是jcrop;
自己修改过针对兼容性的cropbox.js
/**
* Created by ezgoing on 14/9/2014.
*/
"use strict";
(function (factory) {
if (typeof define === 'function' && define.amd) {
define(['jquery'], factory);
} else {
factory(jQuery);
}
}(function ($) {
var cropbox = function(options, el){
var el = el || $(options.imageBox),
obj =
{
state : {},
ratio : 1,
options : options,
imageBox : el,
thumbBox : el.find(options.thumbBox),
spinner : el.find(options.spinner),
image : new Image(),
getDataURL: function ()
{
var width = this.thumbBox.width(),
height = this.thumbBox.height(),
canvas = document.createElement("canvas"),
dim = el.css('background-position').split(' '),
size = el.css('background-size').split(' '),
dx = parseInt(dim[0]) - el.width()/2 + width/2,
dy = parseInt(dim[1]) - el.height()/2 + height/2,
dw = parseInt(size[0]),
dh = parseInt(size[1]),
sh = parseInt(this.image.height),
sw = parseInt(this.image.width);
canvas.width = width;
canvas.height = height;
var context = canvas.getContext("2d");
context.drawImage(this.image, 0, 0, sw, sh, dx, dy, dw, dh);
var imageData = canvas.toDataURL('image/png');
return imageData;
},
getPos: function(){
var width = this.thumbBox.width(),
height = this.thumbBox.height(),
canvas = document.createElement("canvas"),
dim = el.css('background-position').split(' '),
size = el.css('background-size').split(' '),
dx = el.width()/2 - width/2-parseInt(dim[0]),
dy = el.height()/2 - height/2-parseInt(dim[1]),
dw = parseInt(size[0]),
dh = parseInt(size[1]),
sh = parseInt(this.image.height),
sw = parseInt(this.image.width);
obj.dx = dx;
obj.dy = dy;
obj.dw = width/obj.ratio;
obj.dh = height/obj.ratio;
return obj;
},
getBlob: function()
{
var imageData = this.getDataURL();
var b64 = imageData.replace('data:image/png;base64,','');
var binary = atob(b64);
var array = [];
for (var i = 0; i < binary.length; i++) {
array.push(binary.charCodeAt(i));
}
return new Blob([new Uint8Array(array)], {type: 'image/png'});
},
zoomIn: function ()
{
this.ratio*=1.1;
setBackground();
},
zoomOut: function ()
{
this.ratio*=0.9;
setBackground();
}
},
setBackground = function()
{
var w = parseInt(obj.image.width)*obj.ratio;
var h = parseInt(obj.image.height)*obj.ratio;
var pw = (el.width() - w) / 2;
var ph = (el.height() - h) / 2;
el.css({
'background-image': 'url(' + obj.image.src + ')',
'background-size': w +'px ' + h + 'px',
'background-position': pw + 'px ' + ph + 'px',
'background-repeat': 'no-repeat'});
},
imgMouseDown = function(e)
{
e.stopImmediatePropagation();
obj.state.dragable = true;
obj.state.mouseX = e.clientX;
obj.state.mouseY = e.clientY;
},
imgMouseMove = function(e)
{
e.stopImmediatePropagation();
if (obj.state.dragable)
{
var x = e.clientX - obj.state.mouseX;
var y = e.clientY - obj.state.mouseY;
var bg = el.css('background-position').split(' ');
var bgX = x + parseInt(bg[0]);
var bgY = y + parseInt(bg[1]);
el.css('background-position', bgX +'px ' + bgY + 'px');
obj.state.mouseX = e.clientX;
obj.state.mouseY = e.clientY;
}
},
imgMouseUp = function(e)
{
e.stopImmediatePropagation();
obj.state.dragable = false;
},
zoomImage = function(e)
{
e.originalEvent.wheelDelta > 0 || e.originalEvent.detail < 0 ? obj.ratio*=1.1 : obj.ratio*=0.9;
setBackground();
}
obj.spinner.show();
obj.image.onload = function() {
obj.spinner.hide();
setBackground();
el.bind('mousedown', imgMouseDown);
el.bind('mousemove', imgMouseMove);
$(window).bind('mouseup', imgMouseUp);
el.bind('mousewheel DOMMouseScroll', zoomImage);
};
obj.image.src = options.imgSrc;
el.bind('remove', function(){$(window).unbind('mouseup', imgMouseUp)});
return obj;
};
jQuery.fn.cropbox = function(options){
return new cropbox(options, this);
};
}));