头像截取上传并预览

时间:2022-08-29 08:24:24

本人使用的是jfinal+ajaxSubmit异步提交+jcrop截取,说下思路:点击上传图片并保存在服务器(原始图),然后初始化jcrop,并计算预览图。保存时提交截取的图片位置等信息后台在同比缩放之后截取保存即可。
一、页面

                    <div class="pic-wrap">
                        <a class="pass-portrait-filebtn"><i></i>选择您要上传的头像</a>
                        <form name="uploadForm" id="uploadForm" enctype="multipart/form-data" action="/personal/loadAvatar" method="post">
                            <input class="pass-portrait-file" id="originalAvatar" name="originalAvatar" type="file"/>
                        </form>
                        <form id="avatarForm" action="/personal/saveAvatar" method="post">
                            <input id="x" name="x" type="hidden" />
                            <input id="y" name="y" type="hidden" />
                            <input id="width" name="width" type="hidden" />
                            <input id="height" name="height" type="hidden" />
                            <input id="widgetSizeWidth" name="widgetSizeWidth" type="hidden" />
                            <input id="widgetSizeHeight" name="widgetSizeHeight" type="hidden" />
                            <input id="originalPath" name="originalPath" type="hidden" />
                        </form>
                    </div>
                    <div class="thumb-wrap">
                        <div class="thumb-preview pre-big">
                            <div class="thumb" id="currentAvatarBox">
                                <img class="split-thumb" id="currentAvatar" src="/ui/front/images/photo-big.png" onerror="this.src='/ui/front/images/photo-big.png'"/>
                            </div> 
                         </div> 

                        <div id="preview-pane" class="thumb-preview pre-sm">
                            <p>您上传的头像生成如下<br/>请注意是否清晰</p>
                            <div class="preview-container" id="smallAvatarBox">
                              <img class="jcrop-preview" id="smallAvatar" src="/ui/front/images/photo-small.png" onerror="this.src='/ui/front/images/photo-small.png'"/>
                            </div>
                            <p>头像尺寸:100*100像素</p>
                        </div>
                    </div>
                    <button class="disable-avatar" id="btnAjaxSubmit" disabled="disabled">保&nbsp;存</button>

二、js

 var g_oJCrop,boundx,boundy,widgetSizeWidth,widgetSizeHeight;
