基于jquery的imgAreaSelect.js插件+JAVA后台实现图片裁剪保存功能

来源:互联网 发布:腾讯视频for mac官方 编辑:程序博客网 时间:2024/05/19 20:22

前段时间,项目在做个人信息设置,其中有一项是设置用户头像信息,需要将用户选择的头像按照用户需要进行剪切,同时保存为大(120*120)、中(75*75)、小(35*35)三种格式的图像,分别显示到不同的位置。

需求很简单,就是这么easy,这个其中重点就是用户可以自己对选择的头像进行截取,最终选择了基于jquery的imgareaselect.js。既然插件都有了,那就开工吧!

第一步:
前端下载必须的js插件,后台使用java自带imageio包处理,不需要其他jar包。
jquery.imgareaselect-0.9.10.zip
jquery.js

第二步:
新建静态页面index.html (页面有点丑哈。。。)

<html lang="en"><head>    <meta charset="UTF-8">    <title>jquery.imgareaselect图像区域剪切</title>    <meta id="i18n_pagename" content="index-common">    <meta name="viewport" content="width=device-width">    <meta name="keywords" content="" />    <meta name="description" content=""/>    <link rel="stylesheet" href="css/imgareaselect-default.css">    <link rel="stylesheet" href="css/index.css"></head><body>    <div>        <input type="file" style="display: none" id="upImg" onchange="changeImg(this)">        <label for="upImg" id="preview">            <img id="imghead" src="images/normal.png" width="198" height="198" alt="头像">        </label>    </div>    <div class="boxFooter">        <input type="hidden" name="x1" value="0">        <input type="hidden" name="y1" value="0">        <input type="hidden" name="x2" value="100">        <input type="hidden" name="y2" value="100">         <button name="confirm" id="subPhoto" >确&nbsp;定</button>        <div id="imgmsg"></div>    </div>    <script src="js/jquery.js"></script>            <!-- 加载js文件 -->    <script src="js/jquery.imgareaselect.min.js"></script>    <script src="js/image.js"></script></body></html>

说明:该页面是模拟前端截取图像,并将起始位置坐标和图片base64编码发送给后端,后端进行处理。

第三步:
新建前端处理js文件image.js

