java

Get几个非常实用技能——常用文件操作工具类、图片视频操作

Nick · 3月15日 · 2021年本文19739字 · 阅读50分钟200

文件工具类

导入坐标:

<!--工具包-->
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-all</artifactId>
            <version>${hutool.version}</version>
        </dependency>
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>

工具类中的方法
1. toFile:MultipartFile转File
参数:MultipartFile multipartFile
2. getExtensionName:获取文件扩展名,不带 .
参数:String filename
3. getFileNameNoEx:Java文件操作 获取不带扩展名的文件名
参数:String filename
4. getSize:文件大小转换
参数:long size
5. inputStreamToFile:inputStream 转 File
参数:InputStream ins, String name
6. upload:将文件名解析成文件的上传路径
MultipartFile file, String filePath
7. downloadExcel:导出excel
参数:List<Map<String, Object>> list, HttpServletResponse response
8. getFileType:获取文件类型
参数:String type
9. getTransferFileType:获取文件类型英文名
参数:String type
10. checkSize:检测文件是否超出允许范围
参数:long maxSize, long size
11. check:判断两个文件是否相同
参数:File file1, File file2
12. getByte:获取文件字节长度
参数:File file
13. getMd5:将字节数组转换为16进制字符
参数:byte[] bytes
14. downloadFile:下载文件
参数:HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit

代码如下:

/*
 *  Copyright 2019-2020 Zheng Jie
 *
 *  Licensed under the Apache License, Version 2.0 (the "License");
 *  you may not use this file except in compliance with the License.
 *  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 *  Unless required by applicable law or agreed to in writing, software
 *  distributed under the License is distributed on an "AS IS" BASIS,
 *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *  See the License for the specific language governing permissions and
 *  limitations under the License.
 */
package com.team.utils;

import cn.hutool.core.io.IoUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.poi.excel.BigExcelWriter;
import cn.hutool.poi.excel.ExcelUtil;
import com.team.exception.BadRequestException;
import org.apache.poi.util.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.multipart.MultipartFile;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.security.MessageDigest;
import java.text.DecimalFormat;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * File工具类,扩展 hutool 工具包
 *
 */
public class FileUtil extends cn.hutool.core.io.FileUtil {
    private static final Logger log = LoggerFactory.getLogger(FileUtil.class);
    /**
     * 系统临时目录
     * <br>
     * windows 包含路径分割符,但Linux 不包含,
     * 在windows \\==\ 前提下,
     * 为安全起见 同意拼装 路径分割符,
     * <pre>
     *       java.io.tmpdir
     *       windows : C:\Users/xxx\AppData\Local\Temp\
     *       linux: /temp
     * </pre>
     */
    public static final String SYS_TEM_DIR = System.getProperty("java.io.tmpdir") + File.separator;
    /**
     * 定义GB的计算常量
     */
    private static final int GB = 1024 * 1024 * 1024;
    /**
     * 定义MB的计算常量
     */
    private static final int MB = 1024 * 1024;
    /**
     * 定义KB的计算常量
     */
    private static final int KB = 1024;

    /**
     * 格式化小数
     */
    private static final DecimalFormat DF = new DecimalFormat("0.00");

    /**
     * MultipartFile转File
     */
    public static File toFile(MultipartFile multipartFile) {
        // 获取文件名
        String fileName = multipartFile.getOriginalFilename();
        // 获取文件后缀
        String prefix = "." + getExtensionName(fileName);
        File file = null;
        try {
            // 用uuid作为文件名,防止生成的临时文件重复
            file = File.createTempFile(IdUtil.simpleUUID(), prefix);
            // MultipartFile to File
            multipartFile.transferTo(file);
        } catch (IOException e) {
            log.error(e.getMessage(), e);
        }
        return file;
    }