jQuery(function ($) {
    //切换头像
    $("#originalAvatar").change(function() {
        var upFile = $("#originalAvatar").val();
        if(upFile && !/(.*\.jpg$)|(.*\.jpeg$)|(.*\.png$)|(.*\.gif$)/i.test(upFile)){
            tipLayer('请检查文件格式');
            return ;
        }
        $("#uploadForm").ajaxSubmit({
            dataType: 'json',
            success:function(result,status){
                if(result.success){
                    if(g_oJCrop!=null) {
                        g_oJCrop.destroy();  
                    }
                    $("#currentAvatarBox").html("");
                    var box = '<img class="split-thumb" id="currentAvatar" src="/ui/front/images/photo-big.png" onerror="this.src=\'/ui/front/images/photo-big.png\'"/>';
                    $("#currentAvatarBox").append(box);
                    var url=result.path;
                    var originalPath=result.originalPath;
                    $("#currentAvatar").attr("src",imgPath+url);
                    $("#smallAvatar").attr("src",imgPath+url);
                    $("#originalPath").val(originalPath);

                    onShowPreview();
                    $("#btnAjaxSubmit").attr("class","submit-avatar");
                    $("#btnAjaxSubmit").removeAttr("disabled");
                }else{
                    tipLayer(result.msg);
                }
            },
            error: function(result,status,e){  
                tipLayer('文件上传出错');
            }
        });
        return false; 
    });
    // 上传头像
    $("#btnAjaxSubmit").click(function () {
        $("#avatarForm").ajaxSubmit({
            dataType: 'json',
            success:function(result,status){
                if(result.success){
                     var url=result.path;
                     $("#imgicon").attr("src",imgPath+url);
                    layer.open({
                      type: 1,
                      title :'提示',
                      area: '320px',
                      content: '<div><i></i><p class="safe-info">上传头像成功!</p></div>',
                      btn: ['确定'],
                      yes: function(index, layero){
                        //按钮【按钮一】的回调
                        layer.close(index); 
                        window.location.href="/personal/personalAvatar";
                      },btn2: function(index, layero){
                        //按钮【按钮二】的回调
                      },cancel: function(){ 
                        //右上角关闭回调
                        window.location.href="/personal/personalAvatar";
                      }
                });
                }else{
                    tipLayer(result.msg);
                }
            },
            error: function(result,status,e){  
                tipLayer("头像上传异常");
            }
        });
        return false; 
    });
});
//裁剪预览图片
function onShowPreview() {
   $('#currentAvatar').Jcrop({
        onChange: showPreview,
        onSelect: showPreview,
        allowSelect: false,
        boxWidth: 600,
        aspectRatio: 1 / 1,
        minSize: [94, 94]
    },function(){
        g_oJCrop = this;  
        var bounds = g_oJCrop.getBounds();
        var widgetSizes = g_oJCrop.getWidgetSize();
        widgetSizeWidth = widgetSizes[0];
        widgetSizeHeight = widgetSizes[1];
        boundx = bounds[0];
        boundy = bounds[1];
        var x1,y1,x2,y2;  
        if(bounds[0]/bounds[1] > 90/90)  
        {  
            y1 = 0;  
            y2 = bounds[1];  
            x1 = (bounds[0] - 90 * bounds[1]/90)/2;
            x2 = bounds[0]-x1;  
        }
        else  
        {  
            x1 = 0;  
            x2 = bounds[0];  
            y1 = (bounds[1] - 90 * bounds[0]/90)/2;
            y2 = bounds[1]-y1;  
        }
        g_oJCrop.setSelect([x1,y1,x2,y2]);  
   });
}
//事件处理
function showPreview(coords) {
    $("#x").val(coords.x);
    $("#y").val(coords.y);
    $("#width").val(coords.w);
    $("#height").val(coords.h);
    $("#widgetSizeWidth").val(widgetSizeWidth);
    $("#widgetSizeHeight").val(widgetSizeHeight);
    if (parseInt(coords.w) > 0) {
        //计算预览区域图片缩放的比例,通过计算显示区域的宽度(与高度)与剪裁的宽度(与高度)之比得到
        var rx = $("#smallAvatarBox").width() / coords.w;
        var ry = $("#smallAvatarBox").height() / coords.h;
        //通过比例值控制图片的样式与显示
        $("#smallAvatar").css({
            //预览图片宽度为计算比例值与原图片宽度的乘积
            width: Math.round(rx * boundx) + "px",
            //预览图片高度为计算比例值与原图片高度的乘积
            height: Math.round(rx * boundy) + "px",
            marginLeft: "-" + Math.round(rx * coords.x) + "px",
            marginTop: "-" + Math.round(ry * coords.y) + "px"
        });
    }
}
//提示
function tipLayer(message){
    layer.open({
          type: 1,
          title :'提示',
          area: '320px',
          content: '<div><i></i><p class="safe-info">'+ message +'!</p></div>',
          btn: ['确定'],
          yes: function(index, layero){
            //按钮【按钮一】的回调
            layer.close(index); 
          },btn2: function(index, layero){
            //按钮【按钮二】的回调
          },cancel: function(){ 
            //右上角关闭回调
          }
    });
}

这里说下我遇到的问题:
1、jcrop销毁的时候之前的图片还在,后来将图片的容器先删除再添加解决了。
2、jcrop的getBounds方法调用报错,后来发现是版本问题。
3、jcrop的调用可以看官方api;

三、后台

在处理头像的时候发现传过来的截取位置是jcrop缩放之后的位置,所以要先缩放再截取保存。

1.controller

    public void personalAvatar()
    {
        render("/front/personal/personal-myavatar.html");
    }

    public void loadAvatar()
    {
        try
        {
            UploadFile file = getFile("originalAvatar");// 上传并获取文件
            String originalPath = file.getFile().getPath().replace("\\","/");// 获取图片的原始路径
            String staticPath = String.valueOf(PropertiesPlugin.getParamMapValue(DictKeys.statics_res_path)).replace("\\","/");
            String path = originalPath.replace(staticPath, "");// 获取处理后图片的路径

            setAttr("path", path);
            setAttr("originalPath", originalPath);
            setAttr("success", true);
        }
        catch (Exception e)
        {
            setAttr("success", false);
            setAttr("msg", "上传失败,请重新上传!");
        }
        render(new JsonRender().forIE());
    }

    public void saveAvatar()
    {
        // 获取表单传来的数据
        int x = getParaToInt("x");
        int y = getParaToInt("y");
        int width = getParaToInt("width");
        int height = getParaToInt("height");
        int widgetSizeWidth = getParaToInt("widgetSizeWidth");
        int widgetSizeHeight = getParaToInt("widgetSizeHeight");
        String originalPath = getPara("originalPath");

        try
        {
            String resizePath = ImageUtil.getPath(".jpg");// 获取要缩放的目标图片路径
            String subpath = ImageUtil.getPath(".jpg");// 获取要截取的图片路径
            String staticPath = String.valueOf(PropertiesPlugin.getParamMapValue(DictKeys.statics_res_path)).replace("\\","/");
            String path = subpath.replace(staticPath, "");// 获取处理后图片的路径

            ImageUtil.resize(originalPath, resizePath, widgetSizeWidth, widgetSizeHeight);// 压缩图片并保存至目标图片路径
            ImageUtil.cut(resizePath, subpath, x, y, width, height);

            User user = ToolContext.getCurrentUser(getRequest(), true);
            if (user != null)
            {
                UserInfo userInfo = new UserInfo();
                userInfo.set("ids", user.getStr("userinfoids"));
                userInfo.set("titleimg", path);
                UserService.service.updateUserInfo(userInfo, user.getStr("ids"), getRequest());// 更新头像
                setAttr("path", path);
                setAttr("success", true);
                ImageUtil.delete(originalPath);
                ImageUtil.delete(resizePath);
            }
            else
            {
                setAttr("success", false);
                setAttr("msg", "保存失败,请重新上传!");
            }
        }
        catch (Exception e)
        {
            setAttr("success", false);
            setAttr("msg", "保存失败,请重新上传!");
        }
        render(new JsonRender().forIE());
    }

