前端插件——头像截图上传插件的使用(带后台)
效果图:实现上传头像,右边是预览,有三个大小,可以对头像进行裁剪
HTML:
toParentData 和 img 返回的是图片裁剪后的base64编码。其中toParentData用于业务需求,可以忽略。
<!DOCTYPE html> <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %> <html> <head> <c:set var="BASE" value="${pageContext.request.contextPath}"/> <%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%> <meta charset="UTF-8"> <title>头像编辑上传</title> <link rel="stylesheet" href="${BASE}/www/css/userinfo/headImg_style.css" type="text/css" /> <!-- end --> <script>var BASE = "${BASE}";</script> </head> <body> <script type="text/javascript" src="${BASE}/www/js/jquery/jquery-1.11.1.min.js"></script> <script type="text/javascript" src="${BASE}/www/js/userinfo/headImg_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"> <!-- <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="-" > </div> <div class="cropped"></div> </div> <script type="text/javascript"> var toParentData =''; $(window).load(function() { var options = { thumbBox: '.thumbBox', spinner: '.spinner', imgSrc: '' } 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 = []; }) $('#btnCrop').on('click', function(){ var img = cropper.getDataURL(); toParentData = 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(); }) }); function getBase64(){ return toParentData; } </script> </body> </html>
CSS代码
@charset "utf-8"; .container { width: 400px; margin: 40px auto 0 auto; position: relative; font-family: 微软雅黑; font-size: 12px; } .container p { line-height: 12px; line-height: 0px; height: 0px; margin: 10px; color: #bbb } .action { width: 400px; height: 30px; margin: 10px 0; } .cropped { position: absolute; right: -230px; top: 0; width: 200px; border: 1px #ddd solid; height: 460px; padding: 4px; box-shadow: 0px 0px 12px #ddd; text-align: center; } .imageBox { position: relative; height: 400px; width: 400px; border: 1px solid #aaa; background: #fff; overflow: hidden; background-repeat: no-repeat; cursor: move; box-shadow: 4px 4px 12px #B0B0B0; } .imageBox .thumbBox { position: absolute; top: 50%; left: 50%; width: 200px; height: 200px; margin-top: -100px; margin-left: -100px; box-sizing: border-box; border: 1px solid rgb(102, 102, 102); box-shadow: 0 0 0 1000px rgba(0, 0, 0, 0.5); background: none repeat scroll 0% 0% transparent; } .imageBox .spinner { position: absolute; top: 0; left: 0; bottom: 0; right: 0; text-align: center; line-height: 400px; background: rgba(0,0,0,0.7); } .Btnsty_peyton{ float: right; width: 66px; display: inline-block; margin-bottom: 10px; height: 57px; line-height: 57px; font-size: 20px; color: #FFFFFF; margin:0px 2px; background-color: #f38e81; border-radius: 3px; text-decoration: none; cursor: pointer; box-shadow: 0px 0px 5px #B0B0B0; border: 0px #fff solid;} /*选择文件上传*/ .new-contentarea { width: 165px; overflow:hidden; margin: 0 auto; position:relative;float:left; } .new-contentarea label { width:100%; height:100%; display:block; } .new-contentarea input[type=file] { width:188px; height:60px; background:#333; margin: 0 auto; position:absolute; right:50%; margin-right:-94px; top:0; right/*\**/:0px\9; margin-right/*\**/:0px\9; width/*\**/:10px\9; opacity:0; filter:alpha(opacity=0); z-index:2; } a.upload-img{ width:165px; display: inline-block; margin-bottom: 10px; height:57px; line-height: 57px; font-size: 20px; color: #FFFFFF; background-color: #f38e81; border-radius: 3px; text-decoration:none; cursor:pointer; border: 0px #fff solid; box-shadow: 0px 0px 5px #B0B0B0; } a.upload-img:hover{ background-color: #ec7e70; } .tc{text-align:center;} /*www.jq22.com*/
JS代码
"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; }, 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.on('remove', function(){$(window).unbind('mouseup', imgMouseUp)}); return obj; }; jQuery.fn.cropbox = function(options){ return new cropbox(options, this); }; })); /*www.jq22.com*/
拿到base64编码之后,可以当成字符串传到后台。这里给出JAVA在后台解析base64并存储为文件的代码。
//头像上传 @ResponseBody @RequestMapping(value="/headImg/upload", method={RequestMethod.POST}) public Result headImgupload(@RequestParam("base64") String base64,HttpServletRequest request) { String username = shiroUtils.getUserName(); boolean success = true; try{ Log.debug("上传文件的数据:"+base64); String dataPrix = ""; String data = ""; Log.debug("对数据进行判断"); if(base64 == null || "".equals(base64)){ throw new Exception("上传失败,上传图片数据为空"); }else{ String [] d = base64.split("base64,"); if(d != null && d.length == 2){ dataPrix = d[0]; data = d[1]; }else{ throw new Exception("上传失败,数据不合法"); } } Log.debug("对数据进行解析,获取文件名和流数据"); String suffix = ""; if("data:image/jpeg;".equalsIgnoreCase(dataPrix)){//data:image/jpeg;base64,base64编码的jpeg图片数据 suffix = ".jpg"; } else if("data:image/x-icon;".equalsIgnoreCase(dataPrix)){//data:image/x-icon;base64,base64编码的icon图片数据 suffix = ".ico"; } else if("data:image/gif;".equalsIgnoreCase(dataPrix)){//data:image/gif;base64,base64编码的gif图片数据 suffix = ".gif"; } else if("data:image/png;".equalsIgnoreCase(dataPrix)){//data:image/png;base64,base64编码的png图片数据 suffix = ".png"; }else{ throw new Exception("上传图片格式不合法"); } String tempFileName = StringUtils.getRandom(6)+"_"+username+"_headImg"+suffix; Log.debug("生成文件名为:"+tempFileName); //因为BASE64Decoder的jar问题,此处使用spring框架提供的工具包 byte[] bs = Base64Utils.decodeFromString(data); try{ //使用apache提供的工具类操作流 FileUtils.writeByteArrayToFile(new File(request.getSession().getServletContext().getRealPath("")+Constant.HeadImg, tempFileName), bs); }catch(Exception ee){ throw new Exception("上传失败,写入文件失败,"+ee.getMessage()); } System.out.println(request.getSession().getServletContext().getRealPath("")+Constant.HeadImg+"--"+tempFileName); Log.debug("上传成功"); //更改用户头像信息 User user = new User(); user.setUserName(username); user.setHeadImg("/upload/headImg/"+tempFileName); userservice.editHeadImg(user); }catch (Exception e) { Log.debug("上传失败,"+e.getMessage()); success = false; } return new Result(success); }