[NeedBox项目总结]---图片处理

前言

在项目中,我们不可避免的会遇到对图片的处理,首先不考虑图片处理过程的细节,如何存储是个问题。如果图片很多的话,我们不可能把所有的图片都存储在数据库中,所以通常会在本机或者是服务器上单独创建一个目录来管理保存这些图片,在这个目录里,我们又会将其分为很多模块来存放不同类别的图片,而数据库里只需要保存图片的目录就可以了(为了便于项目的迁移,只保存相对路径)。
在这里插入图片描述
对于图片的处理,我使用了Thumbnailator这个类库。为了简化图片的处理,图片工具类自然是不可或缺的。接下来就来详细讲解图片处理的过程。

一、实现步骤

首先,以店铺缩略图的存储为例。每个店铺都会有图片,这个图片都保存在自己店铺的所属目录中。因为用户上传的图片路径大部分都不在同一目录,并且经常会重名,所以我们需要单独处理图片文件的路径,以及图片的重命名。
因此一个图片路径名应该是:项目存储图片的根目录/存储店铺缩略图的目录/店铺id/重命名后的图片名。

二、路径工具类(PathUtil.java)

思路:

  1. 设置图片存储的根目录
  2. 项目中使用的图片按照模块和功能,设置存储的相对路径。
  3. 图片的绝对路径为:根目录+子目录

为了更加方便的获取图片经过处理保存后的根目录和子目录以及其他目录,我们将这些方法写在PathUtil这个工具类里。

package com.yaya.o2o.util;

public class PathUtil {
    private static String seperator = System.getProperty("file.separator");
    //图片经过处理后的保存路径---根路径
    public static String getImgBasePath() {
        String os = System.getProperty("os.name");
        String basePath = "";
        if(os.toLowerCase().startsWith("win")) {
            basePath = "D:/o2o/image";
        } else {
            basePath = "/home/duck/image";
        }
        return basePath.replace("/" , seperator);
    }
    //店铺图片经过处理后的保存路径---子路径
    public static String getShopImagePath(long shopId) {
        String imagePath = "/upload/item/shop/" + shopId + "/";
        return imagePath.replace("/", seperator);
    }
	//个人信息头像经过处理后的保存路径---子路径
    public static String getPersonInfoImagePath() {
        String personInfoImagePath = "/upload/item/personinfo/";
        return personInfoImagePath.replace("/", seperator);
    }
}

考虑到项目将会迁移在不同的操作系统上,所以对不同操作系统上的目录分隔符做了替换处理。这里为了简单起见,我们直接将图片保存的根目录硬编码在代码中。

//获取当前操作系统的目录分隔符
private static String seperator = System.getProperty("file.separator");

在获取到目录后,用String的replace方法进行替换。这个类两个方法路径的结合得到了店铺图片应该存储的目录。但我们还不知道上传的图片的名字,并且没有给图片重命名来防止图片名称重复。下面通过ImageUtil来完成。

三、图片工具类(ImageUtil)

思路:

  1. 围绕添加水印输出目标图片这个功能展开
  2. 核心方法generateThumbnails,创建缩略图中3个关键参数 源图片 水印图 和 目标图片
  3. 围绕 源图片 水印图 和 目标图片,调用PathUtil中的方法拼接目标图片的存储路径以及目标图片的名称。

类似PathUtil工具类,对图片的处理我们也封装为一个类ImageUtil。

package com.yaya.o2o.util;

import com.yaya.o2o.dto.ImageHolder;
import net.coobird.thumbnailator.Thumbnails;
import net.coobird.thumbnailator.geometry.Positions;

import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Random;

public class ImageUtil {
    private static String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
    private static final SimpleDateFormat sDateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
    private static final Random r = new Random();