2、ImageUtil

    public static void resize(String sourcePath, String targetPath, int width, int height) throws IOException
    {
        FileOutputStream out = null;
        try
        {
            Image img = ImageIO.read(new File(sourcePath));// Image对象
            BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);// 生成缩略图片
            image.getGraphics().drawImage(img, 0, 0, width, height, null);// 绘制缩小后的图
            out = new FileOutputStream(new File(targetPath));// 输出到文件流 
            JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);  
            encoder.encode(image);
        }
        finally
        {
            if(out != null)
            {
                out.close();
            }
        }
    }

    public static void cut(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);

            /**//* * 返回包含所有当前已注册 ImageReader 的 Iterator,这些 ImageReader * 声称能够解码指定格式。 参数:formatName - 包含非正式格式名称 . *(例如 "jpeg" 或 "tiff")等 。 */
            String suffix = srcpath.substring(srcpath.lastIndexOf(".") + 1);
            String fromatName1  = JPG;
            if("gif".equals(suffix)){
                fromatName1 = GIF;
            }
            else if("jpg".equals(suffix))
            {
                fromatName1 = JPG;
            }
            else if("png".equals(suffix))
            {
                fromatName1 = PNG;
            }
            else if ("bmp".equals(suffix))
            {
                fromatName1 = BMP;
            }

            String suffix2 = subpath.substring(subpath.lastIndexOf(".") + 1);
            String formatName = JPG;
            if("gif".equals(suffix2))
            {
                formatName = GIF;
            }
            else if("jpg".equals(suffix2))
            {
                formatName = JPG;
            }
            else if("png".equals(suffix2))
            {
                formatName = PNG;
            }
            else if ("bmp".equals(suffix2))
            {
                formatName = BMP;
            }

            Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(fromatName1);
            ImageReader reader = it.next();

            //获取图片流
            iis = ImageIO.createImageInputStream(is);

            /**//* * <p>iis:读取源.true:只向前搜索 </p>.将它标记为 ‘只向前搜索’。 * 此设置意味着包含在输入源中的图像将只按顺序读取,可能允许 reader * 避免缓存包含与以前已经读取的图像关联的数据的那些输入部分。 */
            reader.setInput(iis,true) ;

            /**//* * <p>描述如何对流进行解码的类<p>.用于指定如何在输入时从 Java Image I/O * 框架的上下文中的流转换一幅图像或一组图像。用于特定图像格式的插件 * 将从其 ImageReader 实现的 getDefaultReadParam 方法中返回 * ImageReadParam 的实例。 */
            ImageReadParam param = reader.getDefaultReadParam();

            // 图片裁剪区域,Rectangle指定了坐标空间中的一个区域,通过 Rectangle对象的左上顶点的坐标(x,y),宽度和高度可以定义这个区域
            Rectangle rect = new Rectangle(x, y, width, height);

            //提供一个 BufferedImage,将其用作解码像素数据的目标
            param.setSourceRegion(rect);

            // 使用所提供的ImageReadParam读取通过索引imageIndex指定的对象,并将它作为一个完整的 BufferedImage返回
            BufferedImage bi = reader.read(0, param);

            // 保存新图片
            ImageIO.write(bi, formatName, new File(subpath));
        }
        finally
        {
            if(is!=null)
                is.close();
            if(iis!=null)
                iis.close();
        }
    }