在 Java 项目中 根据用户上传的图片,判断图片宽必须大于高,方便横向展示,且进行图片压缩 要求压缩到300K一下,保持到本地应硬盘中。

我们经常遇到图片上传的功能,如何不进行图片压缩就会导致在前端展示的时候,就像拉窗帘一样缓慢
在 Java 项目中实现用户上传图片的宽高校验和压缩存储,可以通过以下步骤完成:


1. 依赖引入

确保项目中包含图片处理库,推荐使用 Thumbnailator(简化图片操作)和 ImageIO(Java 原生库):


<dependency>
    <groupId>net.coobirdgroupId>
    <artifactId>thumbnailatorartifactId>
    <version>0.4.14version>
dependency>

2. 校验图片宽高是否符合要求

使用 BufferedImage 读取图片尺寸并校验:

import java.awt.image.BufferedImage;
import javax.imageio.ImageIO;
import java.io.File;
import java.io.IOException;

public class ImageUtils {
    /**
     * 校验图片宽度是否大于高度
     * @param imageFile 上传的图片文件
     * @return true=符合横向要求,false=不符合
     */
    public static boolean isWidthGreaterThanHeight(File imageFile) throws IOException {
        BufferedImage image = ImageIO.read(imageFile);
        int width = image.getWidth();
        int height = image.getHeight();
        return width > height;
    }
}

3. 图片压缩到 300KB 以下

通过逐步降低质量或调整尺寸实现压缩目标:

方法 1:使用 Thumbnailator 压缩
import net.coobird.thumbnailator.Thumbnails;
import java.io.File;
import java.io.IOException;

public class ImageUtils {
    /**
     * 压缩图片到指定大小(300KB)以下
     * @param sourceFile 原始图片文件
     * @param targetFile 压缩后的文件
     * @param maxSizeKB  目标最大大小(单位:KB)
     */
    public static void compressImage(File sourceFile, File targetFile, int maxSizeKB) throws IOException {
        long maxSizeBytes = maxSizeKB * 1024;
        float quality = 0.9f; // 初始压缩质量

        do {
            Thumbnails.of(sourceFile)
                    .scale(1.0)     // 保持原始尺寸
                    .outputQuality(quality)
                    .toFile(targetFile);

            quality -= 0.1f; // 逐步降低质量
        } while (targetFile.length() > maxSizeBytes && quality > 0.1f);

        // 如果仍然不满足,调整尺寸
        if (targetFile.length() > maxSizeBytes) {
            Thumbnails.of(sourceFile)
                    .scale(0.5)     // 缩小尺寸为50%
                    .outputQuality(0.7f)
                    .toFile(targetFile);
        }
    }
}
方法 2:使用 ImageIO 动态调整压缩质量
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import java.awt.image.BufferedImage;
import java.io.*;

public class ImageUtils {
    /**
     * 动态调整 JPEG 压缩质量
     */
    public static void compressJPEG(File source, File target, float maxQuality) throws IOException {
        BufferedImage image = ImageIO.read(source);
        try (OutputStream os = new FileOutputStream(target)) {
            ImageWriter writer = ImageIO.getImageWritersByFormatName("jpg").next();
            ImageWriteParam param = writer.getDefaultWriteParam();
            param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
            param.setCompressionQuality(maxQuality); // 0.0~1.0

            writer.setOutput(ImageIO.createImageOutputStream(os));
            writer.write(null, new IIOImage(image, null, null), param);
            writer.dispose();
        }
    }
}

4. 保存到本地硬盘

生成唯一文件名并存储,避免覆盖:

import java.io.File;
import java.nio.file.Files;
import java.nio.file.StandardCopyOption;
import java.util.UUID;

public class ImageStorage {
    /**
     * 保存图片到本地目录
     * @param uploadFile 用户上传的文件
     * @param targetDir  存储目录(如 /var/images/)
     * @return 存储后的文件名
     */
    public static String saveToDisk(File uploadFile, String targetDir) throws IOException {
        String uniqueFileName = UUID.randomUUID() + ".jpg"; // 生成唯一文件名
        File targetFile = new File(targetDir, uniqueFileName);

        // 创建目录(如果不存在)
        if (!targetFile.getParentFile().exists()) {
            targetFile.getParentFile().mkdirs();
        }

        // 复制文件到目标路径
        Files.copy(uploadFile.toPath(), targetFile.toPath(), StandardCopyOption.REPLACE_EXISTING);
        return uniqueFileName;
    }
}

5. 完整调用流程

结合校验、压缩和存储:

public class ImageUploadService {
    public static void processUpload(File uploadedImage, String savePath) throws IOException {
        // 1. 校验宽高
        if (!ImageUtils.isWidthGreaterThanHeight(uploadedImage)) {
            throw new IllegalArgumentException("图片宽度必须大于高度!");
        }

        // 2. 压缩到 300KB 以下
        File compressedFile = File.createTempFile("compressed-", ".jpg");
        ImageUtils.compressImage(uploadedImage, compressedFile, 300);

        // 3. 保存到硬盘
        String savedFileName = ImageStorage.saveToDisk(compressedFile, savePath);
        System.out.println("图片已保存为:" + savedFileName);

        // 清理临时文件
        compressedFile.delete();
    }
}

6. 关键注意事项

  1. 格式兼容性

    • 支持常见格式(JPG/PNG),需根据格式调整压缩逻辑。
    • PNG 压缩率低,建议转换为 JPG 以减小体积。
  2. 性能优化

    • 大图片处理时使用 BufferedInputStream 避免内存溢出。
    • 异步处理(如使用 CompletableFuture)提升响应速度。
  3. 安全性

    • 校验文件头防止非图片文件上传。
    • 限制上传文件大小(如通过 Spring MVC 的 MultipartFile 配置)。
  4. 存储路径

    • 使用绝对路径(如 /data/images/)而非相对路径。
    • 定期清理未使用的临时文件。

7. 扩展功能

  • 图片尺寸调整:若压缩后仍不满足大小,可按比例缩小尺寸:
    Thumbnails.of(sourceFile)
        .size(1024, 768)  // 调整到指定宽高
        .outputQuality(0.8f)
        .toFile(targetFile);
    
  • 日志记录:记录图片处理耗时、压缩率等信息。

通过以上代码和流程,可以高效实现图片宽高校验、压缩存储功能,确保系统稳定性和用户体验。

你可能感兴趣的:(java,java,开发语言)