天天看点

Java图片压缩大小,图片缩放

添加依赖

<!-- 图片缩略图 -->
            <dependency>
                <groupId>net.coobird</groupId>
                <artifactId>thumbnailator</artifactId>
                <version>0.4.8</version>
            </dependency>
           

Java压缩图片案例1

部分后缀图片会出现压缩失败

//压缩至范围(50 压缩到50KB)
    @Value(value = "${jeecg.path.image-comprssion-to}")
    private Integer imageComprssionTo;

    //上传文件路径(win D://opt//upFiles Linux /tang/upload)
    @Value(value = "${jeecg.path.upload}")
    private String uploadpath;

    @Override
    @Transactional(rollbackFor = Throwable.class)
    public AiFileStorage uploadZip(String fileName) {
        String originalFilename = "";//文件名称
        String filePatha = uploadpath;
        String filePathaBackup = uploadpath;
        AiFileStorage aiFileStorage = new AiFileStorage();
        try {
            File addFile = new File(filePatha);
            if (!addFile.exists()) {
                addFile.mkdirs();
            }
            String findFfilePatha = filePatha + "/" + fileName;
            File file = new File(findFfilePatha);
            File savefile;
            //服务器上相同名称的文件,后面拼接 _compress + i
            int i = -1;
            do {
                i++;
                savefile = new File(filePatha + "/" + fileName.substring(0, fileName.lastIndexOf(".")) + "_compress" + (i == 0 ? "" : i)+ fileName.substring(fileName.indexOf(".")));
                originalFilename = fileName.substring(0, fileName.lastIndexOf(".")) + "_compress" + (i == 0 ? "" : i) + fileName.substring(fileName.indexOf("."));
            } while (savefile.exists());


            filePatha += "/" + originalFilename;//绝对路径
            filePathaBackup += "/" + fileName;//源文件
            log.info("地址:" + filePatha);
            log.info("文件大小:" + new BigDecimal((double)file.length()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP)+"M");
            log.info("文件名" + originalFilename);

            BigDecimal a = new BigDecimal((double)file.length()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP);
            Integer productCode = imageComprssionTo;//图片压缩范围 超出的压缩
            BigDecimal b = new BigDecimal(StringUtils.getM(productCode));
            File file_b = new File(filePatha);
            if(a.compareTo(b) == 1){//a大于b,压缩图片 a 源文件大小 b 压缩至大小
                //压缩图片
                File file_c = new File(filePathaBackup);
                Files.copy(file.toPath(),file_b.toPath());
                Files.copy(file.toPath(),file_c.toPath());
                ImageTool.compress("file:" + filePathaBackup,productCode,file_b.getAbsolutePath());
            }else{
                Files.copy(file.toPath(),file_b.toPath());
            }

            aiFileStorage.setCreateTime(new Timestamp(System.currentTimeMillis()));
            aiFileStorage.setSize(file_b.length()/ 1024+" KB");
            aiFileStorage.setType(2);
            aiFileStorage.setSuffix(FileUtil.getExtensionName(file_b.getName()));
            aiFileStorage.setName(file_b.getName());
            aiFileStorage.setUrl(originalFilename);
            aiFileStorageService.save(aiFileStorage);
            return aiFileStorage;
        } catch (NoSuchFileException e) {
            e.printStackTrace();
            throw new BadRequestException("文件不存在");
        }  catch (IOException e) {
            e.printStackTrace();
        }
        return new AiFileStorage();
    }
           

文件记录实体类

package org.jeecg.modules.ai.entity;

import java.io.Serializable;
import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.math.BigDecimal;
import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import com.baomidou.mybatisplus.annotation.TableName;
import lombok.Data;
import com.fasterxml.jackson.annotation.JsonFormat;
import org.springframework.format.annotation.DateTimeFormat;
import org.jeecgframework.poi.excel.annotation.Excel;
import io.swagger.annotations.ApiModel;
import io.swagger.annotations.ApiModelProperty;
import lombok.EqualsAndHashCode;
import lombok.experimental.Accessors;

/**
 * @Description: 文件存储
 * @Date:   2021-01-13
 * @Version: V1.0
 */
@Data
@TableName("ai_file_storage")
@Accessors(chain = true)
@EqualsAndHashCode(callSuper = false)
@ApiModel(value="ai_file_storage对象", description="文件存储")
public class AiFileStorage implements Serializable {
    private static final long serialVersionUID = 1L;

