基于SpringBoot的图片上传组件,实现图片裁剪、Thumbnailator压缩的功能_图片裁剪springboot插件-程序员宅基地

技术标签: springboot  

本周三、周四、周五封装了一个基于SpringBoot的图片上传组件。功能流程如下:

1、前台页面有一个“选择文件”按钮,点击选择一张图片后,在前台界面进行显示。

2、双击显示出来的图片,前台使用cropper图片裁剪插件,将裁剪信息(裁剪起始点坐标 x,y,裁剪宽度width,裁剪高度height)以及上传的图片文件,传给后台。

3、后台对图片进行裁剪,再将裁剪后的图片进行压缩,把原图路径、裁剪后图片路径、压缩后图片路径、base64编码存入数据库。(同时后台将这三种图片保存到本地 D:/images/ 路径下)

4、后台将压缩后的图片路径传给前台。

5、前台接收到这个路径,在页面上进行显示。由于此时显示的是压缩的图片,如果用户想看原图(裁剪后图片的原图),点击该图片,携带这个图片路径请求后台接口。

6、后台接收到压缩图片路径,select数据库,找到裁剪后图片路径,返回给前台。

7、前台接收到这个原图片路径,在页面进行显示。

一、SpringBoot自定义静态资源映射

将一些动态维护的文件,放在服务器磁盘的某个目录下(项目目录之外),并且通过SpringBoot服务进行访问。

实现类继承WebMvcConfigurerAdapter并重写方法addResourceHandlers,将磁盘上文件存放的绝对路径映射,就可以通过访问SpringBoot服务来访问文件了。

[html]  view plain   copy
  1. @Configuration  
  2. public class WebAppConfig extends WebMvcConfigurerAdapter {  
  3.   
  4.     @Override  
  5.     public void addResourceHandlers(ResourceHandlerRegistry registry) {  
  6.         registry.addResourceHandler("/myImages/**").addResourceLocations("file:D:/images/");  
  7.         super.addResourceHandlers(registry);  
  8.     }  
  9. }  
这样就将D盘上的images目录映射到myImages路径下,这个 myImages 是随意的一个命名。
假如在D盘images目录下有一个test.jpg图片,那么通过访问 http://localhost:8080/myImages/test.jpg  就可以访问到该图片了。

二、Java实现图片裁剪、使用Thumbnailator工具对图片进行压缩。

height。

1、controller层代码:

[java]  view plain   copy
  1. /** 
  2.  * 图像切割(按指定起点坐标和宽高切割) 
  3.  * @param file 源图像文件 
  4.  * @param x 目标切片起点坐标X 
  5.  * @param y 目标切片起点坐标Y 
  6.  * @param width 目标切片宽度 
  7.  * @param height 目标切片高度 
  8.  */  
  9. @RequestMapping(value = "/cutImage", method = RequestMethod.POST, headers = "Accept=application/json")  
  10. @ResponseBody  
  11. public HttpResponseEntity cutImage(MultipartFile file,  
  12.                                    int x, int y, int width, int height) {  
  13.     HttpResponseEntity httpResponseEntity = new HttpResponseEntity();  
  14.     try {  
  15.   
  16.         String strResult = imgUploadService.cutImage(file, x, y, width, height);  
  17.         httpResponseEntity.setMessage("成功");  
  18.         httpResponseEntity.setCode("200");  
  19.         httpResponseEntity.setData(strResult);  
  20.   
  21.     } catch (Exception e) {  
  22.         e.printStackTrace();  
  23.         httpResponseEntity.setCode("602");  
  24.         httpResponseEntity.setMessage("失败");  
  25.     }  
  26.     return httpResponseEntity;  
  27. }  
2、service层代码:

在本方法中使用uuid为图片重命名。

在本方法中实现了对图片的裁剪、等比例压缩。此处压缩使用的是Thumbnailator工具,压缩质量很高。但是按照

Thumbnails.of(new_path_img)
        .scale(1f)//图片长宽大小
        .outputQuality(0.1f)//图片质量
        .toFile(compress_img_path);