    //生成缩略图
    //参数:图片文件,保存路径
    public static String generateThumbnail(ImageHolder thumbnail, String targetAddr) {
        //1.目标目录,不存在创建,即/upload/item/shop/shopId
        makeDirPath(targetAddr);

        //2.为了防止图片重名,不采用用户上传的文件名,系统内部采用随机命名的方式
        //随机文件名
        String realFileName = getRandomFileName();

        //3.获取用户上传的文件扩展名,用于拼接新的文件名
        //文件扩展名
        String extension = getFileExtension(thumbnail.getImageName());

        //4.拼接新的文件名
        //相对路径===目标路径+随机文件名+扩展名,即/upload/item/shop/shopId/****.***
        String relativeAddr = targetAddr + realFileName + extension;
        //目标文件===根路径+相对路径
        File dest = new File(PathUtil.getImgBasePath() + relativeAddr);

        //5.给源文件加水印后输出到目标文件
        try {
            Thumbnails.of(thumbnail.getImage()).scale(0.7f)//图片大小
                    //添加水印
                    .watermark(Positions.BOTTOM_RIGHT,//水印位置---右下
                   		//水印路径,水印透明度
                        ImageIO.read(new File(basePath + "watermark.png")), 1.0f)
                    				//输出到目标文件
                    				.toFile(dest);
        } catch (IOException e) {
            e.printStackTrace();
        }
        //返回相对路径
        return relativeAddr;
    }
    
    //生成随机文件名,当前年月日小时分钟秒+五位随机数
    public static String getRandomFileName() {
        int rn = r.nextInt(89999) + 10000; //10000-99999
        String nowTimeStr = sDateFormat.format(new Date());
        return nowTimeStr + rn;
    }
    
    //获取输入文件流的扩展名
    public static String getFileExtension(String fileName) {
        return fileName.substring(fileName.lastIndexOf("."));
    }

    //创建目录
    public static void makeDirPath(String targetAddr) {
        String realFileParentPath = PathUtil.getImgBasePath();
        File dirPath = new File(realFileParentPath + targetAddr);
        if(!dirPath.exists()) {
            dirPath.mkdirs();
        }
    }
}
  1. 首先将水印图片储存在项目的resources目录下
    在这里插入图片描述
    那么在获取水印图片的路径的时候,同样将目录和水印图片名分开管理。
    private static String basePath = Thread.currentThread().getContextClassLoader().getResource("").getPath();
    
    通过执行线程逆推到类加载器进而获取水印图片的绝对路径。
  2. 创建目录涉及到了文件类File,判断目录是否存在,不存在则创建。
  3. 以当前年月日小时分钟秒+五位随机数来作为新文件名,涉及到了日期时间格式化的SimpleDateFormat类和生成随机数的Random类。
  4. 用String的substring 方法截取下标为lastIndexOf(".")后的字符串。
  5. 拼接好了目标文件的绝对路径,开始进行图片处理。

四、用Thumbnailator处理图片

(1)简介

在博客开始我就提到了Thumbnailator这个类库。Thumbnailator是一个用来生成图像缩略图的Java类库,简化了缩略过程,两三行代码就能够从现有图片生成缩略图。支持根据一个目录批量生成缩略图,支持图片缩放,区域裁剪,水印,旋转,保持比例等等功能。

(2)主要功能

  • 从原图创建高质量的缩略图
  • 缩略图中嵌入水印(如logo)
  • 嵌入的水印可以调整透明度从0%到100%
  • 支持缩略图旋转
  • 流畅的接口简化了生成缩略图的编程过程
  • 多种缩略图质量模式选择
  • 可以保存缩略图的长宽比

