Thumbnails 压缩图片到指定kb

要求:

1.代码简单,运行效率高

2.图片不失真(压缩后依然清晰)

3.能压缩到指定kb值(允许尺寸按参数值缩小)

呵呵:一张3M的图片,要求不缩小宽高 、要求不失真!!! 还想压缩到比较小kb值(比如100kb) ;别往下看了。

 

下文能达到的:
允许按比例缩小宽高,如果达不到100kb,允许图片稍微模糊。

 

添加依赖:

<!-- google图片处理 -->
<dependency>
	    <groupId>net.coobird</groupId>
	    <artifactId>thumbnailator</artifactId>
	    <version>0.4.11</version>
</dependency>

代码

package com.solar.oa.card.util;

import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import javax.imageio.ImageIO;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import net.coobird.thumbnailator.Thumbnails;

/**
 * 图片处理
 * @ClassName: ImageUtil.java
 * @Description: TODO 
 * @date 2020年6月30日 下午2:24:55
 * @author yqwang
 */
public class ImageUtil {
    private final static Logger logger = LoggerFactory.getLogger(ImageUtil.class);

    /**
     * 【压缩图片】到要求的图片标准:  宽[300,500],高[300,500];100kb;jpg/jpeg
     * 先按宽高压缩,压缩后如果还不满足100kb,则按质量递归压缩
     * @Title:compressPhoto
     * @Description: TODO 
     * @date 2020年6月30日 下午2:11:52
     * @author yqwang
     * @param imgFile 源图片文件
     * @param maxkb 目标kb
     * @param photoWidth 目标宽度
     * @param photoHeight 模板高度
     * @param quality 质量
     * @return 处理后的文件byte[]
     * @throws Exception
     */
    public static byte[] compressPhoto(File imgFile,Integer maxkb,Integer photoWidth,Integer photoHeight,Float quality) throws Exception{
        // 1.压缩图片是否存在
        if(imgFile == null || !imgFile.exists()){
            throw new Exception("图片文件不存在。");
        }
        byte[] bytes = readFileToByteArray(imgFile);
        if(bytes == null || bytes.length == 0){
            throw new Exception("图片文件为空。");
        }
        
        // 2.是否超过100kb?没超过就不处理图片
        long fileSize = bytes.length;
        if (fileSize <= maxkb * 1024) {
            logger.info("图片不超过{}kb,无需压缩。",maxkb);
            return bytes;
        }
        
        // 3.压缩到300-500宽高,100kb
        BufferedImage bim = ImageIO.read(new ByteArrayInputStream(bytes));
        int imgWidth = bim.getWidth();
        int imgHeight = bim.getHeight();
        
        // 3.1.先按宽高判断是否需要缩放  outputQuality=1确保画质清晰
        if(imgWidth >= photoWidth && imgHeight >= photoHeight){
            logger.info("先按宽{}高{}压缩。",photoWidth,photoHeight);
            ByteArrayOutputStream out = new ByteArrayOutputStream();//Closing a <tt>ByteArrayOutputStream</tt> has no effect.   因此无需close
            Thumbnails.of(new ByteArrayInputStream(bytes)).size(photoWidth, photoHeight).outputQuality(1).outputFormat("jpg").toOutputStream(out);
            bytes = out.toByteArray();
        }
        // 3.2.判断按宽高缩放后是否超过100kb,超过递归就按质量压缩(图片会变得跟模糊!)
        bytes = compressPhotoByQuality(bytes, quality, maxkb);
        return bytes;
    }
   
    /**
     * 递归按quality质量处理,压缩到maxkb后返回新的bytes值
     * @Title:compressPhotoByQuality
     * @Description: TODO 
     * @date 2020年6月30日 下午2:24:36
     * @author yqwang
     * @param bytes 源文件字节
     * @param quality 压缩质量 (如果为1则不处理)
     * @param maxkb 要求压缩到的最大kb
     * @return
     * @throws IOException
     */
    public static byte[] compressPhotoByQuality(byte[] bytes,Float quality,long maxkb) throws IOException{
        if(bytes == null){
            return bytes;
        }
        logger.info("开始按质量压缩图片({}kb)。",bytes.length/1024);
        // 如果配置的1,则不再处理,多说无益
        if(quality == 1){
            logger.info("quality=1,不执行压缩。");
            return bytes;
        }
        // 满足目标kb值,则返回
        long fileSize = bytes.length;
        if (fileSize <= maxkb * 1024) {
            logger.info("图片文件{}kb<={}kb,不再压缩质量。",fileSize/1024,maxkb);
            return bytes;
        }
        // Closing a <tt>ByteArrayOutputStream</tt> has no effect.   因此无需close
        ByteArrayOutputStream out = null;
        out = new ByteArrayOutputStream();
        BufferedImage bim = ImageIO.read(new ByteArrayInputStream(bytes));
        int imgWidth = bim.getWidth();
        int imgHeight = bim.getHeight();
        // 如果不处理size,只用quality,可能导致一致压缩不到目标值,一致递归在当前方法中!!
        int desWidth = new BigDecimal(imgWidth).multiply(new BigDecimal(quality)).intValue();
        int desHeight = new BigDecimal(imgHeight).multiply(new BigDecimal(quality)).intValue();
        logger.info("图片文将按照width={}*height={}进行压缩,画质quality={}。",desWidth,desHeight,quality);
        Thumbnails.of(new ByteArrayInputStream(bytes)).size(desWidth, desHeight).outputQuality(quality).outputFormat("jpg").toOutputStream(out);
        //递归
        return compressPhotoByQuality(out.toByteArray(), quality, maxkb);
    }
    
    /**File to bytes[]*/
    public static byte[] readFileToByteArray(File f) throws Exception {
        byte[] fileb = null;
        InputStream is = null;
        ByteArrayOutputStream out = new ByteArrayOutputStream();

        try {
            is = new FileInputStream(f);
            byte[] b = new byte[1024];

            int n;
            while ((n = is.read(b)) != -1) {
                out.write(b, 0, n);
            }

            fileb = out.toByteArray();
            return fileb;
        } catch (Exception var16) {
            throw new Exception("readFileToByteArray", var16);
        } finally {
            if (is != null) {
                try {
                    is.close();
                } catch (Exception var15) {
                    ;
                }
            }

            if (out != null) {
                try {
                    out.close();
                } catch (Exception var14) {
                    ;
                }
            }

        }
    }
}

 测试

package com.solar.oa.card.util;

import java.io.File;
import java.io.FileOutputStream;
import org.apache.commons.codec.binary.Base64;

public class ImageTest {
    public static void main(String[] args) throws Exception {
        
        // 图片压缩
        File file = new File("D://test/1.jpg");
        /*@Parameters:imgFile 源图片文件;maxkb 目标kb;photoWidth 目标宽度;photoHeight 模板高度;quality 质量*/
        byte[] bytes = ImageUtil.compressPhoto(file, 100, 300, 300, 0.9f);
        
        
        // 输出到文件
        File desFile = new File("D://test/2.jpg"); 
        FileOutputStream fos = new FileOutputStream(desFile);
        fos.write(bytes);
        fos.close();
        
        // 转base64
        System.out.println("data:image/jpg;base64,"+ Base64.encodeBase64String(bytes));
    }
}

效果:1.86MB-->58kb,且压缩后图片依然清晰!

source.jpg: 2708x3085  1.86MB

result.jpg:263x300  58kb

result:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章