这个方法实现的压缩,内存大小依旧很大。

[java]  view plain   copy
  1.     @Override  
  2.     /** 
  3.      * @param srcFile源文件 
  4.      * @param outFile输出文件 
  5.      * @param x坐标 
  6.      * @param y坐标 
  7.      * @param width宽度 
  8.      * @param height高度 
  9.      * @描述 —— 裁剪图片 
  10.      */  
  11.     public String cutImage(MultipartFile file, int x, int y, int width, int height) throws IOException {  
  12.         //得到上传时的文件名  
  13.         String filename = file.getOriginalFilename();  
  14.         //获取文件后缀名  
  15.         String suffixName = filename.substring(filename.lastIndexOf("."));  
  16.         //获取uuid作为文件名  
  17.         String name = UUIDUtil.getOneUUID();  
  18.         filename = name + suffixName;  
  19.         //存储地址  
  20.         String filePath = "D:/images/";  
  21.         //图片路径  
  22.         String path_img = filePath + filename;  
  23.         File dest = new File(path_img);  
  24.         if (!dest.getParentFile().exists()) {  
  25.             dest.getParentFile().mkdirs();  
  26.         }  
  27.         try {  
  28.             file.transferTo(dest);  
  29.         } catch (IOException e) {  
  30.             e.printStackTrace();  
  31.         }  
  32.   
  33.         ImgUploadEntity imgUploadEntity = new ImgUploadEntity();  
  34.         imgUploadEntity.setImgPath(filename);  
  35.   
  36.         FileInputStream is = null;  
  37.         ImageInputStream iis = null;  
  38.         try {  
  39.             // 如果源图片不存在  
  40.             if (!new File(path_img).exists()) {  
  41.                 return "失败";  
  42.             }  
  43.             // 读取图片文件  
  44.             is = new FileInputStream(path_img);  
  45.             // 获取文件格式  
  46.             String ext = path_img.substring(path_img.lastIndexOf(".") + 1);  
  47.             // ImageReader解码指定格式  
  48.             Iterator<ImageReader> it = ImageIO.getImageReadersByFormatName(ext);  
  49.             ImageReader reader = it.next();  
  50.             // 获取图片流  
  51.             iis = ImageIO.createImageInputStream(is);  
  52.             // 输入源中的图像将只按顺序读取  
  53.             reader.setInput(iis, true);  
  54.             // 描述如何对流进行解码  
  55.             ImageReadParam param = reader.getDefaultReadParam();  
  56.             // 图片裁剪区域  
  57.             Rectangle rect = new Rectangle(x, y, width, height);  
  58.             // 提供一个 BufferedImage,将其用作解码像素数据的目标  
  59.             param.setSourceRegion(rect);  
  60.             // 使用所提供的 ImageReadParam 读取通过索引 imageIndex 指定的对象  
  61.             BufferedImage bi = reader.read(0, param);  
  62.             // 保存新图片  
  63.             String name1 = UUIDUtil.getOneUUID();  
  64.             String newFileName = name1 + suffixName;  
  65.             String new_path_img = filePath + newFileName;  
  66.   
  67.             File tempOutFile = new File(new_path_img);  
  68.             if (!tempOutFile.exists()) {  
  69.                 tempOutFile.mkdirs();  
  70.             }  
  71.             ImageIO.write(bi, ext, tempOutFile);  
  72.             imgUploadEntity.setNewImgPath(newFileName);  
  73.   
  74.             //为压缩后图片创建路径  
  75.             String compressImgPath = UUIDUtil.getOneUUID() + suffixName;  
  76.             String compress_img_path = filePath + compressImgPath;  
  77.   
  78.             //等比压缩图片,使用Java  
  79. //            boolean flag = compressImg(new_path_img, compress_img_path,100,100,true);  
  80.   
  81.             /* 
  82.             * 压缩图片,使用Thumbnails工具 
  83.             * 先判断图片大小,如果小于50 kb(51200字节)不进行压缩 
  84.             * file.length()方法最大只能获取2g的文件大小,但是前台传给后台图片最大为10M,所以此处不必担心 
  85.             */  
  86.             if(tempOutFile.length() < 51200){  
  87.                 compressImgPath = newFileName;  
  88.                 compress_img_path = new_path_img;  
  89.                 imgUploadEntity.setCompressImgPath(compressImgPath);  
  90.                 File noCompressFile = new File(compress_img_path);  
  91.                 if (!noCompressFile.exists()) {  
  92.                     tempOutFile.mkdirs();  
  93.                 }  
  94.             }  
  95.             else {  
  96.                 //首先判断图片类型,如果是png格式图片,就修改图片类型成jpg格式(图片尺寸不变)。  
  97.                 if (suffixName.equals(".png")) {  
  98.                     Thumbnails.of(new_path_img)  
  99.                             .scale(1f)  
  100.                             .outputFormat("jpg")  
  101.                             .toFile(filePath + name1);  
  102.                 }  
  103.                 Thumbnails.of(new_path_img)  
  104.                         .scale(1f)//图片长宽大小  
  105.                         .outputQuality(0.1f)//图片质量  
  106.                         .toFile(compress_img_path);  
  107.                 imgUploadEntity.setCompressImgPath(compressImgPath);  
  108.             }  
  109.   
  110.             //获取压缩后文件的base64编码  
  111. //            String strBase64 = codeBase64(compress_img_path);  
  112.   
  113. //            imgUploadEntity.setNewImgBase(strBase64);  
  114.   
  115.             imgUploadEntityMapper.insertImgPath(imgUploadEntity);  
  116.   
  117.             return compressImgPath;  
  118.   
  119.         } catch (Exception e) {  
  120.             e.printStackTrace();  
  121.             return "失败";  
  122.         } finally {  
  123.             try {  
  124.                 if (is != null) {  
  125.                     is.close();  
  126.                 }  
  127.                 if (iis != null) {  
  128.                     iis.close();  
  129.                 }  
  130.             } catch (IOException e) {  
  131.                 e.printStackTrace();  
  132.                 return "失败";  
  133.             }  
  134.         }  
  135.     }  