$(document).ready(function () {   //提交图片剪切信息到后台  $("#subPhoto").click(function(){      var x1 = $("input[name='x1']").val();      var y1 = $("input[name='y1']").val();      var x2 = $("input[name='x2']").val();      var y2 = $("input[name='y2']").val();      var img64 = $("#imghead").attr("src");      alert(x1+":"+y1+":"+x2+":"+y2);      var url = "";      var param = {        'x1': x1,        'y1': y1,        'x2': x2,        'y2': y2,        'image': img64      }      $.post(url,param,function(data){        alert(data);      });  })}); //点击图像区域选择图片function changeImg(obj){  //图片选择处理  var file = obj;  var MAXWIDTH  = 198;   var MAXHEIGHT = 198;  var MAXSIZE = 2048*1024;  var div = document.getElementById('preview');  if (file.files && file.files[0]){    if (file.files[0].size > MAXSIZE) {      alert("more than " + (MAXSIZE/1024/1024) + "M");      return false;    };    div.innerHTML ='<img id=imghead>';    var img = document.getElementById('imghead');    img.onload = function(){       var rect = clacImgZoomParam(MAXWIDTH, MAXHEIGHT, img.offsetWidth, img.offsetHeight);       img.width  =  rect.width;       img.height =  rect.height;       img.style.marginTop = rect.top+'px';    }    var reader = new FileReader();    reader.onload = function(evt){      img.src = evt.target.result;    }    reader.readAsDataURL(file.files[0]);  }  //图片剪切区域处理  $('#imghead').imgAreaSelect({       x1:0,       y1:0,       x2:100,       y2:100,       aspectRatio: '1:1', //比例      handles: true,       onSelectChange: function(img, selection){//图片剪切区域变化时触发        $("#imgmsg").html("x1:"+selection.x1+", y1:"+selection.y1+", x2:"+selection.x2+", y2:"+selection.y2);      },       onSelectEnd: function (img, selection) {//图片剪切区域结束时触发        $('input[name="x1"]').val(selection.x1);        $('input[name="y1"]').val(selection.y1);        $('input[name="x2"]').val(selection.x2);        $('input[name="y2"]').val(selection.y2);     }  }); }//设置图片显示区域为固定大小,方便后台按统一比例截取图片function clacImgZoomParam( maxWidth, maxHeight, width, height ){   var param = {top:0, left:0, width:width, height:height};   if( width>maxWidth || height>maxHeight ){     rateWidth = width / maxWidth;     rateHeight = height / maxHeight;     if( rateWidth > rateHeight ){         param.width =  maxWidth;         param.height = Math.round(height / rateWidth);     }else {         param.width = Math.round(width / rateHeight);         param.height = maxHeight;     }   }   param.left = Math.round((maxWidth - param.width) / 2);   param.top = Math.round((maxHeight - param.height) / 2);   return param;}

说明:该js文件不难,大家都应该能看懂,调用imgAreaSelect.js的地方在$(‘#imghead’).imgAreaSelect({…})里面,这块也不难看懂,在 onSelectChange: function(img, selection){})这个地方图片剪切区域变化时触发,我们可以做一些其他的处理,比如预览截取部分的图像等等。clacImgZoomParam()方法主要是用于对用户选择的图像进行限定固定高度和宽度,方便后台按照统一的比例计算截取的坐标位置。

第四步:
后台接收并处理图片,后台是基于SpringMVC的,不熟悉的可以自学下下。
UserController.java

package com.gochina.tc.api;import javax.servlet.http.HttpServletResponse;import org.springframework.beans.factory.annotation.Autowired;import org.springframework.stereotype.Controller;import org.springframework.web.bind.annotation.RequestMapping;import org.springframework.web.bind.annotation.RequestMethod;import org.springframework.web.bind.annotation.RequestParam;import com.gochina.tc.po.ResultPo;import com.gochina.tc.service.UserService;/** * 用户信息处理 * @author hwy * */@Controller@RequestMapping(value = "/user")public class UserController {    @Autowired    private UserService userService;    @RequestMapping(value = "/uploadImage",method = RequestMethod.POST)    public ResultPo uploadUserImage(            @RequestParam(value = "image",required = true) String base64Code,            @RequestParam(value = "x1",required = true) int x1,            @RequestParam(value = "y1",required = true) int y1,            @RequestParam(value = "x2",required = true) int x2,            @RequestParam(value = "y2",required = true) int y2){        String result = userService.uploadUserImage(base64Code, x1, y1, x2, y2);        if(result.equals("")){            return new ResultPo(false, "上传用户图像失败");        }else{            return new ResultPo("success", result);        }    }}

UserService.java

package com.gochina.tc.service;/** * 用户信息处理service * @author hwy * */public interface UserService {    /**     * 上传并处理用户图片     */    public String uploadUserImage(String base64Code,int x1,int y1,int x2,int y2);}

UserServiceImpl.java

package com.gochina.tc.service.impl;import java.io.File;import java.text.SimpleDateFormat;import java.util.Date;import java.util.UUID;import org.springframework.stereotype.Service;import com.gochina.tc.util.ImageUtil;/** * 用户信息处理serviceImpl * @author hwy * */@Servicepublic class UserServiceImpl implements UserService {    /**     * 用户上传图片处理     */    public String uploadUserImage(String base64Code,int x1,int y1,int x2,int y2){        SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMdd");        String dateStr = sdf.format(new Date());        String path = "D:/user_image/" + dateStr + "/";        String url = "http://127.0.0.1:8080/user_image/" + dateStr + "/";        File f = new File(path);        if(!f.exists()){            f.mkdirs();        }        String fileName = UUID.randomUUID().toString().replaceAll("-", "")+".jpg";        String temp_fileName = path + "t_" + fileName;        String b_fileName = path + "b_" + fileName;        String m_fileName = path + "m_" + fileName;        String s_fileName = path + "s_" + fileName;        String result = "";        try{            //创建原始文件(先强制修改为jpg格式)            boolean isCreate = ImageUtil.base64ToImage(base64Code, path + fileName);            if(isCreate){                float scale = ImageUtil.getScaleCutImage(path + fileName);//比例                int width = (int) ((x2-x1)*scale);                int height = width;                int start_x = (int) (x1*scale);                int start_y = (int) (y1*scale);                //剪切图片                ImageUtil.cutImage(path + fileName, temp_fileName, start_x, start_y, width, height);                //剪切以后的图片压缩到固定大小的图片                ImageUtil.reduceImageByWidthHeight(temp_fileName, b_fileName, 200, 200);//200*200大图                ImageUtil.reduceImageByWidthHeight(temp_fileName, m_fileName, 120, 120);//120*120中图                ImageUtil.reduceImageByWidthHeight(temp_fileName, s_fileName, 70, 70);//70*70小图                result = url + fileName;            }        }catch(Exception e){            e.printStackTrace();        }        return result;    }}

说明:该文件处理流程大致为,1、创建原始文件,将base64编码转换成图片,并强制修改为jpg格式。2、获取图片的压缩比例,并计算剪切图片的长宽和起始坐标。3、按照要求剪切图片。4、将剪切以后的图片压缩到固定大小的图片。

ImageUtil.java

package com.gochina.tc.util;import java.awt.Color;import java.awt.Rectangle;import java.awt.image.BufferedImage;import java.io.File;import java.io.FileInputStream;import java.io.FileOutputStream;import java.io.IOException;import java.io.OutputStream;import java.util.Iterator;import javax.imageio.ImageIO;import javax.imageio.ImageReadParam;import javax.imageio.ImageReader;import javax.imageio.stream.ImageInputStream;import sun.misc.BASE64Decoder;import com.sun.image.codec.jpeg.JPEGCodec;import com.sun.image.codec.jpeg.JPEGEncodeParam;import com.sun.image.codec.jpeg.JPEGImageEncoder;/** * 上传的图片进行截取,压缩处理 * @author hwy * */public class ImageUtil {     /**     * 长高等比例缩小图片     * @param srcImagePath 读取图片路径     * @param toImagePath 写入图片路径     * @param ratio 缩小比例     * @throws IOException     */    public static void reduceImageByRatio(String srcImagePath,String toImagePath,float ratio) throws IOException{        FileOutputStream out = null;        try{            //读入文件              File file = new File(srcImagePath);              // 构造Image对象              BufferedImage src = javax.imageio.ImageIO.read(file);              int width = src.getWidth();              int height = src.getHeight();              // 缩小边长             BufferedImage tag = new BufferedImage((int)(width / ratio), (int)(height / ratio), BufferedImage.TYPE_INT_RGB);              // 绘制 缩小后的图片             tag.getGraphics().drawImage(src, 0, 0, (int)(width / ratio), (int)(height / ratio), null);              out = new FileOutputStream(toImagePath);              JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);             JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(tag);            param.setQuality(0.75f, true);// 默认0.75             encoder.setJPEGEncodeParam(param);            encoder.encode(tag);        }catch(Exception e){            e.printStackTrace();        }finally{            if(out != null){                out.close();              }            out = null;            System.gc();        }    }    /**     * 缩小图片到固定长高     * @param srcImagePath 读取图片路径     * @param toImagePath 写入图片路径     * @param width 缩小后图片宽度     * @param height 缩小后图片长度     * @throws IOException     */    public static void reduceImageByWidthHeight(String srcImagePath, String toImagePath, int width, int height) throws IOException{        FileOutputStream out = null;        try{            //读入文件              File file = new File(srcImagePath);              // 构造Image对象             BufferedImage src = javax.imageio.ImageIO.read(file);              // 缩小边长             BufferedImage tag = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);              // 绘制缩小后的图片             tag.getGraphics().drawImage(src, 0, 0, width, height, null);              out = new FileOutputStream(toImagePath);              JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);             JPEGEncodeParam param = encoder.getDefaultJPEGEncodeParam(tag);            param.setQuality(1f, true);// 默认0.75             encoder.setJPEGEncodeParam(param);            encoder.encode(tag);        }catch(Exception e){            e.printStackTrace();        }finally{            if(out != null){                out.close();              }            out = null;            System.gc();        }    }    /**     * 剪切图片     * @param srcpath     * @param subpath     * @param x     * @param y     * @param width     * @param height     * @throws IOException     */    public static void cutImage(String srcpath,String subpath,int x,int y,int width,int height) throws IOException {          FileInputStream is = null;          ImageInputStream iis = null;          try {              // 读取图片文件              is = new FileInputStream(srcpath);              Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName("jpg");              ImageReader reader = it.next();              // 获取图片流              iis = ImageIO.createImageInputStream(is);              reader.setInput(iis, true);              ImageReadParam param = reader.getDefaultReadParam();              // 图片裁剪区域。Rectangle 指定了坐标空间中的一个区域,通过 Rectangle 对象的左上顶点的坐标(x,y)、宽度和高度可以定义这个区域。             Rectangle rect = new Rectangle(x, y, width, height);              // 提供一个 BufferedImage,将其用作解码像素数据的目标。              param.setSourceRegion(rect);              BufferedImage bi = reader.read(0, param);              // 保存新图片              ImageIO.write(bi, "jpg", new File(subpath));          }finally {              if(is != null){                is.close();             }            if(iis != null){                  iis.close();            }        }      }      /**     * 获取图片缩放尺寸     * @param srcImagePath     * @return     * @throws IOException     */    public static float getScaleCutImage(String srcImagePath) throws IOException{        //读入文件          File file = new File(srcImagePath);          // 构造Image对象          BufferedImage src = javax.imageio.ImageIO.read(file);          int width = src.getWidth();          int height = src.getHeight();        float scale = 0f;        if(width >= height){            scale = (float)width/200;        }else if(width < height){            scale = (float)height/200;        }        return scale;    }    /**     * @Descriptionmap 对字节数组字符串进行Base64解码并生成图片     * @param base64 图片Base64数据     * @param path 图片路径     * @return     */    public static boolean base64ToImage(String base64, String path) {        // 图像数据为空        if(base64 == null){            return false;        }        if(base64.indexOf("base64") != -1){            base64 = base64.substring(base64.indexOf("base64")+7, base64.length());        }        // Base64解码        BASE64Decoder decoder = new BASE64Decoder();        try{            byte[] bytes = decoder.decodeBuffer(base64);            for(int i=0;i<bytes.length;i++){                // 调整异常数据                if(bytes[i] < 0){                    bytes[i] += 256;                }            }            // 生成jpeg图片            OutputStream out = new FileOutputStream(path);            out.write(bytes);            out.flush();            out.close();            //非jpg格式的图片强转为jpg            if(base64.indexOf("image/jpeg") == -1){                imageToJPG(path, path);            }            return true;        }catch(Exception e){            e.printStackTrace();            return false;        }    }    /**     * 将图片格式转成jpg的支持( GIF->JPG GIF->PNG PNG->GIF(X) PNG->JPG)     * @param src1     * @param result     * @throws IOException     */    public static void imageToJPG(String src1,String result) throws IOException{        File f = new File(src1);          f.canRead();          BufferedImage src = ImageIO.read(f);        ImageIO.write(src, "jpg", new File(result));    }}

说明:这个工具类注释写的比较详细,也不难看懂。有几个地方需要注意下:
1、imageToJPG()方法,将图片格式转成jpg的暂时只支持( GIF->JPG 、GIF->PNG 、PNG->GIF(X)、 PNG->JPG)这几种形式。
2、base64ToImage()方法,对字节数组字符串进行Base64解码并生成图片,里面前端传过来的数据串会带有类似data:image/png;base64,这段标示,我们需要将这部分截取掉才可以生成图片。
3、getScaleCutImage()方法,计算scale的时候,基数为200,这个要跟前端的图片显示区域保持一致,不然截取的图片就不正确了。
4、reduceImageByRatio()方法,长高等比例缩小图片中, param.setQuality(0.75f, true); 设置图片的质量,这个默认图像质量是0.75,如果想高质量保存,就设置为接近1即可,当然图片容量大小就会跟着变化了。

好了,大功即将告成!先来看下页面的效果如何吧!

这里写图片描述

当然这个效果比较low,不是很好看,仅仅是个demo而已,再来贴个项目线上的效果图吧,这个不low哦!

截取图

效果图

2 0
原创粉丝点击