基于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

智能推荐

[Mysql] CONVERT函数_mysql convert-程序员宅基地

文章浏览阅读3.1w次,点赞23次,收藏109次。本文主要讲解CONVERT函数_mysql convert

【Android】Retrofit入门详解-程序员宅基地

文章浏览阅读1.6k次,点赞23次,收藏2次。简介:大三学生党一枚!主攻Android开发,对于Web和后端均有了解。个人语录:取乎其上,得乎其中,取乎其中,得乎其下,以顶级态度写好一篇的博客。Retrofit入门一.Retrofit介绍二.Retrofit注解2.1 请求方法注解2.1.1 GET请求2.1.2 POST请求2.2 标记类注解2.2.1 FormUrlEncoded2.2.2 Multipart2.2.3 Streaming2.3 参数类注解2.3.1 Header和Headers2.3.2 Body2.3.3 Path2.3.4_retrofit

教你拷贝所有文件到指定文件夹_所有文件夹下文件的 拷贝怎么弄-程序员宅基地

文章浏览阅读1.9k次。在处理文件的时候,如何将文件、文件夹复制到指定文件夹之中呢?打开【文件批量改名高手】,在“文件批量管理任务”中,先点“添加文件”,将文件素材导入。选好一系列的复制选项,单击开始复制,等全部复制好了,提示“已完成XX%”然后可以任意右击一个文件夹路径,在显示出的下拉列表中,选择“打开文件夹”在“复制到的目标文件夹(目录)”中,导入文件夹,多个文件夹,一行一个。最后,即可看到文件、文件夹都复制到各个指定的文件夹之中一一显示着啦。导入后,在表格中我们就可以看到文件或文件夹的名称以及所排列的序号。..._所有文件夹下文件的 拷贝怎么弄

win10和linux双系统安装步骤(详细!)_怎么装双系统win10和linux-程序员宅基地

文章浏览阅读5k次,点赞11次,收藏42次。Windows10安装ubuntu双系统教程ubuntu分区方案_怎么装双系统win10和linux

从图的邻接表表示转换成邻接矩阵表示_typedef struct arcnode{int adjvex;-程序员宅基地

文章浏览阅读1.1k次。从图的邻接表表示转换成邻接矩阵表示typedef struct ArcNode{ int adjvex;//该弧指向的顶点的位置 struct ArcNode *next;//下一条弧的指针 int weight;//弧的权重} ArcNode;typedef struct{ VertexType data;//顶点信息 ArcNode *firstarc;} VNode,AdList[MAXSIZE];typedef struct{ int vexnum;//顶点数 int _typedef struct arcnode{int adjvex;

学好Python开发你一定会用到这30框架种(1)-程序员宅基地

文章浏览阅读635次,点赞18次,收藏26次。14、fabric是基于Python实现的SSH命令行工具,简化了SSH的应用程序部署及系统管理任务,它提供了系统基础的操作组件,可以实现本地或远程shell命令,包括命令执行,文件上传,下载及完整执行日志输出等功能。7、pycurl 是一个用C语言写的libcurl Python实现,功能强大,支持的协议有:FTP,HTTP,HTTPS,TELNET等,可以理解为Linux下curl命令功能的Python封装。Scipy是Python的科学计算库,对Numpy的功能进行了扩充,同时也有部分功能是重合的。

随便推点

手机能打开的表白代码_能远程打开,各种手机电脑进行监控操作,最新黑科技...-程序员宅基地

文章浏览阅读511次。最近家中的潮人,老妈闲着没事干,开始学玩电脑,引起他的各种好奇心。如看看新闻,上上微信或做做其他的事情。但意料之中的是电脑上会莫名出现各种问题?不翼而飞的图标?照片又不见了?文件被删了,卡机或者黑屏,无声音了,等等问题。常常让她束手无策,求助于我,可惜在电话中说不清,往往只能苦等我回家后才能解决,那种开心乐趣一下子消失了。想想,这样也不是办法啊, 于是,我潜心寻找了两款优秀的远程控制软件。两款软件...

成功Ubuntu18.04 ROS melodic安装Cartograhper+Ceres1.13.0,以及错误总结_ros18.04 安装ca-程序员宅基地

文章浏览阅读1.8k次。二.初始化工作空间三.设置下载地址四.下载功能包此处可能会报错,请看:rosdep update遇到ERROR: error loading sources list: The read operation timed out问题_DD᭄ꦿng的博客-程序员宅基地接下来一次安装所有功能包,注意对应ROS版本 五.编译功能包isolated:单独编译各个功能包,每个功能包之间不产生依赖。编译过程时间比较长,可能需要几分钟时间。此处可能会报错:缺少absl依赖包_ros18.04 安装ca

Harbor2.2.1配置(trivy扫描器、镜像签名)_init error: db error: failed to download vulnerabi-程序员宅基地

文章浏览阅读4.1k次,点赞3次,收藏7次。Haobor2.2.1配置(trivy扫描器、镜像签名)docker-compose下载https://github.com/docker/compose/releases安装cp docker-compose /usr/local/binchmod +x /usr/local/bin/docker-composeharbor下载https://github.com/goharbor/harbor/releases解压tar xf xxx.tgx配置harbor根下建立:mkd_init error: db error: failed to download vulnerability db: database download

openFOAM学习笔记(四)—— openFOAM中的List_openfoam list-程序员宅基地

文章浏览阅读3.2k次。又是一个很底层的部分,但是也非常重要_openfoam list

C++对象的JSON序列化与反序列化探索_c++对象 json 序列化和反序列化 库-程序员宅基地

文章浏览阅读1.7w次,点赞3次,收藏15次。一:背景作为一名C++开发人员,我一直很期待能够像C#与JAVA那样,可以轻松的进行对象的序列化与反序列化,但到目前为止,尚未找到相对完美的解决方案。本文旨在抛砖引玉,期待有更好的解决方案;同时向大家寻求帮助,解决本文中未解决的问题。 二:相关技术介绍本方案采用JsonCpp来做具体的JSON的读入与输出,再结合类成员变量的映射,最终实现对象的JSON序列化与反序列化。本文不再_c++对象 json 序列化和反序列化 库

linux x window 详解,王垠:详解Xwindow(插窗户)的工作原理-程序员宅基地

文章浏览阅读523次。该楼层疑似违规已被系统折叠隐藏此楼查看此楼(本文作者貌似是王垠,在某处扒拉出来的转载过来)Xwindow 是非常巧妙的设计,很多时候它在概念上比其它窗口系统先进,以至于经过很多年它仍然是工作站上的工业标准。许多其它窗口系统的概念都是从 Xwindow 学来的。Xwindow 可以说的东西太多了。下面只分辨一些容易混淆的概念,提出一些正确使用它的建议。分辨 X server 和 X client这..._整个插入的窗叫什么