	/**主键*/
	@TableId(type = IdType.ASSIGN_ID)
    @ApiModelProperty(value = "主键")
    private String id;
	/**创建人*/
    @ApiModelProperty(value = "创建人")
    private String createBy;
	/**上传或同步的时间*/
	@JsonFormat(timezone = "GMT+8",pattern = "yyyy-MM-dd HH:mm:ss")
    @DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss")
    @ApiModelProperty(value = "上传或同步的时间")
    private Date createTime;
	/**文件名称*/
	@Excel(name = "文件名称", width = 15)
    @ApiModelProperty(value = "文件名称")
    private String name;
	/**文件大小*/
	@Excel(name = "文件大小", width = 15)
    @ApiModelProperty(value = "文件大小")
    private String size;
	/**文件类型:私有或公开(1,私 2.共)*/
	@Excel(name = "文件类型:私有或公开(1,私 2.共)", width = 15)
    @ApiModelProperty(value = "文件类型:私有或公开(1,私 2.共)")
    private Integer type;
	/**文件url*/
	@Excel(name = "文件url", width = 15)
    @ApiModelProperty(value = "文件url")
    private String url;
	/**文件后缀*/
	@Excel(name = "文件后缀", width = 15)
    @ApiModelProperty(value = "文件后缀")
    private String suffix;
}
           

FileUtil工具类

package org.jeecg.modules.ai.utils;

import cn.hutool.core.util.IdUtil;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.text.DecimalFormat;

/**
 * File工具类,扩展 hutool 工具包
 * @author 亿校云
 * @date 2018-12-27
 */
public class FileUtil extends cn.hutool.core.io.FileUtil {

    /**
     * 定义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
     * @param multipartFile
     * @return
     */
    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) {
            e.printStackTrace();
        }
        return file;
    }

    /**
     * 删除
     * @param files
     */
    public static void deleteFile(File... files) {
        for (File file : files) {
            if (file.exists()) {
                file.delete();
            }
        }
    }

    /**
     * 获取文件扩展名
     * @param filename
     * @return
     */
    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文件操作 获取不带扩展名的文件名
     * @param filename
     * @return
     */
    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;
    }

    /**
     * 文件大小转换
     * @param size
     * @return
     */
    public static String getSize(int 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;
    }
}
           

Java压缩图片案例2

把图片转换成流文件

需要再添加个依赖

<dependency>
    <groupId>commons-io</groupId>
    <artifactId>commons-io</artifactId>
    <version>2.5</version>
</dependency>
           

ImageTool工具类

package me.zhengjie.utils;

import net.coobird.thumbnailator.Thumbnails;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;

import javax.imageio.stream.FileImageOutputStream;
import java.io.*;
import java.net.URL;

/**
 *  图片处理类
 *
 * @author honghe
 */
public class ImageTool {

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

    private static final long DEFAULT_SIZE = 200 * 1024;


    /*public static void main(String[] args) {
        String picUrl = "C:/Users/admin/Desktop/url/picture/═╝╞м20.png";
        compress(picUrl,50);
    }*/

    /**
     * @param picUrl 图片地址
     * @param desFileSize 压缩大小
     */
    public static byte[] compress(String picUrl, long desFileSize,String fileNameCopy) {
        try {
            URL url = new URL(picUrl);
            byte[] imageBytes = IOUtils.toByteArray(url);
            if (imageBytes == null || imageBytes.length <= 0) {
                logger.error("图片资源加载失败,请检查链接地址!url:" + picUrl);
                throw new RuntimeException("图片资源加载失败,请检查链接地址!url:" + picUrl);
            }
            if (imageBytes.length <= desFileSize * 1024) {
                return imageBytes;
            }
            byte[] imageBytesCopy = imageBytes;
            double accuracy = getAccuracy(imageBytes.length / 1024);
            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("【图片压缩】 | 图片原大小={}kb | 压缩后大小={}kb | url={}",
                    imageBytesCopy.length / 1024, imageBytes.length / 1024, picUrl);
            File file = new File(fileNameCopy);
            if(!file.exists()) {
                file.createNewFile();
            }
            FileWriter fileWriter =new FileWriter(file);
            fileWriter.write("");
            fileWriter.flush();
            fileWriter.close();

            FileImageOutputStream imageOutput = new FileImageOutputStream(new File(fileNameCopy));
            imageOutput.write(imageBytes, 0, imageBytes.length);
            imageOutput.close();
            return imageBytes;
        } catch (Exception e) {
            logger.error("图片资源加载失败,请检查链接地址!url:" + picUrl);
            throw new RuntimeException("图片资源加载失败,请检查链接地址!url:" + picUrl);
        }
    }

    /**
     * 对图片byte[]进行base64
     */
    public static String base64ByPic(byte[] imageBatys) {
        // 对字节数组Base64编码
        BASE64Encoder encoder = new BASE64Encoder();
        return encoder.encode(imageBatys);
    }