    /**
     * 获取文件扩展名,不带 .
     */
    public static String getExtensionName(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length() - 1))) {
                return filename.substring(dot + 1);
            }
        }
        return filename;
    }

    /**
     * Java文件操作 获取不带扩展名的文件名
     */
    public static String getFileNameNoEx(String filename) {
        if ((filename != null) && (filename.length() > 0)) {
            int dot = filename.lastIndexOf('.');
            if ((dot > -1) && (dot < (filename.length()))) {
                return filename.substring(0, dot);
            }
        }
        return filename;
    }

    /**
     * 文件大小转换
     */
    public static String getSize(long size) {
        String resultSize;
        if (size / GB >= 1) {
            //如果当前Byte的值大于等于1GB
            resultSize = DF.format(size / (float) GB) + "GB   ";
        } else if (size / MB >= 1) {
            //如果当前Byte的值大于等于1MB
            resultSize = DF.format(size / (float) MB) + "MB   ";
        } else if (size / KB >= 1) {
            //如果当前Byte的值大于等于1KB
            resultSize = DF.format(size / (float) KB) + "KB   ";
        } else {
            resultSize = size + "B   ";
        }
        return resultSize;
    }

    /**
     * inputStream 转 File
     */
    static File inputStreamToFile(InputStream ins, String name) throws Exception {
        File file = new File(SYS_TEM_DIR + name);
        if (file.exists()) {
            return file;
        }
        OutputStream os = new FileOutputStream(file);
        int bytesRead;
        int len = 8192;
        byte[] buffer = new byte[len];
        while ((bytesRead = ins.read(buffer, 0, len)) != -1) {
            os.write(buffer, 0, bytesRead);
        }
        os.close();
        ins.close();
        return file;
    }

    /**
     * 将文件名解析成文件的上传路径
     */
    public static File upload(MultipartFile file, String filePath) {
        Date date = new Date();
        SimpleDateFormat format = new SimpleDateFormat("yyyyMMddhhmmssS");
        String name = getFileNameNoEx(file.getOriginalFilename());
        String suffix = getExtensionName(file.getOriginalFilename());
        String nowStr = "-" + format.format(date);
        try {
            String fileName = name + nowStr + "." + suffix;
            String path = filePath + fileName;
            // getCanonicalFile 可解析正确各种路径
            File dest = new File(path).getCanonicalFile();
            // 检测是否存在目录
            if (!dest.getParentFile().exists()) {
                if (!dest.getParentFile().mkdirs()) {
                    System.out.println("was not successful.");
                }
            }
            // 文件写入
            file.transferTo(dest);
            return dest;
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 导出excel
     */
    public static void downloadExcel(List<Map<String, Object>> list, HttpServletResponse response) throws IOException {
        String tempPath = SYS_TEM_DIR + IdUtil.fastSimpleUUID() + ".xlsx";
        File file = new File(tempPath);
        BigExcelWriter writer = ExcelUtil.getBigWriter(file);
        // 一次性写出内容,使用默认样式,强制输出标题
        writer.write(list, true);
        //response为HttpServletResponse对象
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=utf-8");
        //test.xls是弹出下载对话框的文件名,不能为中文,中文请自行编码
        response.setHeader("Content-Disposition", "attachment;filename=file.xlsx");
        ServletOutputStream out = response.getOutputStream();
        // 终止后删除临时文件
        file.deleteOnExit();
        writer.flush(out, true);
        //此处记得关闭输出Servlet流
        IoUtil.close(out);
    }

    public static String getFileType(String type) {
        String documents = "txt pdf pps wps doc docx ppt pptx xls xlsx";
        String music = "mp3 wav wma mpa ram ra aac aif m4a";
        String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
        String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
        if (image.contains(type)) {
            return "图片";
        } else if (documents.contains(type)) {
            return "文档";
        } else if (music.contains(type)) {
            return "音乐";
        } else if (video.contains(type)) {
            return "视频";
        } else {
            return "其他";
        }
    }

    public static String getTransferFileType(String type) {
        String documents = "txt pdf pps wps doc docx ppt pptx xls xlsx";
        String music = "mp3 wav wma mpa ram ra aac aif m4a";
        String video = "avi mpg mpe mpeg asf wmv mov qt rm mp4 flv m4v webm ogv ogg";
        String image = "bmp dib pcp dif wmf gif jpg tif eps psd cdr iff tga pcd mpt png jpeg";
        if (image.contains(type)) {
            return "image";
        } else if (documents.contains(type)) {
            return "documents";
        } else if (music.contains(type)) {
            return "music";
        } else if (video.contains(type)) {
            return "video";
        } else {
            return "other";
        }
    }

    public static void checkSize(long maxSize, long size) {
        // 1M
        int len = 1024 * 1024;
        if (size > (maxSize * len)) {
            throw new BadRequestException("文件超出规定大小");
        }
    }

    /**
     * 判断两个文件是否相同
     */
    public static boolean check(File file1, File file2) {
        String img1Md5 = getMd5(file1);
        String img2Md5 = getMd5(file2);
        return img1Md5.equals(img2Md5);
    }

    /**
     * 判断两个文件是否相同
     */
    public static boolean check(String file1Md5, String file2Md5) {
        return file1Md5.equals(file2Md5);
    }

    private static byte[] getByte(File file) {
        // 得到文件长度
        byte[] b = new byte[(int) file.length()];
        try {
            InputStream in = new FileInputStream(file);
            try {
                System.out.println(in.read(b));
            } catch (IOException e) {
                log.error(e.getMessage(), e);
            }
        } catch (FileNotFoundException e) {
            log.error(e.getMessage(), e);
            return null;
        }
        return b;
    }

    private static String getMd5(byte[] bytes) {
        // 16进制字符
        char[] hexDigits = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
        try {
            MessageDigest mdTemp = MessageDigest.getInstance("MD5");
            mdTemp.update(bytes);
            byte[] md = mdTemp.digest();
            int j = md.length;
            char[] str = new char[j * 2];
            int k = 0;
            // 移位 输出字符串
            for (byte byte0 : md) {
                str[k++] = hexDigits[byte0 >>> 4 & 0xf];
                str[k++] = hexDigits[byte0 & 0xf];
            }
            return new String(str);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        return null;
    }

    /**
     * 下载文件
     *
     * @param request  /
     * @param response /
     * @param file     /
     */
    public static void downloadFile(HttpServletRequest request, HttpServletResponse response, File file, boolean deleteOnExit) {
        response.setCharacterEncoding(request.getCharacterEncoding());
        response.setContentType("application/octet-stream");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            response.setHeader("Content-Disposition", "attachment; filename=" + file.getName());
            IOUtils.copy(fis, response.getOutputStream());
            response.flushBuffer();
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                    if (deleteOnExit) {
                        file.deleteOnExit();
                    }
                } catch (IOException e) {
                    log.error(e.getMessage(), e);
                }
            }
        }
    }

    public static String getMd5(File file) {
        return getMd5(getByte(file));
    }

}

