jcrop为基于jquery库实现的图片裁切插件。当使用该插件使需要引入jquery和jcrop(包括js文件和css文件)。
//css文件的引入
<link rel="stylesheet" type="text/css" href="/Jcrop/css/jquery.Jcrop.min.css">
//js文件的引入
<script type="text/javascript" src="javascripts/jquery.js"></script>
<script type="text/javascript" src="/Jcrop/js/jquery.Jcrop.js"></script>
在项目中,需要实现当点击上传图片时,出现弹出框对上传的图片进行裁切,裁切完成后。点击提交按钮,改变用户的头像。
实现的过程如下:
- 点击上传图片按钮,触发ajax请求,将图片上传。上传成功后,触发ajax的回调函数,出现弹出框。
- 在弹出框中显示要上传的图片,并且将该图片作为jcrop的实例,对图像进行裁切,同时显示裁切图片的预览图
- 点击提交按钮,将jcrop的处理结果作为参数,提交请求。其中jcrop的参数包括相对于原图像的裁切的起点坐标以及裁切的宽度。
- 后台处理上传的图片和图片的裁切
前端代码如下
EventUtil.addHandler(userImgUpload, "change", function(e){
var e = EventUtil.getEvent(e);
//上传图片 当上传成功后 触发弹出框
var formd = new FormData();
formd.append("file",this.files[0]);
ajax("post","userSet/imgupload", null, formd, function(res){
var str = "<div class='img-wrap'><div class='upload-origin'><img id='upload-img' src="+JSON.parse(res).img+"></img></div><div class='pre-img'><span id='pre-big'><img id='crop-pre-big' src="
+JSON.parse(res).img+"></span><span id='pre-middle'><img id='crop-pre-middle' src="+JSON.parse(res).img+"></span><span id='pre-small'><img id='crop-pre-small' src="+JSON.parse(res).img+
"></span></div><input type='hidden' id='x' name='x' />"+
"<input type='hidden' id='y' name='y' />"+
"<input type='hidden' id='w' name='w' />"+
"<input type='hidden' id='h' name='h' />";
//Popular为弹出框类
var pop2 = document.querySelector('.p2');
var p2 = Popuper({
wrap: pop2,
type: 'success',
//confirm: uploadImg,
cancel: function() {
alert('cancel callback');
}
}).edit({
title: '头像上传',
content: str
}).show();
p2.toggle().edit({
type:'info'
});
//当图片加载完后增加jcrop类
$("#upload-img").on("load",function(){
console.log("cheng");
console.log($("#upload-img"));
var api = $.Jcrop("#upload-img",{
boxWidth:300,
boxHeight:300,
onChange:showPreview,
onSelect:showPreview,
aspectRatio:1
})
//初始化选区框的宽高为min(width,height)
api.setSelect([$("#upload-img").width()>$("#upload-img").height()?1/2*($("#upload-img").width()-$("#upload-img").height()):0,
$("#upload-img").width()>$("#upload-img").height()?0:1/2*($("#upload-img").height()-$("#upload-img").width()),
$("#upload-img").width()>$("#upload-img").height()?1/2*($("#upload-img").width()+$("#upload-img").height()):$("#upload-img").height(),
$("#upload-img").width()>$("#upload-img").height()?$("#upload-img").height():1/2*($("#upload-img").height()+$("#upload-img").width())]);
})
})
})
//当选区框改变时触发的操作
function showPreview(coords){
console.log(coords);//返回的是相对于原图像裁切的宽高信息
$("#x").val(coords.x);
$("#y").val(coords.y);
$("#w").val(coords.w);
$("#h").val(coords.h);
//预览图的生成 通过改变图片的宽高
if(parseInt(coords.w)>0){
var bigRx = $("#pre-big").width()/coords.w;
var bigRy = $("#pre-big").height()/coords.h;
console.log(bigRx)
$("#crop-pre-big").css({
width:Math.round(bigRx*$("#upload-img").width())+"px",
height:Math.round(bigRy*$("#upload-img").height())+"px",
marginLeft:"-"+Math.round(bigRx*coords.x)+"px",
marginTop:"-"+Math.round(bigRy*coords.y)+"px"
})
var middleRx = $("#pre-middle").width()/coords.w;
var middleRy = $("#pre-middle").height()/coords.h;
$("#crop-pre-middle").css({
width:Math.round(middleRx*$("#upload-img").width())+"px",
height:Math.round(middleRy*$("#upload-img").height())+"px",
marginLeft:"-"+Math.round(middleRx*coords.x)+"px",
marginTop:"-"+Math.round(middleRy*coords.y)+"px"
})
var smallRx = $("#pre-small").width()/coords.w;
var smallRy = $("#pre-small").height()/coords.h;
$("#crop-pre-small").css({
width:Math.round(smallRx*$("#upload-img").width())+"px",
height:Math.round(smallRy*$("#upload-img").height())+"px",
marginLeft:"-"+Math.round(smallRx*coords.x)+"px",
marginTop:"-"+Math.round(smallRy*coords.y)+"px"
})
}
}
$('#crop-form').submit(function(event) {
event.preventDefault()
});
//点击提交按钮时 将form表单以ajax方式提交
$("#upload-submit").on("click",function(e){
e.stopPropagation();
console.log("fjkdfajk");
$.ajax({
url:"/upload/imgupload/size",
type:"POST",
data:$("#crop-form").serialize(),
success:function(res){
console.log(res);
}
})
})
对于后端的处理,本文使用的是nodejs
首先是处理上传图片,这里使用的是multer包,上传代码如下:
app.post('/userset/imgupload',upload.single("file"),function(req,res){
//将信息存入文章数据库
var path = "/uploads/"+req.file.filename;
console.log("user");
console.log(req.session.user);
User.update({name: req.session.user.name},{img:path},function(err){
if(err){
console.log(err);
}
res.send({
img: path
})
})
})
当该后台代码执行完成后,触发ajax请求 对图片进行裁切
当裁切完成后,触发ajax请求,将裁切的尺寸和裁切的起点传给后台服务器 ,后台服务器需要裁切图片,这里需要引入imageMagick。imageMagick可以裁剪图片、重置图片大小以及添加水印等操作,具体使用方法请参照gm官方文档。在这里需要注意,引入该包之前需要在本地安装imageMagick。安装完之后在项目中引入imageMagick包,安装imageMagick包和gm包
npm install imageMagick
npm install gm
处理裁切的主要程序如下:
var fs = require('fs');
var gm = require('gm').subClass({imageMagick:true});
var path = require('path');
//param为json对象,包括图片的起始位置和图片裁切的宽度和高度
function ImgCrop(param,callback){
//新文件的路径
var imgdir = path.dirname(param.path);
var base = path.basename(param.path);
var filename = base.split('.')[0];
var newfile = filename + param.rWidth;
var newpath = path.join(imgdir,newfile+path.extname(param.path));
//crop:裁切 resize:重置尺寸 stream:将文件以流的形式读取
gm(path.join("./public", param.path))
.crop(param.width,param.height,param.x,param.y)
.resize(param.rWidth,param.rHeight)
.stream(function(err,stdout){
if(err){
throw err;
}
//将文件写入指定路径
var writeStream = fs.createWriteStream(path.join("./public", newpath));
stdout.pipe(writeStream)
//这里需要注意path.join连接后的路径以反斜杠分割,这里将反斜杠转化为斜杠
callback(null,newpath.replace(/\\/g,"\/"));
})
}
module.exports = ImgCrop;
当使用该模块时 需要引入该模块,并调用
var imgcrop = require('../models/imgcrop.js');
imgcrop({path:user.img,
width:req.body.w,
height:req.body.h,
x:req.body.x,
y:req.body.y,
rWidth:200,
rHeight:200
},function(err,newpath){
User.update({name: req.session.user.name},{bigimg:newpath},function(err){
if(err){
console.log(err);
}
res.send({
img: newpath
})
})
最后裁切时的截图截图如下