    /**
     * base64字符串转换成图片
     * 对字节数组字符串进行Base64解码并生成图
     *
     * @param imgStr      base64字符串
     * @param imgFilePath 图片存放路径
     * @dateTime 2018-02-23 14:42:17
     */
    public static boolean Base64ToImage(String imgStr, String imgFilePath) throws IOException {
        OutputStream out = null;
        if (StringUtils.isEmpty(imgStr)) {
            return false;
        }
        BASE64Decoder decoder = new BASE64Decoder();
        try {
            // Base64解码
            byte[] b = decoder.decodeBuffer(imgStr);
            for (int i = 0; i < b.length; ++i) {
                if (b[i] < 0) {// 调整异常数据
                    b[i] += 256;
                }
            }
            out = new FileOutputStream(imgFilePath);
            out.write(b);
            out.flush();
            out.close();
            return true;
        } catch (Exception e) {
            return false;
        } finally {
            if (out != null) {
                out.close();
            }
        }
    }

    /**
     * 自动调节精度(经验数值)
     *
     * @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;
    }
}
           

上传图片Controller和Service

/**
     * 上传图片
     * @param file
     * @return
     * @throws Exception
     */
    @Log("上传图片")
    @PostMapping(value = "/picturesProduct")
    public ResponseEntity picturesProduct(@RequestParam MultipartFile file, String productUrl){
        Picture picture = pictureProductService.uploadZip(file,SecurityUtils.getUsername());
        Map map = new HashMap();
        map.put("errno",0);
        map.put("id",picture.getId());
        map.put("data",new String[]{picture.getUrl()});
        return new ResponseEntity(map,HttpStatus.OK);
    }



