我是靠谱客的博主 单薄大米,最近开发中收集的这篇文章主要介绍Java 利用jquery库cropper完成图片裁剪功能,觉得挺不错的,现在分享给大家,希望可以做个参考。

概述

功能描述:点击用户头像,弹出一个图片裁剪的modal,提交后,java后端保存裁剪后的图片,然后返回该图片url给前端显示。Cropper官网及下载
Cropper依赖于jquery、bootstrap。

1.Java核心图片裁剪工具类 ImageCut.java

package com.jykj.demo.util;

import java.io.*;  
import java.awt.*;  
import java.awt.image.*;  
import java.awt.Graphics;  
import java.awt.color.ColorSpace;  
import javax.imageio.ImageIO;  

public class ImageCut {  

    /**  
     * 图像切割(改)     *  
     * @param srcImageFile            源图像地址 
     * @param dirImageFile            新图像地址 
     * @param x                       目标切片起点x坐标 
     * @param y                      目标切片起点y坐标 
     * @param destWidth              目标切片宽度 
     * @param destHeight             目标切片高度 
     */  
    public static void abscut(String srcImageFile,String dirImageFile, int x, int y, int destWidth,  
            int destHeight) {  
        try {  
            Image img;  
            ImageFilter cropFilter;  
            // 读取源图像  
            BufferedImage bi = ImageIO.read(new File(srcImageFile));  
            int srcWidth = bi.getWidth(); // 源图宽度  
            int srcHeight = bi.getHeight(); // 源图高度            
            if (srcWidth >= destWidth && srcHeight >= destHeight) {  
                Image image = bi.getScaledInstance(srcWidth, srcHeight,  
                        Image.SCALE_DEFAULT);  
                // 改进的想法:是否可用多线程加快切割速度  
                // 四个参数分别为图像起点坐标和宽高  
                // 即: CropImageFilter(int x,int y,int width,int height)  
                cropFilter = new CropImageFilter(x, y, destWidth, destHeight);
                img = Toolkit.getDefaultToolkit().createImage(  
                        new FilteredImageSource(image.getSource(), cropFilter));  
                BufferedImage tag = new BufferedImage(destWidth, destHeight,  
                        BufferedImage.TYPE_INT_RGB);  
                Graphics g = tag.getGraphics();  
                g.drawImage(img, 0, 0, null); // 绘制缩小后的图  
                g.dispose();  
                // 输出为文件  
                ImageIO.write(tag, "JPEG", new File(dirImageFile));  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  
    public static void cut(InputStream is,File dirImageFile, int x, int y, int destWidth,  
            int destHeight) throws IOException {  
        cut(ImageIO.read(is),dirImageFile,x,y,destWidth,destHeight);
    }  
    public static void cut(BufferedImage bi,File dirImageFile, int x, int y, int destWidth,  
            int destHeight) {  
        try {  
            Image img;  
            ImageFilter cropFilter;  
            // 读取源图像  
            int srcWidth = bi.getWidth(); // 源图宽度  
            int srcHeight = bi.getHeight(); // 源图高度            
            if (srcWidth >= destWidth && srcHeight >= destHeight) {  
                Image image = bi.getScaledInstance(srcWidth, srcHeight,  
                        Image.SCALE_DEFAULT);  
                // 改进的想法:是否可用多线程加快切割速度  
                // 四个参数分别为图像起点坐标和宽高  
                // 即: CropImageFilter(int x,int y,int width,int height)  
                cropFilter = new CropImageFilter(x, y, destWidth, destHeight);
                img = Toolkit.getDefaultToolkit().createImage(  
                        new FilteredImageSource(image.getSource(), cropFilter));  
                BufferedImage tag = new BufferedImage(destWidth, destHeight,  
                        BufferedImage.TYPE_INT_RGB);  
                Graphics g = tag.getGraphics();  
                g.drawImage(img, 0, 0, null); // 绘制缩小后的图  
                g.dispose();  
                // 输出为文件  
                ImageIO.write(tag, "JPEG", dirImageFile);  
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }   
    /** 
     * 缩放图像 
     *  
     * @param srcImageFile       源图像文件地址 
     * @param result             缩放后的图像地址 
     * @param scale              缩放比例 
     * @param flag               缩放选择:true 放大; false 缩小; 
     */  
    public static void scale(String srcImageFile, String result, int scale,  
            boolean flag) {  
        try {  
            BufferedImage src = ImageIO.read(new File(srcImageFile)); // 读入文件  
            int width = src.getWidth(); // 得到源图宽  
            int height = src.getHeight(); // 得到源图长  
            if (flag) {  
                // 放大  
                width = width * scale;  
                height = height * scale;  
            } else {  
                // 缩小  
                width = width / scale;  
                height = height / scale;  
            }  
            Image image = src.getScaledInstance(width, height,Image.SCALE_DEFAULT);  
            BufferedImage tag = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);  
            Graphics g = tag.getGraphics();  
            g.drawImage(image, 0, 0, null); // 绘制缩小后的图  
            g.dispose();  
            ImageIO.write(tag, "JPEG", new File(result));// 输出到文件流  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  

    /** 
     * 重新生成按指定宽度和高度的图像 
     * @param srcImageFile       源图像文件地址 
     * @param result             新的图像地址 
     * @param _width             设置新的图像宽度 
     * @param _height            设置新的图像高度 
     */  
    public static void scale(String srcImageFile, String result, int _width,int _height) {        
        scale(srcImageFile,result,_width,_height,0,0);  
    }  

    public static void scale(String srcImageFile, String result, int _width,int _height,int x,int y) {  
        try {  

            BufferedImage src = ImageIO.read(new File(srcImageFile)); // 读入文件  

            int width = src.getWidth(); // 得到源图宽  
            int height = src.getHeight(); // 得到源图长  

            if (width > _width) {  
                 width = _width;  
            }  
            if (height > _height) {  
                height = _height;  
            }             
            Image image = src.getScaledInstance(width, height,Image.SCALE_DEFAULT);  
            BufferedImage tag = new BufferedImage(width, height,BufferedImage.TYPE_INT_RGB);  
            Graphics g = tag.getGraphics();  
            g.drawImage(image, x, y, null); // 绘制缩小后的图  
            g.dispose();              
            ImageIO.write(tag, "JPEG", new File(result));// 输出到文件流  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }  

    /** 
     * 图像类型转换 GIF->JPG GIF->PNG PNG->JPG PNG->GIF(X) 
     */  
    public static void convert(String source, String result) {  
        try {  
            File f = new File(source);  
            f.canRead();  
            f.canWrite();  
            BufferedImage src = ImageIO.read(f);  
            ImageIO.write(src, "JPG", new File(result));  
        } catch (Exception e) {  
            e.printStackTrace();  
        }  
    }  

    /** 
     * 彩色转为黑白 
     *  
     * @param source 
     * @param result 
     */  
    public static void gray(String source, String result) {  
        try {  
            BufferedImage src = ImageIO.read(new File(source));  
            ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);  
            ColorConvertOp op = new ColorConvertOp(cs, null);  
            src = op.filter(src, null);  
            ImageIO.write(src, "JPEG", new File(result));  
        } catch (IOException e) {  
            e.printStackTrace();  
        }  
    }     
}  

2. Java后端图片裁剪处理(Controller)

//图片裁剪功能
    @RequestMapping(value = "/imgCut.do",method = RequestMethod.POST, produces="text/html;charset=utf-8")  
    @ResponseBody
    public String profile_imgCut(MultipartFile avatar_file,String avatar_src,String avatar_data, HttpServletRequest request, Model model) {
        String dir = ConfigInfo.resources_upload_path;
        String path = request.getSession().getServletContext().getRealPath(dir);  

        String name = avatar_file.getOriginalFilename();
        //判断文件的MIMEtype
        String type = avatar_file.getContentType();
        if(type==null || !type.toLowerCase().startsWith("image/")) return  JSON.toJSONString(new Result(false,"不支持的文件类型,仅支持图片!"));
        System.out.println("file type:"+type);
        String fileName = new Date().getTime()+""+new Random().nextInt(10000)+"_"+name.substring(name.lastIndexOf('.'));
        System.out.println("文件路径:"+path+":"+fileName); 

        JSONObject joData = (JSONObject) JSONObject.parse(avatar_data);
          // 用户经过剪辑后的图片的大小  
        float x = joData.getFloatValue("x");
        float y = joData.getFloatValue("y");
        float w =  joData.getFloatValue("width");
        float h =  joData.getFloatValue("height");

        //开始上传
        File targetFile = new File(path, fileName);
        //保存  
        try {  
            if(!targetFile.exists()){  
                targetFile.mkdirs();  
                InputStream is = avatar_file.getInputStream();
                ImageCut.cut(is, targetFile, (int)x,(int)y,(int)w,(int)h);  
                is.close();
            }  
        } catch (Exception e) {  
            e.printStackTrace();  
            return  JSON.toJSONString(new Result(false,"上传失败,出现异常:"+e.getMessage()));
        }  
        return  JSON.toJSONString(new Result(true,"上传成功!",request.getSession().getServletContext().getContextPath()+dir+fileName));
    }

3. 前端form提交(test.html)

<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <title>TEST</title>
  <!-- Tell the browser to be responsive to screen width -->
  <meta content="width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no" name="viewport">
  <link rel="stylesheet" href="${request.contextPath}/resources/bootstrap/css/bootstrap.min.css">
  <link rel="stylesheet" href="${request.contextPath}/resources/cropper/cropper.min.css"/>
  <link rel="stylesheet" href="${request.contextPath}/resources/cropper/crop-avatar/css/main.css"/>
</head>
<body>
 <div class="container" id="crop-avatar">
    <!-- Current avatar -->
    <div class="avatar-view" title="Change the avatar">
      <img src="${request.contextPath}/resources/cropper/crop-avatar/img/picture.jpg" alt="Avatar">
    </div>

    <!-- Cropping modal -->
    <div class="modal fade" id="avatar-modal" aria-hidden="true" aria-labelledby="avatar-modal-label" role="dialog" tabindex="-1">
      <div class="modal-dialog modal-lg">
        <div class="modal-content">
          <form class="avatar-form" action="imgCut.do" enctype="multipart/form-data" method="post" accept="image/*">
            <div class="modal-header">
              <button type="button" class="close" data-dismiss="modal">&times;</button>
              <h4 class="modal-title" id="avatar-modal-label">Change Avatar</h4>
            </div>
            <div class="modal-body">
              <div class="avatar-body">

                <!-- Upload image and data -->
                <div class="avatar-upload">
                  <input type="hidden" class="avatar-src" name="avatar_src">
                  <input type="hidden" class="avatar-data" name="avatar_data">
                  <label for="avatarInput" class="btn btn-primary">选择图片</label>
                  <input type="file" class="avatar-input" id="avatarInput" name="avatar_file" style="display: none;" accept="image/*">
                </div>

                <!-- Crop and preview -->
                <div class="row">
                  <div class="col-md-9">
                    <div class="avatar-wrapper"></div>
                  </div>
                  <div class="col-md-3">
                    <div class="avatar-preview preview-lg"></div>
                    <div class="avatar-preview preview-md"></div>
                    <div class="avatar-preview preview-sm"></div>
                  </div>
                </div>

                <div class="row avatar-btns">
                  <div class="col-md-9">
                    <div class="btn-group">
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="-90" title="Rotate -90 degrees">Rotate Left</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="-15">-15deg</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="-30">-30deg</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="-45">-45deg</button>
                    </div>
                    <div class="btn-group">
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="90" title="Rotate 90 degrees">Rotate Right</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="15">15deg</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="30">30deg</button>
                      <button type="button" class="btn btn-primary" data-method="rotate" data-option="45">45deg</button>
                    </div>
                  </div>
                  <div class="col-md-3">
                    <button type="submit" class="btn btn-primary btn-block avatar-save">Done</button>
                  </div>
                </div>
              </div>
            </div>
            <!-- <div class="modal-footer">
              <button type="button" class="btn btn-default" data-dismiss="modal">Close</button>
            </div> -->
          </form>
        </div>
      </div>
    </div><!-- /.modal -->

    <!-- Loading state -->
    <div class="loading" aria-label="Loading" role="img" tabindex="-1"></div>
  </div>
<!-- jQuery -->
<script src="${request.contextPath}/resources/plugins/jQuery/jquery-2.2.4.min.js"></script>
<script src="${request.contextPath}/resources/bootstrap/js/bootstrap.min.js"></script>
<script src="${request.contextPath}/resources/cropper/cropper.min.js"></script>
<script src="${request.contextPath}/resources/cropper/crop-avatar/js/main.js"></script>
</body>
</html>

注意:从Cropper官网上下载下来后,在examples目录下有一个示例crop-avatar,将其中的main.css以及main.js复制到你的项目中,Cropper是依赖于jquery以及bootstrap的,所以也要把相应的css和js引进来。

4. 页面展示效果

点击头像,弹出modal。点击Done提交form后生成目标裁剪图片保存到服务器,并返回给页面显示。
这里写图片描述

5.配置文件上传

由于上面图片裁剪涉及到图片上传,所以需要配置Spring支持文件上传功能。

5.1 依赖的jar

<!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.3.1</version>
        </dependency>

5.2 在Spring配置文件中添加文件上传支持

<!-- 支持上传文件 -->  
    <bean id="multipartResolver" class="org.springframework.web.multipart.commons.CommonsMultipartResolver"/>  

6. 说明

Cropper 使用的是html5的一个新特性(FormData)来提交表单,在其main.js文件中有这样一行代码:

var data = new FormData(this.$avatarForm[0]);

这本质上也就是对表单进行了序列化。Cropper同时也支持旋转,只是在后台处理旋转会比较麻烦点。
前端form提交的数据有 :avatar_file(源文件),avatar_data(裁剪参数JSON),如下通过FormData序列化后所提交的form的数据,后台控制器参数名只要对上就可以了:

------WebKitFormBoundaryx52DDecBJ0KiNHRY
Content-Disposition: form-data; name="avatar_src"


------WebKitFormBoundaryx52DDecBJ0KiNHRY
Content-Disposition: form-data; name="avatar_data"

{"x":76.49999999999999,"y":22.000000000000007,"height":176.00000000000003,"width":176.00000000000003,"rotate":0}
------WebKitFormBoundaryx52DDecBJ0KiNHRY
Content-Disposition: form-data; name="avatar_file"; filename="3.jpg"
Content-Type: image/jpeg


------WebKitFormBoundaryx52DDecBJ0KiNHRY--

另外Result是自定义的类,很简单:

public class Result {
    private boolean success;
    private String info;
    private Object data;//也可用来标识错误代码
    ...  此处省略getset方法
}

用到的JSON,当然可以用其他的JSON的jar包:

<dependency>
  <groupId>com.alibaba</groupId>
    <artifactId>fastjson</artifactId>
    <version>1.2.12</version>
</dependency>

参考:jQuery与Java实现图片的剪切

最后

以上就是单薄大米为你收集整理的Java 利用jquery库cropper完成图片裁剪功能的全部内容,希望文章能够帮你解决Java 利用jquery库cropper完成图片裁剪功能所遇到的程序开发问题。

如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。

本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
点赞(45)

评论列表共有 0 条评论

立即
投稿
返回
顶部