可以实现 图片压缩 的另一种方法:这种方法需要传入想要压缩后的图片长、宽。我认为这个方法也很好,可以指定大小。


[html]  view plain   copy
  1. /**  
  2.  * @param inputFile  源文件  
  3.  * @param outFile    生成文件  
  4.  * @param width      指定宽度  
  5.  * @param height     指定高度  
  6.  * @param proportion 是否等比例操作  
  7.  * @描述 —— 是否等比例缩放图片  
  8.  */  
  9. public static boolean compressImg(String inputFile, String outFile,  
  10.                                   int width, int height, boolean proportion) {  
  11.     try {  
  12.         // 获得源文件  
  13.         File file = new File(inputFile);  
  14.         if (!file.exists()) {  
  15.             return false;  
  16.         }  
  17.         Image img = ImageIO.read(file);  
  18.         // 判断图片格式是否正确  
  19.         if (img.getWidth(null) == -1) {  
  20.             return false;  
  21.         } else {  
  22.             int newWidth;  
  23.             int newHeight;  
  24.             // 判断是否是等比缩放  
  25.             if (proportion == true) {  
  26.                 // 为等比缩放计算输出的图片宽度及高度  
  27.                 double rate1 = ((double) img.getWidth(null))  
  28.                         / (double) width + 0.1;  
  29.                 double rate2 = ((double) img.getHeight(null))  
  30.                         / (double) height + 0.1;  
  31.                 // 根据缩放比率大的进行缩放控制  
  32.                 double rate = rate1 > rate2 ? rate1 : rate2;  
  33.                 newWidth = (int) (((double) img.getWidth(null)) / rate);  
  34.                 newHeight = (int) (((double) img.getHeight(null)) / rate);  
  35.             } else {  
  36.                 newWidth = width; // 输出的图片宽度  
  37.                 newHeight = height; // 输出的图片高度  
  38.             }  
  39.   
  40.             BufferedImage tag = new BufferedImage((int) newWidth,  
  41.                     (int) newHeight, BufferedImage.TYPE_INT_RGB);  
  42.   
  43.             /*  
  44.              * Image.SCALE_SMOOTH 的缩略算法 生成缩略图片的平滑度的,优先级比速度高  
  45.             生成的图片质量比较好但速度慢  
  46.              */  
  47.             tag.getGraphics().drawImage(  
  48.                     img.getScaledInstance(newWidth, newHeight,  
  49.                             Image.SCALE_SMOOTH), 0, 0, null);  
  50.             FileOutputStream out = new FileOutputStream(outFile);  
  51.             // JPEGImageEncoder可适用于其他图片类型的转换  
  52.             JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(out);  
  53.             encoder.encode(tag);  
  54.             out.close();  
  55.         }  
  56.     } catch (IOException ex) {  
  57.         ex.printStackTrace();  
  58.     }  
  59.     return true;  
  60. }  