   /**
     * 上传图片
     * @param file
     * @param username
     * @return
     */
    @CacheEvict(allEntries = true)
    Picture uploadZip(MultipartFile file, String username);
           

Impl

@Override
    @Transactional(rollbackFor = Throwable.class)
    public Picture uploadZip(MultipartFile file, String username) {
        String originalFilename = "";//文件名称
        String originalFilenameBackup = "";//文件名称备份
        // 文件保存路径
        String filePatha = pictureUrl;
        String filePathaBackup = pictureUrl;
        String urlProduct = "";
        Picture picture = new Picture();
        try {
            File addFile = new File(filePatha);
            if (!addFile.exists()) {
                addFile.mkdirs();
            }
            //如果出现同名文件,文件名后面加随机数
            String findFfilePatha = filePatha + "/" + file.getOriginalFilename();
            File addNameFile = new File(findFfilePatha);
            if (!addNameFile.exists()) {
                originalFilename = FileUtil.getFileNameNoEx(file.getOriginalFilename())+"."+ FileUtil.getExtensionName(file.getOriginalFilename());
                originalFilenameBackup = FileUtil.getFileNameNoEx(file.getOriginalFilename())+"Backup."+ FileUtil.getExtensionName(file.getOriginalFilename());
            }else{
                originalFilename = FileUtil.getFileNameNoEx(file.getOriginalFilename()) + System.currentTimeMillis() +"."+ FileUtil.getExtensionName(file.getOriginalFilename());
                originalFilenameBackup = FileUtil.getFileNameNoEx(file.getOriginalFilename()) + System.currentTimeMillis() +".Backup"+ FileUtil.getExtensionName(file.getOriginalFilename());

            }
            filePatha += "/" + originalFilename;//绝对路径
            filePathaBackup += "/" + originalFilenameBackup;//备份文件
            urlProduct += "/" + originalFilename;//相对路径
            // 转存文件
            log.info("地址:" + filePatha);
            log.info("文件大小:" + new BigDecimal((double)file.getSize()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP)+"M");
            log.info("文件名" + originalFilename);
            File file_a = FileUtil.toFile(file);

            BigDecimal a = new BigDecimal((double)file.getSize()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP);
            BigDecimal b = new BigDecimal (0.3);//超过0.3M的图片进行压缩
            File file_b = new File(filePatha);
            if(a.compareTo(b) == 1){//a大于b,压缩图片
                //压缩图片
                //第一种方法 部分格式图片会压缩失败
                //Thumbnails.of(file_a.getAbsolutePath()).scale(1f).outputQuality(0.25f).toFile(file_b.getAbsolutePath());

                //第二种 流文件
                File file_c = new File(filePathaBackup);//备份数据
                Files.copy(file_a.toPath(),file_c.toPath());//不压缩直接拷贝
                ImageTool.compress("file:" + filePathaBackup,2000,file_b.getAbsolutePath());
                log.info("压缩成功:" + file_b.getAbsolutePath());
            }else{
                Files.copy(file_a.toPath(),file_b.toPath());//不压缩直接拷贝
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        picture.setCreateTime(new Timestamp(System.currentTimeMillis()));
        picture.setSize(new BigDecimal((double)file.getSize()/1024/1024).divide(new BigDecimal(1),2,BigDecimal.ROUND_HALF_UP)+"M");
        picture.setUsername(username);
        picture.setFilename(originalFilename);
        picture.setUrl("/static/picture" + urlProduct);//存本地相对地址
        picture.setDelete(filePatha);
        pictureRepository.save(picture);
        return picture;
    }
           

按指定大小把图片进行缩放(会遵循原图高宽比例)

//按指定大小把图片进行缩和放(会遵循原图高宽比例) 
/此处把图片压成400×500的缩略图
Thumbnails.of(fromPic).size(400,500).toFile(toPic);//变为400*300,遵循原图比例缩或放到400*某个高度
           

按照指定比例进行缩小和放大

//按照比例进行缩小和放大
Thumbnails.of(fromPic).scale(0.2f).toFile(toPic);//按比例缩小
Thumbnails.of(fromPic).scale(2f);//按比例放大
           

按指定的大小进行缩放(不遵循原图比例)

//不按比例,就按指定的大小进行缩放
Thumbnails.of(fromPic).size(100, 100).keepAspectRatio(false).toFile(toPic);
//或者Thumbnails.of(fromPic).forceSize(100,100).toFile(toPic);
           

旋转图片

//旋转图片,rotate(角度),正数则为顺时针,负数则为逆时针
Thumbnails.of(fromPic).size(200,200).rotate(90).toFile(toPic);
           

图片尺寸不变,压缩图片文件大小

//图片尺寸不变,压缩图片文件大小outputQuality实现,参数1为最高质量
Thumbnails.of(fromPic).scale(1f).outputQuality(0.25f).toFile(toPic);
           

给图片加水印

//给图片加水印,watermark(位置,水印图,透明度)Positions.CENTER表示加在中间
Thumbnails.of(fromPic).size(400,400)
	.watermark(Positions.CENTER,ImageIO.read(waterPic),0.5f)
	.outputQuality(0.8f).toFile(toPic);
           

图片裁剪

//用sourceRegion()实现图片裁剪
//图片中心300*300的区域,Positions.CENTER表示中心,还有许多其他位置可选
Thumbnails.of(fromPic).sourceRegion(Positions.CENTER,300,300)
	.size(300,300).toFile(toPic);
           
//图片中上区域300*300的区域
Thumbnails.of(fromPic).sourceRegion(Positions.TOP_CENTER,300,300)
	.size(300,300).toFile(toPic);
           

转换图片格式 

格式由jpg变为png,图片大小没变。

//用outputFormat(图像格式)转换图片格式,保持原尺寸不变
Thumbnails.of(fromPic).scale(1f).outputFormat("png")
	.toFile("picture/png格式的图片.png");
           

输出成文件流OutputStream

//输出成文件流OutputStream
OutputStream os=new FileOutputStream(toPic);
Thumbnails.of(fromPic).size(120,120).toOutputStream(os);
           

输出成BufferedImage

//输出BufferedImage,asBufferedImage()返回BufferedImage
BufferedImage bi=Thumbnails.of(fromPic).size(120,120).asBufferedImage();
ImageIO.write(bi,"jpg",toPic);
           

压缩至指定图片尺寸,保持图片不变形,多余部分裁剪掉

//压缩至指定图片尺寸(例如:横400高300),保持图片不变形,多余部分裁剪掉(这个是引的网友的代码)
		BufferedImage image = ImageIO.read(fromPic);
		Builder<BufferedImage> builder = null;
 
		int imageWidth = image.getWidth();
		int imageHeitht = image.getHeight();
		if ((float)300 / 400 != (float)imageWidth / imageHeitht) {
			if (imageWidth > imageHeitht) {
				image = Thumbnails.of(fromPic).height(300).asBufferedImage();
			} else {
				image = Thumbnails.of(fromPic).width(400).asBufferedImage();
			}
			builder = Thumbnails.of(image).sourceRegion(Positions.CENTER, 400, 300).size(400, 300);
		} else {
			builder = Thumbnails.of(image).size(400, 300);
		}
		builder.outputFormat("jpg").toFile(toPic);
           

参考作者:https://blog.csdn.net/chenleixing/article/details/44685817

Java图片压缩大小,图片缩放