(3)在项目中使用

  1. 添加依赖
    <dependency>
    	<groupId>net.coobird</groupId>
    	<artifactId>thumbnailator</artifactId>
    	<version>0.4.8</version>
    </dependency>
    
  2. 代码示例
    			//图片路径
    Thumbnails.of(thumbnail.getImage())
    				//图片大小
    				.scale(0.7f)
                    //添加水印
                    .watermark(Positions.BOTTOM_RIGHT,//水印位置---右下
                   		//水印路径,水印透明度
                        ImageIO.read(new File(basePath + "watermark.png")), 1.0f)
                    				//输出到目标文件
                    				.toFile(dest);
    
    Thumbnails.of() 这个方法可以传入一个文件也可以传入一个文件流。
    scale() 方法是缩放的倍数。
    watermark() 方法分别可以设置水印图的位置,水印图片的绝对路径,透明度。
    toFile() 方法是目标文件路径。
  3. 效果展示
    水印图:
    在这里插入图片描述
    添加水印图后的店铺缩略图:
    在这里插入图片描述

(4)具体场景

以下参考自:https://rensanning.iteye.com/blog/1545708 侵删~

  1. 指定大小进行缩放

    //size(宽度, 高度)
     
    /*
     * 若图片横比200小,高比300小,不变
     * 若图片横比200小,高比300大,高缩小到300,图片比例不变
     * 若图片横比200大,高比300小,横缩小到200,图片比例不变
     * 若图片横比200大,高比300大,图片按比例缩小,横为200或高为300
     */
    Thumbnails.of("image.jpg")
    	.size(200, 300)
    	.toFile("newImage.jpg");
    
  2. 按照比例进行缩放

    //scale(比例)
     
    Thumbnails.of("image.jpg")
    	.scale(1.10f)
    	.toFile("newImage.jpg");
    
  3. 旋转

    //rotate(角度) 正数:顺时针 负数:逆时针
    Thumbnails.of("image.jpg")
    	.size(1280,1024)
    	.rotate(90)
    	.toFile("newImage1.jpg");
     
    Thumbnails.of("image.jpg")
    	.size(1280,1024)
    	.rotate(-90)
    	.toFile("newImage2.jpg");
    
  4. 水印

    //watermark(位置,水印图,透明度)
    Thumbnails.of("image.jpg")
    	.size(1280,1024)
    	.watermark(Positions.CENTER,ImageIO.read(newFile("watermark.png")),0.5f)
    	.outputQuality(0.8f)
    	.toFile("newImage.jpg");
    

    压缩图片文件大小outputQuality实现,参数1为最高质量

  5. 裁剪

    //sourceRegion()
     
    //图片中心400*400的区域
    Thumbnails.of("image.jpg")
    	.sourceRegion(Positions.CENTER,400,400)
    	.size(200,200)
    	.keepAspectRatio(false)
    	.toFile("newImage1.jpg");
     
    //图片右下400*400的区域
    Thumbnails.of("image.jpg")
    	.sourceRegion(Positions.BOTTOM_RIGHT,400,400)
    	.size(200,200)
    	.keepAspectRatio(false)
    	.toFile("newImage2.jpg");
     
    //指定坐标
    Thumbnails.of("image.jpg")
    	.sourceRegion(600,500,400,400)
    	.size(200,200)
    	.keepAspectRatio(false)
    	.toFile("newImage3.jpg");
    
  6. 转化图像格式

    //outputFormat(图像格式)
    Thumbnails.of("image.jpg")
    	.size(1280,1024)
    	.outputFormat("png")
    	.toFile("newImage1.png");
    
    Thumbnails.of("image.jpg")
    	.size(1280,1024)
    	.outputFormat("gif")
    	.toFile("newImage2.gif");
    
  7. 输出到OutputStream

    //toOutputStream(流对象)
    OutputStreamos = newFileOutputStream("newImageOutputStream.png");
    Thumbnails.of("image.jpg")
    	.size(1280,1024)
    	.toOutputStream(os);
    
  8. 输出到BufferedImage

    //asBufferedImage()返回BufferedImage
    BufferedImage thumbnail = Thumbnails.of("image.jpg")
    										.size(1280,1024)
    										.asBufferedImage();
    ImageIO.write(thumbnail,"jpg",newFile("newImageBufferedImage.jpg"));
    

更多方法使用详情可查看API:https://coobird.github.io/thumbnailator/javadoc/0.4.8/

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确性。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值