js,angularjs 图片上传服务器,并解决照片旋转问题,前端图片压缩上传
2017-07-29 11:33
926 查看
手机网站 App 开发时遇到用户拍照上传的场景,照片的大小一般不低于2M ,用户网络不好时会导致上传的时候异常卡顿,因此考虑使用前端图片压缩,再上传服务器.
主要使用canvas来重新绘制前端图片,然后使用toDataURL方法拿到图片被压缩之后的的 Base64 编码数据,上传编码数据,后台解码还原成图片,并根据前端传递的图片旋转信息将图片做相应的旋转处理,废话不多说,直接上代码,虽然说的是 angularjs 的压缩图片上传,其实跟 angularjs 基本没有关系纯粹的 js 代码实现的图片重绘:
前端主要代码
在需要上传图片的地方调用uploadPic方法即可,file 传入 input.files[0] success 为上传成功之后的回调方法,fail 为上传失败之后的回调;
后端代码:
旋转图片的代码如下:
以上代码即可解决图片压缩上传,照片翻转的问题
如果想上传图片原图,并在后端做图片的选择操作,最好在后端直接读取图片,EXIF.js读取图片信息时非常慢,但由于图片重新绘制会丢失照片原有的旋转信息因此前端压缩时必须读取照片旋转角度以便后台修正,如果前端直接上传原图,可以在后台使用
来读取照片信息,并获取需要旋转的角度
主要代码如下:
不压缩直接上传的前端代码如下,参数的意义与之前压缩上传的一致
exif.js下载链接:http://pan.baidu.com/s/1jItDFMI 密码:m98m
主要使用canvas来重新绘制前端图片,然后使用toDataURL方法拿到图片被压缩之后的的 Base64 编码数据,上传编码数据,后台解码还原成图片,并根据前端传递的图片旋转信息将图片做相应的旋转处理,废话不多说,直接上代码,虽然说的是 angularjs 的压缩图片上传,其实跟 angularjs 基本没有关系纯粹的 js 代码实现的图片重绘:
前端主要代码
this.uploadPic = function(file, success, fail) { if (!/image\/\w+/.test(file.type)) { alert("image only please."); return false; } //EXIF为一个 js 读取图片参数工具类,可以用来读取照片被旋转的角度, //用作后端代码修正照片旋转, EXIF.getData(file,function() { //orient即读取到的照片旋转参数 orient = EXIF.getTag(this,'Orientation'); var rotate = 0; if (orient != null && orient != ""&& orient != 1) { switch (orient) { case 6:// 需要顺时针(向左)90度旋转 rotate = 90; break; case 8:// 需要逆时针(向右)90度旋转 rotate = 270; break; case 3:// 需要180度旋转 rotate = 180; break; } } //此处开始读取图片并使用canvas将读取到的信息重新绘制 var reader = new FileReader(); reader.readAsDataURL(file); reader.onload = function(e) { var img = new Image, width = 640, // image // resize quality = 0.8, // image // quality canvas = document.createElement("canvas"), drawer = canvas.getContext("2d"); img.src = this.result; img.onload = function() { canvas.width = width; canvas.height = width * (img.height / img.width); //开始绘制图片(压缩之后) drawer.drawImage(img, 0, 0,canvas.width,canvas.height); //获取压缩之后的 base64 编码的数据 bodyData = canvas.toDataURL("image/jpeg",quality); //上传图片的 base64 编码信息 $http.post("/common/upload-base64?rotate=" + rotate,bodyData) .success(function(data) { success(data); }) .error(function(data) { fail(data); }); } } }); }
在需要上传图片的地方调用uploadPic方法即可,file 传入 input.files[0] success 为上传成功之后的回调方法,fail 为上传失败之后的回调;
后端代码:
@RequestMapping(value = "/upload-base64", method = RequestMethod.POST) @ResponseBody public Map<String, Object> uploadFileBase64(HttpServletRequest request, HttpServletResponse response,@RequestBody String fileBase64, @RequestParam(required = false, value = "rotate", defaultValue = "0") int rotate) throws IOException { logger.info("开始上传base64格式的文件:"); long begin = System.currentTimeMillis(); //前端上传的数据的开始部分为文件标识信息,在解码之前需要去掉这部分信息 fileBase64 = fileBase64.replace("data:image/jpeg;base64,", ""); // Base64解码 byte[] bytes = Base64.decodeBase64(fileBase64); for (int i = 0; i < bytes.length; ++i) { if (bytes[i] < 0) {// 调整异常数据 bytes[i] += 256; } } String separator = "/"; String realServerPath = request.getSession().getServletContext() .getRealPath(separator); Date date = new Date(); String dateStr = new SimpleDateFormat("yyyyMMdd").format(date); String timeStr = new SimpleDateFormat("HHmmssSSS").format(date); // 存储的相对路径, 用于返回到页面 StringBuffer relativePath = new StringBuffer(); relativePath.append(this.uploadPath).append(separator).append(dateStr); StringBuffer uploadDir = new StringBuffer(); uploadDir.append(realServerPath).append(separator).append(relativePath); File dirPath = new File(uploadDir.toString()); if (!dirPath.exists()) { dirPath.mkdirs(); } StringBuffer savedFileName = new StringBuffer(); savedFileName.append(dateStr).append(timeStr) .append(new Random().nextInt()).append(".").append("jpg"); String realFilePath = uploadDir + separator + savedFileName; File uploadedFile = new File(realFilePath); //写入图片 FileCopyUtils.copy(bytes, uploadedFile); logger.info("上传base64文件成功:" + ",耗时:" + (System.currentTimeMillis() - begin) + "ms"); //校验是否需要对图片做旋转处理 if (ImageUtil.ANGLE_0 != rotate) { ImageUtil.rotatePhonePhoto(realFilePath, rotate); } Map<String, Object> map = new HashMap<>(); map.put("relativePath", relativePath + separator + savedFileName); return map; }
旋转图片的代码如下:
/** * 将图片旋转一定角度 * * @param fullPath * @param angel * @return */ public static String rotatePhonePhoto(String fullPath, int angel) { logger.info("旋转图片:" + fullPath + " 角度:" + angel); long begin = System.currentTimeMillis(); BufferedImage src; try { ImageIO.setUseCache(false); src = ImageIO.read(new File(fullPath)); int src_width = src.getWidth(null); int src_height = src.getHeight(null); Rectangle rect_des = calcRotatedSize(new Rectangle( new Dimension(src_width, src_height)), angel); BufferedImage res = new BufferedImage(rect_des.width, rect_des.height, BufferedImage.TYPE_INT_RGB); Graphics2D g2 = res.createGraphics(); g2.translate((rect_des.width - src_width) / 2, (rect_des.height - src_height) / 2); g2.rotate(Math.toRadians(angel), src_width / 2, src_height / 2); g2.drawImage(src, null, null); //注意此处使用 jpg 格式,如果使用其他格式编码会出现效率的诸多问题 ImageIO.write(res, "jpg", new File(fullPath)); } catch (IOException e) { logger.error("", e); } logger.info("旋转图片:" + fullPath + " 角度:" + angel + " 耗时:" + (System.currentTimeMillis() - begin) + "ms"); return fullPath; } /** * 计算新照片的大小 * * @param src * @param angel * @return */ public static Rectangle calcRotatedSize(Rectangle src, int angel) { // if angel is greater than 90 degree, we need to do some conversion if (angel >= 90) { if (((angel / 90) % 2) == 1) { int temp = src.height; src.height = src.width; src.width = temp; } angel = angel % 90; } double r = Math.sqrt((src.height * src.height) + (src.width * src.width)) / 2; double len = 2 * Math.sin(Math.toRadians(angel) / 2) * r; double angel_alpha = (Math.PI - Math.toRadians(angel)) / 2; double angel_dalta_width = Math.atan((double) src.height / src.width); double angel_dalta_height = Math.atan((double) src.width / src.height); int len_dalta_width = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_width)); int len_dalta_height = (int) (len * Math.cos(Math.PI - angel_alpha - angel_dalta_height)); int des_width = src.width + (len_dalta_width * 2); int des_height = src.height + (len_dalta_height * 2); return new Rectangle(new Dimension(des_width, des_height)); }
以上代码即可解决图片压缩上传,照片翻转的问题
如果想上传图片原图,并在后端做图片的选择操作,最好在后端直接读取图片,EXIF.js读取图片信息时非常慢,但由于图片重新绘制会丢失照片原有的旋转信息因此前端压缩时必须读取照片旋转角度以便后台修正,如果前端直接上传原图,可以在后台使用
<dependency> <groupId>com.drewnoakes</groupId> <artifactId>metadata-extractor</artifactId> <version>2.10.1</version> </dependency>
来读取照片信息,并获取需要旋转的角度
主要代码如下:
/** * 获取图片的旋转角度 * * @param filePath * @return 图片旋转角度 */ public static int getRotateAngleForPhoto(String filePath) { File file = new File(filePath); int angle = ANGLE_0; Metadata metadata; try { metadata = JpegMetadataReader.readMetadata(file); Directory directory = metadata .getFirstDirectoryOfType(ExifIFD0Directory.class); if ((null != directory) && directory.containsTag( ExifIFD0Directory.TAG_ORIENTATION)) { // Exif信息中方向 int orientation = directory.getInt( ExifIFD0Directory.TAG_ORIENTATION); // 原图片的方向信息 if (6 == orientation) { // 6旋转90 angle = ANGLE_90; } else if (3 == orientation) { // 3旋转180 angle = ANGLE_180; } else if (8 == orientation) { // 8旋转90 angle = ANGLE_270; } } } catch (JpegProcessingException e) { logger.error("", e); } catch (MetadataException e) { logger.error("", e); } catch (IOException e) { logger.error("", e); } return angle; }
不压缩直接上传的前端代码如下,参数的意义与之前压缩上传的一致
this.uploadPicNotCompress = function(file, success, fail) { if (!/image\/\w+/.test(file.type)) { alert("image only please."); return false; } var formdata = new FormData(); // 初始化一个FormData实例 formdata.append('file', file); // file就是图片或者其他你要上传的formdata $http.post("common/upload", formdata, { transformRequest : angular.identity, headers : { 'Content-Type' : undefined }}) .success(function(data) { success(data); }) .error(function(data) { fail(data); }); }
exif.js下载链接:http://pan.baidu.com/s/1jItDFMI 密码:m98m
相关文章推荐
- 前端input图片的上传和压缩以及图片旋转90度问题解决
- JS前端上传图片、压缩、并且处理旋转问题,生成base64数据
- JS前端上传图片、压缩、并且处理旋转问题,生成base64数据
- 利用exif.js解决ios手机上传竖拍照片旋转90度问题
- 前端把图片转为base64,解决手机上传图片自动旋转的问题
- 利用exif.js解决ios或Android手机上传竖拍照片旋转90度问题
- vue2实现移动端上传、预览、压缩图片解决拍照旋转问题
- vue2移动端上传,预览,压缩图片,解决拍照旋转问题
- 利用exif.js解决ios手机上传竖拍照片旋转90度问题
- 解决图片上传到服务器旋转90度的问题(图片倒置)
- 利用exif.js解决ios手机上传竖拍照片旋转90度问题
- 利用exif.js解决ios手机上传竖拍照片旋转90度问题
- 详解利用exif.js解决ios手机上传竖拍照片旋转90度问题
- 利用exif.js插件解决ios手机上传竖拍照片旋转90度问题
- 利用exif.js解决ios手机上传竖拍照片旋转90度问题
- 利用exif.js解决ios手机上传竖拍照片旋转90度问题
- vue2移动端上传,预览,压缩图片,解决拍照旋转问题
- vue2移动端上传,预览,压缩图片,解决拍照旋转问题
- js图片前端压缩多图上传(旋转其实已经好了只是手机端有问题要先压缩再旋转)
- 解决:百度编辑器UEditor,怎么将图片保存到图片服务器,或者上传到ftp服务器的问题(如果你正在用UE,这篇文章值得你看下)