用CropBox实现用户头像裁剪上传与Java后台交互
2017-11-21 15:53
417 查看
参考网站:https://developer.mozilla.org/zh-CN/docs/Web/API/Blob
参考:
http://blog.csdn.net/u013160024/article/details/51849732
http://www.cnblogs.com/shinefon-2-2/p/5901330.html
http://www.cnblogs.com/hhhyaaon/p/5928152.html
主流的前端jQuery 图像裁剪插件有Jcrop和CropBox,前者是将原图和需要裁剪的参数(裁剪的各点坐标,旋转角度等)传到后台,然后由后台完成实际的裁剪和后续操作。
CropBox实现功能相对较少,但操作更简单,它的原理是:
将裁减后的图片通过base64编码,然后转化为blob格式发送到服务器,服务器完成解码即可,官网介绍可以看github上的说明和Demo
核心js函数只有两个:
getDataURL 将裁剪后的图片简单以base64编码后的结果,用于实时预览,当然也可以将它直接传到服务器,然后解码为png格式
getBlob 上传图片为Blob格式
首先贴出两个函数的源码:
下面贴出主要代码:
视图层
index.html
实现头像裁剪,上传,预览,
这里利用了jQuery.ajax()函数,不懂得去复习下吧
官网
我的博客里也有简要介绍:http://www.cnblogs.com/xzwblog/p/6915213.html#_label5
cropbox用法:
github上的说明和Demo
image.html
从后台获得byte[]格式的字节流,然后展示经过后台处理后的效果:
控制层
service层
图片处理工具类
分析
利用Fiddler我们简要分析一下http的请求与回应。
如下图所示,当我们点击了提交按钮
。。。。。详情请参考:
https://www.cnblogs.com/xzwblog/p/6912320.html
参考:
http://blog.csdn.net/u013160024/article/details/51849732
http://www.cnblogs.com/shinefon-2-2/p/5901330.html
http://www.cnblogs.com/hhhyaaon/p/5928152.html
主流的前端jQuery 图像裁剪插件有Jcrop和CropBox,前者是将原图和需要裁剪的参数(裁剪的各点坐标,旋转角度等)传到后台,然后由后台完成实际的裁剪和后续操作。
CropBox实现功能相对较少,但操作更简单,它的原理是:
将裁减后的图片通过base64编码,然后转化为blob格式发送到服务器,服务器完成解码即可,官网介绍可以看github上的说明和Demo
核心js函数只有两个:
getDataURL 将裁剪后的图片简单以base64编码后的结果,用于实时预览,当然也可以将它直接传到服务器,然后解码为png格式
getBlob 上传图片为Blob格式
首先贴出两个函数的源码:
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; }, 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'}); },
下面贴出主要代码:
视图层
index.html
实现头像裁剪,上传,预览,
这里利用了jQuery.ajax()函数,不懂得去复习下吧
官网
我的博客里也有简要介绍:http://www.cnblogs.com/xzwblog/p/6915213.html#_label5
cropbox用法:
github上的说明和Demo
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>CropBox头像裁剪,上传,回显</title> <link rel="stylesheet" href="/css/style.css" type="text/css" /> </head> <body> <script type="text/javascript" src="/js/jquery-1.11.1.min.js"></script> <script type="text/javascript" src="/js/cropbox.js"></script> <div class="container"> <div class="imageBox"> <div class="thumbBox"></div> <div class="spinner" style="display: none">Loading...</div> </div> <div class="action"> 4000 <!-- <input type="file" id="file" style=" width: 200px">--> <div class="new-contentarea tc"><a href="javascript:void(0)" class="upload-img"> <label for="upload-file">上传图像</label> </a> <input type="file" class="" name="upload-file" id="upload-file"/> </div> <input type="button" id="btnCrop" class="Btnsty_peyton" value="裁切"> <input type="button" id="btnZoomIn" class="Btnsty_peyton" value="+"> <input type="button" id="btnZoomOut" class="Btnsty_peyton" value="-"> <input type="button" id="blobSubmit" class="Btnsty_peyton" value="提交"> </div> <div class="cropped"></div> </div> <script type="text/javascript"> $(window).load(function() { var options = { thumbBox: '.thumbBox', spinner: '.spinner', imgSrc: 'images/avatar.png' } var cropper = $('.imageBox').cropbox(options); $('#upload-file').on('change', function(){ var reader = new FileReader(); reader.onload = function(e) { options.imgSrc = e.target.result; cropper = $('.imageBox').cropbox(options); } reader.readAsDataURL(this.files[0]); this.files = []; }) $('#blobSubmit').on('click', function(){ var img = cropper.getBlob(); var formdata = new FormData(); formdata.append("imagefile", img); $.ajax({ url:"/file/updateHeadPicture.action", data: formdata, type:"post", //默认值: true。默认情况下,通过data选项传递进来的数据,如果是一个对象(技术上讲只要不是字符串), // 都会处理转化成一个查询字符串,以配合默认内容类型 "application/x-www-form-urlencoded"。如果要发送 DOM 树信息或其它不希望转换的信息,请设置为 false。 processData: false, contentType: false, success: function(oResult) { if(oResult.success==1){ window.location.href="/image"; }else{ alert(oResult.message); } } }) }) $('#btnCrop').on('click', function(){ var img = cropper.getDataURL(); $('.cropped').html(''); $('.cropped').append('<img src="'+img+'" align="absmiddle" style="width:64px;margin-top:4px;border-radius:64px;box-shadow:0px 0px 12px #7E7E7E;" ><p>64px*64px</p>'); $('.cropped').append('<img src="'+img+'" align="absmiddle" style="width:128px;margin-top:4px;border-radius:128px;box-shadow:0px 0px 12px #7E7E7E;"><p>128px*128px</p>'); $('.cropped').append('<img src="'+img+'" align="absmiddle" style="width:180px;margin-top:4px;border-radius:180px;box-shadow:0px 0px 12px #7E7E7E;"><p>180px*180px</p>'); }) $('#btnZoomIn').on('click', function(){ cropper.zoomIn(); }) $('#btnZoomOut').on('click', function(){ cropper.zoomOut(); }) }); </script> </div> </body> </html>
image.html
从后台获得byte[]格式的字节流,然后展示经过后台处理后的效果:
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> <html xmlns="http://www.w3.org/1999/xhtml"> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf-8" /> <title>头像展示</title> </head> <body> <div id="forAppend" class="demo"></div> <img src="/image/xie" alt=""/> ##单位是像素,并且是按照长和宽中较小的值来确定等比例缩放的比例 <img src="/image/xie/300/100" alt=""/> </body> </html>
控制层
package com.cropbox.demo.uploadHead.controller; import com.alibaba.fastjson.JSON; import com.cropbox.demo.uploadHead.mapper.UserMapper; import com.cropbox.demo.uploadHead.model.UploadPictureResponse; import com.cropbox.demo.uploadHead.model.User; import com.cropbox.demo.uploadHead.service.UploadService; import com.cropbox.demo.uploadHead.utils.ImageUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RequestMethod; import org.springframework.web.bind.annotation.RequestParam; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.*; /** * getBlob:上传图片为Blob格式,并保存到mysql的blob字段中, * 其实File继承了Blob,所以表单中的图片处理方式与之类似, * 实现头像的裁剪,保存到服务器,并在需要时回显到客户端 * * @author xie * @version 1.0 * @Date 2017/5/26 */ @Controller public class FileController { @Autowired UploadService uploadService; @Autowired UserMapper userMapper; @Autowired ImageUtils imageUtils; /** * 主页 * @return */ @RequestMapping(path = {"/"}, method = {RequestMethod.GET, RequestMethod.POST}) public String index() { return "index"; } /** * 实现图片上传 * @param file * @param response */ @RequestMapping(path = {"/file/updateHeadPicture.action"}, method = {RequestMethod.GET, RequestMethod.POST}) public void index(@RequestParam("imagefile") MultipartFile file, HttpServletResponse response) { try { UploadPictureResponse uploadPictureResponse = uploadService.updateHeadPicture(file); /* 设置编码格式,返回结果json结果,注意其中的对象转化为json字符串格式为: {"message":"上传图片成功!","success":1,"url":"C:\\\\home\\\\myblog\\\\pic\\\\2f1b63bc4b654a27a7e0c1b1a0fb9270.png"} 所以前端可以直接读取success,message等信息 */ response.setContentType( "application/json;charset=UTF-8"); response.getWriter().write( JSON.toJSONString(uploadPictureResponse)); } catch (IOException e1) { e1.printStackTrace(); } } @RequestMapping(path= {"/image"}, method = {RequestMethod.GET, RequestMethod.POST}) public String index1() { return "image"; } /** * 按照用户名查找头像 * @param username * @param response */ @RequestMapping(path = {"/image/{username}"}, method = {RequestMethod.GET, RequestMethod.POST}) public void index1(@PathVariable("username") String username, HttpServletResponse response) { User user = userMapper.selectByUsername(username); try { //写到输出流 response.setContentType("image/png"); response.setCharacterEncoding("UTF-8"); //BufferedOutputStream 是缓冲输出流,默认新建字节数组大小为8192的“缓冲输出流” OutputStream outputStream = new BufferedOutputStream(response.getOutputStream()); outputStream.write(user.getHead()); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } /** * 按照用户名查找头像,并提供缩放功能 * @param username 用户名 * @param width 要求图片的宽度 * @param height 要求图片的高度 * @param response */ @RequestMapping(path = "/image/{username}/{width}/{height}") public void getPhotoById(@PathVariable("username") String username, @PathVariable("width") int width, @PathVariable("height") int height, HttpServletResponse response) { User user = userMapper.selectByUsername(username); byte[] data = user.getHead(); try { if (width > 0 && height > 0) { data = imageUtils.scaleImage(data, width, height); } response.setContentType("image/png"); response.setCharacterEncoding("UTF-8"); OutputStream outputStream = new BufferedOutputStream(response.getOutputStream()); outputStream.write(data); outputStream.flush(); outputStream.close(); } catch (IOException e) { e.printStackTrace(); } } }
service层
package com.cropbox.demo.uploadHead.service; import com.cropbox.demo.uploadHead.mapper.UserMapper; import com.cropbox.demo.uploadHead.model.UploadPictureResponse; import com.cropbox.demo.uploadHead.utils.ImageUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.util.FileCopyUtils; import org.springframework.web.multipart.MultipartFile; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.nio.file.Files; import java.nio.file.StandardCopyOption; import java.util.UUID; /** * 类的详细说明 * * @author xie * @version 1.0 * @Date 2017/5/27 */ @Service public class UploadService { @Autowired ImageUtils imageUtils; @Autowired UserMapper userMapper; /** * 上传的头像统一都转换为了png格式,故不进行是否允许类型判断 * @param file * @return * @throws IOException */ public UploadPictureResponse updateHeadPicture(MultipartFile file) throws IOException { UploadPictureResponse uploadPictureResponse = new UploadPictureResponse(); try { InputStream is = file.getInputStream(); byte[] bytes = FileCopyUtils.copyToByteArray(is); //更新数据库中的blob格式的head字段,返回1表示更新成功,返回0表示失败 int success = userMapper.updateHead(1,bytes); //上面已经将输入流中的数据全部读完,故重新初始化 is = file.getInputStream(); //同时将图片保存到C:\\home\\myblog\\pic\\ 路径下,这里保存到文件夹只是演示作用,请根据需求决定将图片保存到数据库还是服务器文件夹 String fileName = UUID.randomUUID().toString().replaceAll("-", "") + ".png" ; Files.copy(is, new File(imageUtils.getPictureDir() + fileName).toPath(), StandardCopyOption.REPLACE_EXISTING); uploadPictureResponse.setSuccess(success); uploadPictureResponse.setMessage("上传图片成功!"); uploadPictureResponse.setUrl(imageUtils.getPictureDir() + fileName); is.close(); return uploadPictureResponse; } catch (Exception e) { // 请求失败时打印的异常的信息 uploadPictureResponse.setSuccess(0); uploadPictureResponse.setMessage("服务器异常!"); return uploadPictureResponse; } } }
图片处理工具类
package com.cropbox.demo.uploadHead.utils; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import javax.imageio.ImageIO; import java.awt.image.BufferedImage; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.IOException; /** * 图片处理服务 * * @author xie * @version 1.0 * @Date 2017/5/27 */ @Service public class ImageUtils { /** 头像图片的放置路径*/ @Value("${headPath.home}") private String PictureDir; /** 允许的图片类型头像图片,这里分别使用属性占位符和SpEL表达式,可以实现更复杂的功能,运行时计算值*/ @Value("${pictureLimit.suffix}") private String PictureFileSuffix; /** 判断上传图片格式是否被允许 */ public boolean isFileAllowed(String fileSuffix) { for (String suffix : PictureFileSuffix.split(",")) { if (suffix.equals(fileSuffix)) { return true; } } return false; } /** * 获得图片存储路径 * @return */ public String getPictureDir(){ return PictureDir; } /** * 获得系统允许上传图片后缀 * @return */ public String getPictureFileSuffix(){ return PictureFileSuffix; } /** * 等比例缩放图片,按照长和宽中较小的数来确定缩放比例,所有单位为像素, * 在传输中,图片是不能直接传的,因此需要把图片变为字节数组,然后传输比较方便;只需要一般输出流的write方法即可;而字节数组变成BufferedImage能够还原图像; * * @param data 图片的byte[]格式 * @param width 缩放后的宽度 * @param height 缩放后的高度 * @return 图片缩放后的byte[]格式 * @throws IOException */ public byte[] scaleImage(byte[] data, int width, int height) throws IOException { ////从特定文件载入 BufferedImage oldImage = ImageIO.read(new ByteArrayInputStream(data)); int imageOldWidth = oldImage.getWidth(); int imageOldHeight = oldImage.getHeight(); double scale_x = (double) width / imageOldWidth; double scale_y = (double) height / imageOldHeight; double scale_xy = Math.min(scale_x, scale_y); int imageNewWidth = (int) (imageOldWidth * scale_xy); int imageNewHeight = (int) (imageOldHeight * scale_xy); //创建一个不带透明色的BufferedImage对象 BufferedImage newImage = new BufferedImage(imageNewWidth, imageNewHeight, BufferedImage.TYPE_INT_RGB); /*BufferedImage与Image之间的相互转换,其中 * oldImage.getScaledInstance(imageNewWidth, imageNewHeight, BufferedImage.SCALE_SMOOTH)表示缩放图像 * BufferedImage.SCALE_SMOOTH表示压缩图片所用的算法,本算法生成缩略图片的平滑度的优先级比速度高,生成的图片质量比较好,但速度慢 * */ newImage.getGraphics().drawImage(oldImage.getScaledInstance(imageNewWidth, imageNewHeight, BufferedImage.SCALE_SMOOTH), 0, 0, null); /* 释放绘图上下文所占的系统资源 */ newImage.getGraphics().dispose(); ByteArrayOutputStream outPutStream = new ByteArrayOutputStream(); /*BufferedImage ---->byte[], 参数newImage表示获得的BufferedImage; 参数format表示图片的格式,比如“gif”等; 参数out表示输出流,如果要转成Byte数组,则输出流为ByteArrayOutputStream即可; 执行完后,只需要toByteArray()就能得到byte[]; */ ImageIO.write(newImage, "jpg", outPutStream); oldImage.flush(); outPutStream.flush(); outPutStream.close(); return outPutStream.toByteArray(); } }
分析
利用Fiddler我们简要分析一下http的请求与回应。
如下图所示,当我们点击了提交按钮
。。。。。详情请参考:
https://www.cnblogs.com/xzwblog/p/6912320.html
相关文章推荐
- 如何用CropBox实现头像裁剪并与java后台交互
- java后台加安卓端实现头像上传功能
- 选取图片裁剪并上传功能的实现(后台java实现)
- jquery.Jcrop结合JAVA后台实现图片裁剪上传实例
- laravel博客开发之利用jcorp结合laravel和ajaxupload实现用户头像上传和裁剪功能
- js+java实现的头像上传和裁剪,完美兼容各种浏览器
- ASP.NET简单实现APP中用户个人头像上传和裁剪
- java读取图片处理实现缩放裁剪,用于个人信息中上传图片自定义头像大小
- jQuery实现用户头像裁剪插件cropbox.js
- ASP.NET简单实现APP中用户个人头像上传和裁剪
- java通过nginx+apache tomcat接收用户头像图片上传,实现网站动态和静态域名访问图片的详细教程
- JAVA + js 实现 头像上传及裁剪功能
- WEB前端 和 JAVA后台 关于头像上传功能实现中出现的ajax 404问题经验
- plupload 上传组件,后台用java实现
- jQuery Jcrop 结合后台java实现图像裁剪切图案例
- Android 设置用户头像 -》拍照/相册选择+裁剪 实现
- Easyui Datagrid 如何实现后台交互显示用户数据列表
- PHP Uploadify+jQuery.imgAreaSelect插件+AJAX 实现图片上传裁剪 仿微博头像上传功能
- android 用户头像,图片裁剪,上传并附带用户数据base64code 方式
- 小议头像预览裁剪上传的实现