本组件原计划将压缩后的图片转化成base64编码,存到数据库,前台请求图片时,给前台返回这个base64编码,但是由于Thumbnailato工具压缩完图片后,图片依旧很大,导致base64码过长,不利于前后台数据交互,所以后来改成直接传图片路径了。

把图片转base64编码的代码贴出来:

[java]  view plain   copy
  1. public String codeBase64(String inputFile) {  
  2.     //将压缩后图片文件转化为字节数组字符串,并对其进行Base64编码处理  
  3.     InputStream in = null;  
  4.     byte[] data = null;  
  5.     //读取图片字节数组  
  6.     try {  
  7.         in = new FileInputStream(inputFile);  
  8.         data = new byte[in.available()];  
  9.         in.read(data);  
  10.         in.close();  
  11.     } catch (IOException e) {  
  12.         e.printStackTrace();  
  13.     }  
  14.     String strBase64 = new String(Base64.encodeBase64(data));  
  15.   
  16.     return strBase64;  
  17.   
  18. }  

Thumbnailato使用时需要添加依赖

[html]  view plain   copy
  1. <dependency>  
  2. <span style="white-space:pre;"> </span><groupId>net.coobird</groupId>  
  3.     <artifactId>thumbnailator</artifactId>  
  4.     <version>0.4.8</version>  
  5. </dependency>  
以上代码就是Java实现对图片上传、裁剪、压缩的代码实现。

本人还是一枚Java小白,如有不对的地方,请大家多多指正。

参考自:

http://blog.csdn.net/Colton_Null/article/details/78255970

http://blog.csdn.net/wangpeng047/article/details/19624993

http://blog.csdn.net/wangpeng047/article/details/19624993

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/qq_34826130/article/details/80781116

智能推荐

Docker 快速上手学习入门教程_docker菜鸟教程-程序员宅基地

文章浏览阅读2.5w次,点赞6次,收藏50次。官方解释是,docker 容器是机器上的沙盒进程,它与主机上的所有其他进程隔离。所以容器只是操作系统中被隔离开来的一个进程,所谓的容器化,其实也只是对操作系统进行欺骗的一种语法糖。_docker菜鸟教程

电脑技巧:Windows系统原版纯净软件必备的两个网站_msdn我告诉你-程序员宅基地

文章浏览阅读5.7k次,点赞3次,收藏14次。该如何避免的,今天小编给大家推荐两个下载Windows系统官方软件的资源网站,可以杜绝软件捆绑等行为。该站提供了丰富的Windows官方技术资源,比较重要的有MSDN技术资源文档库、官方工具和资源、应用程序、开发人员工具(Visual Studio 、SQLServer等等)、系统镜像、设计人员工具等。总的来说,这两个都是非常优秀的Windows系统镜像资源站,提供了丰富的Windows系统镜像资源,并且保证了资源的纯净和安全性,有需要的朋友可以去了解一下。这个非常实用的资源网站的创建者是国内的一个网友。_msdn我告诉你

vue2封装对话框el-dialog组件_<el-dialog 封装成组件 vue2-程序员宅基地

文章浏览阅读1.2k次。vue2封装对话框el-dialog组件_

MFC 文本框换行_c++ mfc同一框内输入二行怎么换行-程序员宅基地

