两种截取方式:
1:通过服务器进行截取。
2:使用canvas 画布进行本地的截取后上传服务器。
准备工作
下载jcorp插件
html页面代码
<div class="upload-head fr">
<p class="head-set-title">头像设置</p>
<div class="head-set-pic" style="width:140px;height:140px;overflow:hidden">
<img src="/static/images/head-set.jpg" id="picImg">
</div>
<p class="pdf-max">jpg,jpeg,png,BMP大小不超过5M</p>
<div class="upload-words"><span class="reletive-area"><input class="input-file" type="file" id="upload"><input type="hidden" name ="picture" id="picture"><a class="upload-btn" href="javascript:;">上传头像</a></span>
</div>
</div>
jcorp插件的使用
首先,在改变<input type="file">的src的时候触发事件
file为上传的图片,func为截取框点击确认的时候触发的方法
var changeHeadPic= function(file,func)
{
if (file.files && file.files[0])
{
var reader = new FileReader();
reader.readAsDataURL(file.files[0]);
reader.onload = function (e) {
//将弹框中显示的图片设置为上传的图片,进行显示
$('#cutimg').removeAttr('src');
$('#cutimg').attr('src', e.target.result);
//将头像显示的图片设置为上传的图片,进行显示
$('#picImg').removeAttr('src');
$('#picImg').attr('src', e.target.result);
//设置弹框中显示图片的高度为自动,宽度在样式中进行设置
$('#cutimg').css({
height:"auto"
});
//调用插件,进行截取
jcrop = $.Jcrop('#cutimg',{
//设置截取框的大小和起始位置setSelect: [ 50, 50, 140, 140 ],
allowSelect:false,
bgOpacity:0.6,
dragEdges:true,
//规定宽高比例为1 即为正方形aspectRatio: 1,
//移动截取框的事件onSelect: updateCoords,
onChange: updateCoords
});
};
if(jcrop != undefined)
{jcrop.destroy();
}
if(typeof(func) == "function")
{
$("#change-pic").data("confirmFunction",func);
}
//显示弹框$("#change-pic").show();
}
}
//移动截取框的事件
var updateCoords = function (c)
{
$('#x').val(c.x);
$('#y').val(c.y);
$('#w').val(c.w);
$('#h').val(c.h);
xsize = 140;
ysize = 140;
var rx = xsize / (c.w);
var ry = ysize / (c.h);
if(jcrop != undefined) {
var bounds = jcrop.getBounds();
boundx = bounds[0];
boundy = bounds[1];
}
if(boundx && boundy)
{
//设置移动截取框的时候,显示头像的变化此处是通过img外部包裹的div的样式进行的控制。
<div class="head-set-pic" style="width:140px;height:140px;overflow:hidden">
<img src="/static/images/head-set.jpg" id="picImg">
</div>
$('#picImg').css({
width: Math.round(rx * boundx) + 'px',
height: Math.round(ry * boundy) + 'px',
marginLeft: '-' + Math.round(rx * c.x) + 'px',
marginTop: '-' + Math.round(ry * c.y) + 'px'
});
}
};
以上工作准备完成,图片截取的准备工作完成,接下来进行点击确认进行真实的图片截取
1、上传至服务器进行截取
获取截取图片的x,y,w,h的值,并且上传显示的图片的img的宽高,进行截取,因为jcorp的截取框是选择img标签中的宽高
var uploadHead = function()
{
var y = $('#y').val();
var w = $('#w').val();
var h = $('#h').val();
var imgh = $("#cutimg").height();
var imgw = $("#cutimg").width();
var formData = new FormData();
formData.append('file', headerFile);
formData.append('x', x);
formData.append('y', y);
formData.append('w', w);
formData.append('h', h);
formData.append('imgh', imgh);
formData.append('imgw', imgw)
$.ajax({
url: "/upload/cut",
data: formData,
type: 'POST',
cache: false,
processData: false,
contentType: false
})
.done(function (data) {
console.log(data);
$("#picImg").attr("src",data);
$("#picImg").css({
width: '140px',
height: '140px',
marginLeft: '0px',
marginTop: '0px'
});
$("#picture").val(data);
})
.fail(function (res) {
console.log("upload is file");
});
}
服务器端代码
@RequestMapping("/cut")
@ResponseBody
public String upLoadCut(
HttpServletRequest request,
@RequestParam(value = "x") String x,
@RequestParam(value = "y") String y,
@RequestParam(value = "h") String h,
@RequestParam(value = "w") String w,
@RequestParam(value = "imgh") int imgh,
@RequestParam(value = "imgw") int imgw,
@RequestParam(value = "file") MultipartFile imageFile) throws IllegalStateException, IOException
{
String ckResult = null;
// 判断是否是multipart类型的请求。
if (request instanceof MultipartHttpServletRequest) {
//获取文件名称
String fileName = imageFile.getOriginalFilename();
//获取文件后缀
String suffix = fileName.substring(fileName.lastIndexOf(".")+1, fileName.length()).toLowerCase();
//上传路径
File dir = new File(remoteDir + remoteSubDir);
if(!dir.exists()){
dir.mkdirs();
}
//重命名文件名称
String saveName = UUID.randomUUID().toString()+"_src.jpg";
//设置上传路径以及名称
File file = new File(dir,saveName);
//将一个通道和另一个通道直接相连接
//设置上传文件与需要保存的文件通道相连
imageFile.transferTo(file);
String srcImagePath = remoteDir + remoteSubDir + saveName;
//设置截取大小
int imageX = Integer.parseInt(x);
int imageY = Integer.parseInt(y);
int imageH = Integer.parseInt(h);
int imageW = Integer.parseInt(w);
//截取并且上传图片返回文件读取路径
ckResult = uploadService.uploadImgCut(imgh,imgw,srcImagePath, suffix, imageX, imageY, imageH, imageW);
}
return ckResult;
}
/**
* 截取图片 返回文件
* @param srcImageFile 原图片地址
* @param srcImageName 原图片名称
* @param x 截取时的x坐标
* @param y 截取时的y坐标
* @param desWidth 截取的宽度
* @param desHeight 截取的高度
*/
public String uploadImgCut(int imgh, int imgw,String srcImagePath,String suffix, int x, int y, int desWidth,int desHeight){
try {
Image img;
ImageFilter cropFilter;
BufferedImage bi = ImageIO.read(new File(srcImagePath));
int srcWidth = imgw;
int srcHeight = imgh;
if (srcWidth >= desWidth && srcHeight >= desHeight) {
Image image = bi.getScaledInstance(srcWidth, srcHeight,Image.SCALE_DEFAULT);
cropFilter = new CropImageFilter(x, y, desWidth, desHeight);
img = Toolkit.getDefaultToolkit().createImage(
new FilteredImageSource(image.getSource(), cropFilter));
BufferedImage tag = new BufferedImage(desWidth, desHeight,
BufferedImage.TYPE_INT_RGB);
Graphics g = tag.getGraphics();
g.drawImage(img, 0, 0, null);
g.dispose();
//设置最新文件名称(截取之后的图片)
String tempName = UUID.randomUUID().toString();
File file = new File(remoteDir+Constants.FilePath.HEAD+tempName+"."+suffix);
//输出文件
ImageIO.write(tag, suffix, file);
//删除源文件
deleteFile(srcImagePath);
//返回文件读取路径
return remoteUrl+Constants.FilePath.HEAD+tempName+"."+suffix;
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
public void deleteFile(String sPath) {
File file = new File(sPath);
// 路径为文件且不为空则进行删除
if (file.isFile() && file.exists()) {
file.delete();
}
}
2、本地截取后上传服务器
//头像截取并且上传事件
var uploadHead = function()
{
var x = $('#x').val();
var y = $('#y').val();
var w = $('#w').val();
var h = $('#h').val();
var imgh = $("#cutimg").height();
var imgw = $("#cutimg").width();
//创建第一块画布,将图片真实宽高设置为cutimg元素的宽高,以方便进行截取
var canvas=$('<canvas ></canvas>')[0];
var ctx=canvas.getContext('2d');
var img = new Image();
img.src = $("#picImg").attr("src");
ctx.drawImage(img,0,0,imgw,imgh);
//创建第二块画布(需要上传至服务器的图片),进行截取
var canvas1 = $('<canvas width="140" height="140"></canvas>')[0];
var ctx1 = canvas1.getContext('2d');
var img1 = new Image();
img1.src = canvas.toDataURL("image/png");
ctx1.drawImage(img1,x,y,w,h,0,0,140,140);
//此处为测试代码,显示截取后的图片
// $("#aa").html(
// canvas1
// );
//以下代码执行上传
var data=canvas1.toDataURL();
// dataURL 的格式为 “data:image/png;base64,****”,逗号之前都是一些说明性的文字,我们只需要逗号之后的就行了
data=data.split(',')[1];
data=window.atob(data);
var ia = new Uint8Array(data.length);
for (var i = 0; i < data.length; i++) {
ia[i] = data.charCodeAt(i);
};
// canvas.toDataURL 返回的默认格式就是 image/png
var blob=new Blob([ia], {type:"image/png"});
//进行截取
var formData = new FormData();
formData.append('file', blob);
formData.append('subpath','head');
$.ajax({
url: "/upload/cut",
data: formData,
type: 'POST',
cache: false,
processData: false,
contentType: false
})
.done(function (data) {
console.log(data);
$("#picImg").attr("src",data);
$("#picImg").css({
width: '140px',
height: '140px',
marginLeft: '0px',
marginTop: '0px'
});
$("#picture").val(data);
})
.fail(function (res) {
console.log("upload is file");
});
}
服务器端代码
@RequestMapping("")
@ResponseBody
public String upLoad(HttpServletRequest request,
HttpServletResponse response,
@RequestParam(value = "file") MultipartFile multipartFile,
@RequestParam(value = "subpath") String subpath)
{
logger.debug("Enter method: upLoad()");
String ckResult = null;
// 判断是否是multipart类型的请求。
if (request instanceof MultipartHttpServletRequest) {
//转换为MultipartHttpServletRequest
// MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
//获取文件
// MultipartFile multipartFile = multipartRequest.getFile("file");
String fileName = multipartFile.getOriginalFilename();
String suffix = fileName.substring(fileName.lastIndexOf(".")+1, fileName.length()).toLowerCase();
//上传文件
try {
ckResult = uploadService.upload(multipartFile.getBytes(), suffix ,subpath);
} catch (IOException e) {
logger.error("Exit method: fileUpload().error the message is [" +e.getMessage()+ "]");
} catch (Exception e) {
logger.error("Exit method: fileUpload().error the message is [" +e.getMessage()+ "]");
}
}
logger.debug("Exit method: fileUpload().");
return ckResult;
}
@Override
public String upload(byte[] bytes, String suffix, String subpath) throws Exception {
log.debug("upload process begin...");
String path = "";
String tempName = UUID.randomUUID().toString();
String filePath ="";
//【重要】此处需要设置图片上传的路径以及显示的路径
log.debug("the file's raw path is [ "+filePath+" ]");
//上传文件
uploadFileToRemote(bytes, filePath);
log.debug("UPLOAD SUCCESS ! and the file's real internet path is [ "+path+" ]");
return path;
}
/**
* 根据传入的byte[]将文件上传到服务器的某个固定路径下
* @param bytes 文件字节流
* @param folderName 远程文件夹名称
* @param fileName 文件名
* @return 拼接的文件的网络路径
*/
public static void uploadFileToRemote(byte[] bytes,String filePath){
//检查文件夹是否存在
int index = filePath.lastIndexOf("/");
String folderName = filePath.substring(0,index+1);
File folder = new File(folderName);
if(!folder.exists()){
folder.mkdirs();
}
//输出文件
File destFile = new File(filePath);
OutputStream out = null;
try {
//检查文件是否存在
if(!destFile.exists()){
destFile.createNewFile();
}
//输出流
out = new FileOutputStream(destFile);
out.write(bytes);
out.flush();
} catch (Exception e) {
log.error("UPLOAD FAILURE ! ,the error is [ "+e+" ]");
}
finally{
//关闭流
try {
if(null != out){
out.close();
}
} catch (IOException e) {
log.error("UPLOAD FAILURE ! REASON: close outputStream failed the error is [ "+e+" ]");
}
}
}
此方法需要为什么要创建2个画布的原因(本人的理解)
jcorp插件并没有改变图片的真实大小,获取到截取的X,Y,W,H都是显示的img元素的大小,
如果不创建另外的画布,将图片的大小进行压缩,那么截取的图片就会使上传图片的原始大小,截取会出现错位,
所以需要将图片进行压缩到截取弹框中显示图片的img的大小。
点击上传头像按钮,显示如下
选择图片后,显示如下
移动截取框位置,显示如下
点击确认按钮,显示如下