方法:

/**
 * 对图片进行原比例无损压缩,并将压缩后的图片覆盖原文件。
 *
 * @param path 图片的文件路径
 */
private static void doWithPhoto(String path) {
    // 创建文件对象
    File file = new File(path);

    // 如果文件不存在,直接返回
    if (!file.exists()) {
        return;
    }

    // 初始化变量
    BufferedImage image = null; // 用于存储读取到的图片
    FileOutputStream os = null; // 用于输出压缩后的图片

    try {
        // 读取图片文件
        image = ImageIO.read(file);

        // 获取图片的宽度和高度
        int width = image.getWidth();
        int height = image.getHeight();

        // 创建一个空白的 BufferedImage 对象,用于存储压缩后的图片
        // TYPE_INT_RGB 表示图像采用 RGB 格式
        BufferedImage bfImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);

        // 将原图像缩放后绘制到新的 BufferedImage 上
        bfImage.getGraphics().drawImage(
            image.getScaledInstance(width, height, Image.SCALE_SMOOTH), // 缩放图像,保持平滑效果
            0, // 绘制起点的 x 坐标
            0, // 绘制起点的 y 坐标
            null // 图像观察者,null 表示不需要,在大多数现代应用中,图像通常是一次性加载的,因此不需要显式提供图像观察者。传递 null 是一种简便的处理方式,表明开发者不会对图像加载的中间状态进行干预。
        );

        // 创建文件输出流,用于保存压缩后的图片
        os = new FileOutputStream(path);

        // 使用 JPEG 编码器对压缩后的图像进行编码
        JPEGImageEncoder encoder = JPEGCodec.createJPEGEncoder(os);
        encoder.encode(bfImage);

    } catch (IOException e) {
        // 捕获并打印 IO 异常
        e.printStackTrace();
    } finally {
        // 关闭文件输出流,避免资源泄漏
        if (os != null) {
            try {
                os.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

调用:

@Test
void contextLoads52(){
    doWithPhoto("D:\\kaifa\\imgAddr\\yasuo2.png"); //引号内写图片路径
}

效果:

左侧为压缩前,右侧为压缩后