文章浏览阅读4.7k次,点赞5次,收藏6次。MFC 文本框换行 标签: it mfc 文本框1.将Multiline属性设置为True2.换行是使用"\r\n" (宽字符串为L"\r\n")3.如果需要编辑并且按Enter键换行,还要将 Want Return 设置为 True4.如果需要垂直滚动条的话将Vertical Scroll属性设置为True,需要水平滚动条的话将Horizontal Scroll属性设_c++ mfc同一框内输入二行怎么换行

redis-desktop-manager无法连接redis-server的解决方法_redis-server doesn't support auth command or ismis-程序员宅基地

文章浏览阅读832次。检查Linux是否是否开启所需端口,默认为6379,若未打开,将其开启:以root用户执行iptables -I INPUT -p tcp --dport 6379 -j ACCEPT如果还是未能解决,修改redis.conf,修改主机地址:bind 192.168.85.**;然后使用该配置文件,重新启动Redis服务./redis-server redis.conf..._redis-server doesn't support auth command or ismisconfigured. try

实验四 数据选择器及其应用-程序员宅基地

文章浏览阅读4.9k次。济大数电实验报告_数据选择器及其应用

随便推点

灰色预测模型matlab_MATLAB实战|基于灰色预测河南省社会消费品零售总额预测-程序员宅基地

文章浏览阅读236次。1研究内容消费在生产中占据十分重要的地位,是生产的最终目的和动力,是保持省内经济稳定快速发展的核心要素。预测河南省社会消费品零售总额,是进行宏观经济调控和消费体制改变创新的基础,是河南省内人民对美好的全面和谐社会的追求的要求,保持河南省经济稳定和可持续发展具有重要意义。本文建立灰色预测模型,利用MATLAB软件,预测出2019年~2023年河南省社会消费品零售总额预测值分别为21881...._灰色预测模型用什么软件

log4qt-程序员宅基地

文章浏览阅读1.2k次。12.4-在Qt中使用Log4Qt输出Log文件,看这一篇就足够了一、为啥要使用第三方Log库,而不用平台自带的Log库二、Log4j系列库的功能介绍与基本概念三、Log4Qt库的基本介绍四、将Log4qt组装成为一个单独模块五、使用配置文件的方式配置Log4Qt六、使用代码的方式配置Log4Qt七、在Qt工程中引入Log4Qt库模块的方法八、获取示例中的源代码一、为啥要使用第三方Log库,而不用平台自带的Log库首先要说明的是,在平时开发和调试中开发平台自带的“打印输出”已经足够了。但_log4qt

100种思维模型之全局观思维模型-67_计算机中对于全局观的-程序员宅基地

文章浏览阅读786次。全局观思维模型,一个教我们由点到线,由线到面,再由面到体,不断的放大格局去思考问题的思维模型。_计算机中对于全局观的

线程间控制之CountDownLatch和CyclicBarrier使用介绍_countdownluach于cyclicbarrier的用法-程序员宅基地

文章浏览阅读330次。一、CountDownLatch介绍CountDownLatch采用减法计算;是一个同步辅助工具类和CyclicBarrier类功能类似,允许一个或多个线程等待,直到在其他线程中执行的一组操作完成。二、CountDownLatch俩种应用场景: 场景一:所有线程在等待开始信号(startSignal.await()),主流程发出开始信号通知,既执行startSignal.countDown()方法后;所有线程才开始执行;每个线程执行完发出做完信号,既执行do..._countdownluach于cyclicbarrier的用法

自动化监控系统Prometheus&Grafana_-自动化监控系统prometheus&grafana实战-程序员宅基地

文章浏览阅读508次。Prometheus 算是一个全能型选手,原生支持容器监控,当然监控传统应用也不是吃干饭的,所以就是容器和非容器他都支持,所有的监控系统都具备这个流程,_-自动化监控系统prometheus&grafana实战

React 组件封装之 Search 搜索_react search-程序员宅基地

文章浏览阅读4.7k次。输入关键字,可以通过键盘的搜索按钮完成搜索功能。_react search