获取图片响应流操作

流操作
传入参数:
1. src:本地图片路径
2. response:HttpServletResponse对象

/**
     * @param src
     * @param response
     *
     */
    //获取图片
    public static void getImageSteam(String src, HttpServletResponse response) {

        File file = new File(src);
        //System.out.println("文件名---" + file.getName());

        //获取文件后缀名
        String extensionName = FileUtil.getExtensionName(file.getName());
        //System.out.println("后缀名---" + extensionName);

        //设置响应数据类型(后缀名)
        response.setContentType("image/" + extensionName);
        FileInputStream in = null;
        ServletOutputStream out = null;
        try {
            in = new FileInputStream(file);
            out = response.getOutputStream();
            byte[] bytes = new byte[1024 * 10];
            int len = 0;

            while ((len = in.read(bytes)) != -1) {
                out.write(bytes, 0, len);
            }
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
 /**
     * @param fileName
     * @param response 获取图片的方法
     */
    @GetMapping("/getImage")
    @AnonymousAccess
    @Transactional
    public void getImage(@RequestParam String fileName, HttpServletResponse response) {
        System.out.println("文件名---" + fileName);
        FeedbackImages image = feedbackService.findImageByName(fileName);
        String src = image.getSrc();
        System.out.println("文件路径---" + src);

        /*使用ImageUtil的封装方法*/
        ImageUtil.getImageSteam(src, response);
    }

获取视频响应流操作

传入参数:
1. src:本地图片路径
2. response:HttpServletResponse对象

/**
     * @param src
     * @param response
     *
     */
    //获取视频文件
    public static void getImageSteam(String src, HttpServletResponse response) {

        File file = new File(src);
        //System.out.println("文件名---" + file.getName());

        //获取文件后缀名
        String extensionName = FileUtil.getExtensionName(file.getName());
        //System.out.println("后缀名---" + extensionName);

        //设置响应数据类型(后缀名)
        response.setContentType("video/" + extensionName);
        FileInputStream in = null;
        ServletOutputStream out = null;

        try {
            in = new FileInputStream(file);
            out = response.getOutputStream();
            byte[] bytes = new byte[1024 * 10];
            int len = 0;

            while ((len = in.read(bytes)) != -1) {
                out.write(bytes, 0, len);
            }
            out.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                in.close();
                out.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
/**
     * @param fileName
     * @param response 获取视频的方法
     */
    @GetMapping("/getVideo")
    @AnonymousAccess
    @Transactional
    public void getVideo(@RequestParam String fileName, HttpServletRequest request, HttpServletResponse response) throws UnsupportedEncodingException {

        response.setHeader("Content-Type", "video/mp4");

        System.out.println("文件名---" + fileName);
        FeedbackImages image = feedbackService.findImageByName(fileName);
        String src = image.getSrc();
        System.out.println("文件路径---" + src);

        /*使用ImageUtil的封装方法*/
        ImageUtil.getVideoSteam(src, response);
    }

获取视频响应流(断点传输)

特别注意:如果使用上述的方法直接对视频进行流传输,会出现一个问题:在前端使用video标签读取视频时,视频无法拖动进度条,只能一直从头播放到尾,缺少了断点续传。(移动端好像不会)
因此在响应视频的文件流时,需要对文件进行字节切割,实现单点续传。

传入参数:
src:本地图片路径
response:HttpServletResponse对象

 //获取视频
    public static void getVideoSteam(String src, HttpServletRequest request, HttpServletResponse response) {
    BufferedInputStream bis = null;
        try {
            File file = new File(src);
            if (file.exists()) {
                long p = 0L;
                long toLength = 0L;
                long contentLength = 0L;
                int rangeSwitch = 0; // 0,从头开始的全文下载;1,从某字节开始的下载(bytes=27000-);2,从某字节开始到某字节结束的下载(bytes=27000-39000)
                long fileLength;
                String rangBytes = "";
                fileLength = file.length();

                // get file content
                InputStream ins = new FileInputStream(file);
                bis = new BufferedInputStream(ins);

                // tell the client to allow accept-ranges
                response.reset();
                response.setHeader("Accept-Ranges", "bytes");

                // client requests a file block download start byte
                String range = request.getHeader("Range");
                if (range != null && range.trim().length() > 0 && !"null".equals(range)) {
                    response.setStatus(javax.servlet.http.HttpServletResponse.SC_PARTIAL_CONTENT);
                    rangBytes = range.replaceAll("bytes=", "");
                    if (rangBytes.endsWith("-")) { // bytes=270000-
                        rangeSwitch = 1;
                        p = Long.parseLong(rangBytes.substring(0, rangBytes.indexOf("-")));
                        contentLength = fileLength - p; // 客户端请求的是270000之后的字节(包括bytes下标索引为270000的字节)
                    } else { // bytes=270000-320000
                        rangeSwitch = 2;
                        String temp1 = rangBytes.substring(0, rangBytes.indexOf("-"));
                        String temp2 = rangBytes.substring(rangBytes.indexOf("-") + 1, rangBytes.length());
                        p = Long.parseLong(temp1);
                        toLength = Long.parseLong(temp2);
                        contentLength = toLength - p + 1; // 客户端请求的是 270000-320000 之间的字节
                    }
                } else {
                    contentLength = fileLength;
                }

                // 如果设设置了Content-Length,则客户端会自动进行多线程下载。如果不希望支持多线程,则不要设置这个参数。
                // Content-Length: [文件的总大小] - [客户端请求的下载的文件块的开始字节]
                response.setHeader("Content-Length", new Long(contentLength).toString());

                // 断点开始
                // 响应的格式是:
                // Content-Range: bytes [文件块的开始字节]-[文件的总大小 - 1]/[文件的总大小]
                if (rangeSwitch == 1) {
                    String contentRange = new StringBuffer("bytes ").append(new Long(p).toString()).append("-")
                            .append(new Long(fileLength - 1).toString()).append("/")
                            .append(new Long(fileLength).toString()).toString();
                    response.setHeader("Content-Range", contentRange);
                    bis.skip(p);
                } else if (rangeSwitch == 2) {
                    String contentRange = range.replace("=", " ") + "/" + new Long(fileLength).toString();
                    response.setHeader("Content-Range", contentRange);
                    bis.skip(p);
                } else {
                    String contentRange = new StringBuffer("bytes ").append("0-").append(fileLength - 1).append("/")
                            .append(fileLength).toString();
                    response.setHeader("Content-Range", contentRange);
                }

                String fileName = file.getName();
                response.setContentType("application/octet-stream");
                response.addHeader("Content-Disposition", "attachment;filename=" + fileName);

                OutputStream out = response.getOutputStream();
                int n = 0;
                long readLength = 0;
                int bsize = 1024;
                byte[] bytes = new byte[bsize];
                if (rangeSwitch == 2) {
                    // 针对 bytes=27000-39000 的请求,从27000开始写数据
                    while (readLength <= contentLength - bsize) {
                        n = bis.read(bytes);
                        readLength += n;
                        out.write(bytes, 0, n);
                    }
                    if (readLength <= contentLength) {
                        n = bis.read(bytes, 0, (int) (contentLength - readLength));
                        out.write(bytes, 0, n);
                    }
                } else {
                    while ((n = bis.read(bytes)) != -1) {
                        out.write(bytes, 0, n);
                    }
                }
                out.flush();
                out.close();
                bis.close();
            }
        } catch (IOException ie) {
            // 忽略 ClientAbortException 之类的异常
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

截取视频某帧图片

1、使用工具:ffmpeg,
官网下载地址:http://ffmpeg.org/download.html
自己提供的下载地址:
链接:https://pan.baidu.com/s/1x03SItqFfhl0LHGypxDqRA
提取码:obun

测试:
进入含有ffmpeg.exe的bin目录(也可以配置环境变量)
ffmpeg -i xxx.mp4 -y -f image2 -t 0.001 -s 125×125 xxx.jpg
运行成功后,将截取xxx.mp4的第0.0001秒的图片生成125*125的xxx.jpg图片
注意视频、图片名称要带路径,否则当前目录
其他f fmpeg 工具命令可以参考:https://blog.csdn.net/YZ099/article/details/108082980

使用java编写代码实现
获取成功返回true,获取失败返回false
传入参数:
1. ffmpegPath:ffmpeg.exe存放的路径
2. path:视频文件的存放路径
3. outImagePath:输出缩略图的保存路径

 /**
     * 获得视频缩略图,获取成功返回true,获取失败返回false
     *
     * @param ffmpegPath   是ffmpeg.exe存放的路径
     * @param path         是视频文件的存放路径
     * @param outImagePath 输出缩略图的保存路径
     * @return
     */
    public static boolean SaveVideoThumbnail(String ffmpegPath, String path, String outImagePath) throws Exception {
        boolean flag = true;
        try {
            File file = new File(path);
            if (!file.exists()) {    //判断视频文件是否存在
                return false;
            }
            //设置参数
            List<String> commands = new java.util.ArrayList<String>();
            commands.add(ffmpegPath);//这里设置ffmpeg.exe存放的路径
            commands.add("-i");
            commands.add(path);//这里是设置要截取缩略图的视频的路径
            commands.add("-y");
            commands.add("-f");
            commands.add("image2");
            commands.add("-ss");
            commands.add("1");//这里设置的是要截取视频开始播放多少秒后的图,可以自己设置时间
            commands.add("-t");
            commands.add("0.001");
            //commands.add("-s");
            //commands.add("660x660");//这里设置输出图片的大小
            commands.add(outImagePath);//这里设置输出的截图的保存路径
            //截取缩略图并保存
            ProcessBuilder builder = new ProcessBuilder();
            builder.command(commands);
            builder.start();
        } catch (Exception e) {
            e.printStackTrace();
            flag = false;
            System.out.println("获取视频缩略图失败");
        }
        return flag;
    }

在获取的视频缩略图中间添加暂停按钮

思路:使用java GPU绘图工具Graphics2D,先将截取的视频图片绘画出来,然后再获取该图片的正中间位置,接着绘画出准备好的暂停按钮的图标图片,最后使用文件流导出图片。

传入参数:
1. bigPath:大图片的路径
2. smallPath:小图片的路径

/**
     * 在获取的视频缩略图中间添加暂停按钮
     *
     * @param bigPath
     * @param smallPath
     * @throws IOException
     */
    public static void mergeImage(String bigPath, String smallPath) throws IOException {

        try {
            BufferedImage small;
            BufferedImage big = ImageIO.read(new File(bigPath));
            if (smallPath.contains("http")) {

                URL url = new URL(smallPath);
                small = ImageIO.read(url);
            } else {
                small = ImageIO.read(new File(smallPath));
            }

            Graphics2D g = big.createGraphics();

            int width = big.getWidth() - small.getWidth();
            int height = big.getHeight() - small.getHeight();
            float fx = width / 2;
            float fy = height / 2;
            int x_i = (int) fx;
            int y_i = (int) fy;
//            g.drawImage(small, x_i, y_i, small.getWidth(), small.getHeight(), null);
            g.drawImage(small, x_i, y_i, null);
            g.dispose();
            ImageIO.write(big, "png", new File(bigPath));

        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行结果输出的图片
在这里插入图片描述

压缩图片

压缩一般分为三种情况:
1. 按图片的比例进行压缩
2. 直接设置图片压缩后的输出大小进行压缩
3. 按设置宽高对图片进行压缩

1. 按图片的比例进行压缩

思路:获取传进来的图片,获取该图片的宽高,计算出比例,然后根据传进来的要压缩结果宽度/比例得到要压缩结果的高度,接着按照要压缩结果的宽高进行对图片进行压缩,最后文件流输出图片。

传入参数:
1. srcImgPath:原图片路径
2. distImgPath: 转换大小后图片路径
3. width0:压缩结果的目标宽度

 /***
     * 功能 :调整图片大小
     * @param srcImgPath 原图片路径
     * @param distImgPath  转换大小后图片路径
     * @param width0  按比例压缩图片,压缩后宽度为width0
     */
    public static void resizeImage(String srcImgPath, String distImgPath,
                                   int width0) throws IOException {

        File srcFile = new File(srcImgPath);
        Image srcImg = ImageIO.read(srcFile);
        BufferedImage buffImg = null;
        float width = ((BufferedImage) srcImg).getWidth();
        float height = ((BufferedImage) srcImg).getHeight();
        float scale = width / height;
        int height0 = (int) (width0 / scale);
        System.out.println(scale + ":" + width0 + "---" + height0);
        buffImg = new BufferedImage(width0, height0, BufferedImage.TYPE_INT_RGB);
        buffImg.getGraphics().drawImage(
                srcImg.getScaledInstance(width0, height0, Image.SCALE_SMOOTH), 0,
                0, null);

        ImageIO.write(buffImg, "JPG", new File(distImgPath));

    }


    public static void main(String[] args) {
        try {
            resizeImage("D:\\projects\\TS_Admin\\trunk\\team-system\\src\\main\\resources\\static\\images\\pause.png", "D:\\projects\\TS_Admin\\trunk\\team-system\\src\\main\\resources\\static\\images\\pause_100_100.png", 100);
        } catch (IOException e) {
            System.out.println("图片转换出现异常!");
        }

    }

2. 直接设置图片压缩后的输出大小进行压缩

传入参数:
1. imageBytes:源图片字节数组
2. desFileSize: 指定图片大小,单位kb
3. imageId:影像编号
return: 压缩质量后的图片字节数组

代码如下:

/**
 * Created by tao.
 * Date: 2021/3/12 17:45
 * 描述:
 */

public class PicUtils {

    private static Logger logger = LoggerFactory.getLogger(PicUtils.class);

    public static void main(String[] args) throws IOException {
        byte[] bytes = FileUtils.readFileToByteArray(new File("C:\\teamadmin\\file\\图片\\3a6372e3cfefec8144de4fc0585105dd.jpg"));
        long l = System.currentTimeMillis();
        bytes = PicUtils.compressPicForScale(bytes, 50, "x");// 图片小于300kb
        System.out.println(System.currentTimeMillis() - l);
        FileUtils.writeByteArrayToFile(new File("C:\\teamadmin\\file\\图片\\3a6372e3cfefec8144de4fc0585105dd.jpg"), bytes);
    }

    /**
     * 根据指定大小压缩图片
     *
     * @param imageBytes  源图片字节数组
     * @param desFileSize 指定图片大小,单位kb
     * @param imageId     影像编号
     * @return 压缩质量后的图片字节数组
     */
    public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize, String imageId) {
        if (imageBytes == null || imageBytes.length <= 0 || imageBytes.length < desFileSize * 1024) {
            return imageBytes;
        }
        long srcSize = imageBytes.length;
        double accuracy = getAccuracy(srcSize / 1024);
        try {
            while (imageBytes.length > desFileSize * 1024) {
                ByteArrayInputStream inputStream = new ByteArrayInputStream(imageBytes);
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream(imageBytes.length);
                Thumbnails.of(inputStream)
                        .scale(accuracy)
                        .outputQuality(accuracy)
                        .toOutputStream(outputStream);
                imageBytes = outputStream.toByteArray();
            }
            logger.info("【图片压缩】imageId={} | 图片原大小={}kb | 压缩后大小={}kb",
                    imageId, srcSize / 1024, imageBytes.length / 1024);
        } catch (Exception e) {
            logger.error("【图片压缩】msg=图片压缩失败!", e);
        }
        return imageBytes;
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @param size 源图片大小
     * @return 图片压缩质量比
     */
    private static double getAccuracy(long size) {
        double accuracy;
        if (size < 900) {
            accuracy = 0.85;
        } else if (size < 2047) {
            accuracy = 0.6;
        } else if (size < 3275) {
            accuracy = 0.44;
        } else {
            accuracy = 0.4;
        }
        return accuracy;
    }
}

3. 按设置宽高对图片进行压缩

传入参数:
1. srcImgPath:原图片路径
2. distImgPath: 转换大小后图片路径
3. width:压缩结果的目标宽度
4. height:压缩结果的目标高度

/***
     * 功能 :调整图片大小
     * @param srcImgPath 原图片路径
     * @param distImgPath  转换大小后图片路径
     */
    public static void resizeImage(String srcImgPath, String distImgPath,
                                   int width,int height) throws IOException {

        File srcFile = new File(srcImgPath);
        Image srcImg = ImageIO.read(srcFile);
        BufferedImage buffImg = null;
        buffImg = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        buffImg.getGraphics().drawImage(
                srcImg.getScaledInstance(width, height, Image.SCALE_SMOOTH), 0,
                0, null);
        ImageIO.write(buffImg, "JPG", new File(distImgPath));
    }

压缩结果
在这里插入图片描述

0 条回应
在线人数:1人
隐藏