备忘录 【Java图片压缩】

这个功能平时用不到,偶尔用到了代码写了就忘记,本地文件夹备忘录里找起来又麻烦,这里就先记录一下代码


import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.*;

public class ImageCompressionUtil {

    // 主方法:压缩图片
    public static void compressImage(String sourceImagePath, String targetImagePath, int targetFileSizeKB) throws IOException {
        File inputFile = new File(sourceImagePath);
        BufferedImage originalImage = ImageIO.read(inputFile);

        // 计算缩放比例
        double scale = calculateScale(inputFile.length(), targetFileSizeKB);
        BufferedImage resizedImage = resizeImage(originalImage, scale);

        // 使用二分法查找最佳质量
        float bestQuality = findBestJPEGQuality(resizedImage, targetImagePath, targetFileSizeKB);

        // 最终保存图片
        saveCompressedImage(resizedImage, targetImagePath, bestQuality);
    }

    // 计算缩放比例
    private static double calculateScale(long originalSize, int targetFileSizeKB) {
        long targetSize = targetFileSizeKB * 1024;

        if (originalSize <= targetSize) {
            return 1.0; // 不缩放
        }

        double scale = Math.sqrt((double) targetSize / originalSize);
        return Math.max(scale, 0.2); // 最小缩放比例,防止过小
    }

    // 调整图片大小
    private static BufferedImage resizeImage(BufferedImage originalImage, double scale) {
        int newWidth = (int) (originalImage.getWidth() * scale);
        int newHeight = (int) (originalImage.getHeight() * scale);

        BufferedImage resizedImage = new BufferedImage(newWidth, newHeight, BufferedImage.TYPE_INT_RGB);
        Graphics2D g2d = resizedImage.createGraphics();
        g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
        g2d.drawImage(originalImage.getScaledInstance(newWidth, newHeight, Image.SCALE_SMOOTH), 0, 0, null);
        g2d.dispose();

        return resizedImage;
    }

    // 使用二分法查找最佳 JPEG 质量
    private static float findBestJPEGQuality(BufferedImage image, String tempFilePath, int targetFileSizeKB) throws IOException {
        float low = 0.05f;  // 最低质量
        float high = 1.0f;  // 最高质量
        float bestQuality = high;
        long targetSize = targetFileSizeKB * 1024;
        long bestFileSize = Long.MAX_VALUE;

        while (high - low > 0.01f) { // 细化到 0.01
            float mid = (low + high) / 2;
            long compressedSize = saveTempCompressedImage(image, tempFilePath, mid);

            if (Math.abs(compressedSize - targetSize) < targetSize * 0.05) {
                return mid;
            }

            if (compressedSize > targetSize) {
                high = mid;
            } else {
                low = mid;
            }

            if (compressedSize < bestFileSize) {
                bestQuality = mid;
                bestFileSize = compressedSize;
            }
        }
        return bestQuality;
    }

    // 保存 JPEG 并返回文件大小
    private static long saveTempCompressedImage(BufferedImage image, String tempFilePath, float quality) throws IOException {
        File tempFile = new File(tempFilePath);
        saveCompressedImage(image, tempFilePath, quality);
        return tempFile.length();
    }

    // 保存最终压缩图片
    private static void saveCompressedImage(BufferedImage image, String targetImagePath, float quality) throws IOException {
        File outputFile = new File(targetImagePath);
        OutputStream out = new FileOutputStream(outputFile);
        ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();
        ImageWriteParam param = writer.getDefaultWriteParam();

        // 设置 JPEG 压缩质量
        param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
        param.setCompressionQuality(quality);

        // 写入文件
        writer.setOutput(ImageIO.createImageOutputStream(out));
        writer.write(null, new IIOImage(image, null, null), param);
        out.close();
    }
}

调用如下

/**
 * 压缩图片
 * sourceImagePath:图片位置
 * targetImagePath:图片压缩后的位置
 */
try {
  String sourceImagePath = directoryPath+"/"+originalFileName;
  String targetImagePath = directoryPath+"/thumbnail_"+originalFileName;
  ImageCompressionUtil.compressImage(sourceImagePath, targetImagePath, 10);
}catch (Exception e){
   e.printStackTrace();
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值