|
|
@@ -0,0 +1,175 @@
|
|
|
+package org.dromara.common.core.utils.file;
|
|
|
+
|
|
|
+import cn.hutool.core.io.FileUtil;
|
|
|
+import net.coobird.thumbnailator.Thumbnails;
|
|
|
+import org.slf4j.Logger;
|
|
|
+import org.slf4j.LoggerFactory;
|
|
|
+
|
|
|
+import java.io.*;
|
|
|
+import java.nio.file.Files;
|
|
|
+import java.nio.file.Path;
|
|
|
+import java.nio.file.Paths;
|
|
|
+
|
|
|
+public class PicCompressor {
|
|
|
+ //以下是常量,按照阿里代码开发规范,不允许代码中出现魔法值
|
|
|
+ private static final Logger logger = LoggerFactory.getLogger(PicCompressor.class);
|
|
|
+ private static final Integer ZERO = 0;
|
|
|
+ private static final Integer ONE_ZERO_TWO_FOUR = 1024;
|
|
|
+ private static final Integer NINE_ZERO_ZERO = 900;
|
|
|
+ private static final Integer THREE_TWO_SEVEN_FIVE = 3275;
|
|
|
+ private static final Integer TWO_ZERO_FOUR_SEVEN = 2047;
|
|
|
+ private static final Double ZERO_NINE = 0.9;
|
|
|
+ private static final Double ZERO_SIX = 0.6;
|
|
|
+ private static final Double ZERO_FOUR_FOUR = 0.44;
|
|
|
+ private static final Double ZERO_FOUR = 0.4;
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 根据指定大小压缩图片
|
|
|
+ *
|
|
|
+ * @param imageBytes 源图片字节数组
|
|
|
+ * @param desFileSize 指定图片大小,单位kb
|
|
|
+ * @return 压缩质量后的图片字节数组
|
|
|
+ */
|
|
|
+ public static byte[] compressPicForScale(byte[] imageBytes, long desFileSize) {
|
|
|
+ if (imageBytes == null || imageBytes.length <= ZERO || imageBytes.length < desFileSize * ONE_ZERO_TWO_FOUR) {
|
|
|
+ return imageBytes;
|
|
|
+ }
|
|
|
+ long srcSize = imageBytes.length;
|
|
|
+ double accuracy = getAccuracy(srcSize / ONE_ZERO_TWO_FOUR);
|
|
|
+ ByteArrayInputStream inputStream = null;
|
|
|
+ ByteArrayOutputStream outputStream = null;
|
|
|
+ try {
|
|
|
+ while (imageBytes.length > desFileSize * ONE_ZERO_TWO_FOUR) {
|
|
|
+ inputStream = new ByteArrayInputStream(imageBytes);
|
|
|
+ outputStream = new ByteArrayOutputStream(imageBytes.length);
|
|
|
+ Thumbnails.of(inputStream)
|
|
|
+ // 缩放比例
|
|
|
+ .scale(accuracy)
|
|
|
+ // 图片质量
|
|
|
+ .outputQuality(accuracy)
|
|
|
+ .toOutputStream(outputStream);
|
|
|
+ imageBytes = outputStream.toByteArray();
|
|
|
+ accuracy = getAccuracy(imageBytes.length/ONE_ZERO_TWO_FOUR);
|
|
|
+ }
|
|
|
+ logger.info("图片原大小={}kb | 压缩后大小={}kb",
|
|
|
+ srcSize / ONE_ZERO_TWO_FOUR, imageBytes.length / ONE_ZERO_TWO_FOUR);
|
|
|
+ } catch (Exception e) {
|
|
|
+ logger.error("【图片压缩】msg=图片压缩失败!", e);
|
|
|
+ }finally {
|
|
|
+ closeStream(inputStream, outputStream);
|
|
|
+ }
|
|
|
+ return imageBytes;
|
|
|
+ }
|
|
|
+
|
|
|
+ static void closeStream(ByteArrayInputStream inputStream, ByteArrayOutputStream outputStream) {
|
|
|
+ if(inputStream != null){
|
|
|
+ try {
|
|
|
+ inputStream.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if(outputStream != null){
|
|
|
+ try {
|
|
|
+ outputStream.close();
|
|
|
+ } catch (IOException e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 自动调节精度(经验数值)
|
|
|
+ *
|
|
|
+ * @param size 源图片大小
|
|
|
+ * @return 图片压缩质量比
|
|
|
+ */
|
|
|
+ private static double getAccuracy(long size) {
|
|
|
+ double accuracy;
|
|
|
+ if (size < ONE_ZERO_TWO_FOUR) {
|
|
|
+ accuracy = ZERO_NINE;
|
|
|
+ } else if (size < TWO_ZERO_FOUR_SEVEN) {
|
|
|
+ accuracy = ZERO_SIX;
|
|
|
+ } else if (size < THREE_TWO_SEVEN_FIVE) {
|
|
|
+ accuracy = ZERO_FOUR_FOUR;
|
|
|
+ } else {
|
|
|
+ accuracy = ZERO_FOUR;
|
|
|
+ }
|
|
|
+ return accuracy;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+
|
|
|
+ public static void main(String[] args) throws IOException {
|
|
|
+ /* File file = new File("C:\\Users\\LENOVO\\Downloads\\avatar-photo\\avatar\\StuBaseinfo\\20200930\\2020022004.JPG");
|
|
|
+ // 获取file的 bytes数组
|
|
|
+ byte[] bytes = FileUtil.readBytes(file);
|
|
|
+ //压缩图片到指定200K以内,不管你的图片有多少兆,都不会超过200kb,精度还算可以,不会模糊
|
|
|
+ byte[] compressed = compressPicForScale(bytes, 200);
|
|
|
+ //生成保存在服务器的图片名称,统一修改原后缀名为:jpg
|
|
|
+ String newFileName = "2020022004" + ".jpg";
|
|
|
+ File fOut = new File("C:\\Users\\LENOVO\\Desktop\\" + newFileName);
|
|
|
+ FileOutputStream fileOutputStream = new FileOutputStream(fOut);
|
|
|
+ fileOutputStream.write(compressed);
|
|
|
+ fileOutputStream.close();*/
|
|
|
+
|
|
|
+ tempCompress();
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ public static void tempCompress() throws IOException {
|
|
|
+// String SOURCE_DIR = "C:\\Users\\LENOVO\\Downloads\\avatar-photo";
|
|
|
+// String TARGET_DIR = "C:\\Users\\LENOVO\\Downloads\\avatar-photo-copy";
|
|
|
+ String SOURCE_DIR = "C:\\Users\\LENOVO\\Desktop\\test-photo";
|
|
|
+ String TARGET_DIR = "C:\\Users\\LENOVO\\Desktop\\test-photo-copy";
|
|
|
+ Path sourcePath = Paths.get(SOURCE_DIR);
|
|
|
+ Path targetPath = Paths.get(TARGET_DIR);
|
|
|
+
|
|
|
+ // 创建目标目录
|
|
|
+ Files.createDirectories(targetPath);
|
|
|
+
|
|
|
+ // 遍历源目录中的所有文件
|
|
|
+ Files.walk(sourcePath)
|
|
|
+ .filter(Files::isRegularFile)
|
|
|
+ .filter(path -> isImageFile(path.toString()))
|
|
|
+ .forEach(sourceFile -> {
|
|
|
+ try {
|
|
|
+ Path relativePath = sourcePath.relativize(sourceFile);
|
|
|
+ Path targetFile = targetPath.resolve(relativePath);
|
|
|
+
|
|
|
+ // 创建目标文件的父目录
|
|
|
+ Files.createDirectories(targetFile.getParent());
|
|
|
+
|
|
|
+ File sfile = sourceFile.toFile();
|
|
|
+ // 获取file的 bytes数组
|
|
|
+ byte[] sbytes = FileUtil.readBytes(sfile);
|
|
|
+ if(sbytes.length <= 200*1024){
|
|
|
+ Files.copy(sourceFile, targetFile);
|
|
|
+ logger.info("图片大小小于200KB,不进行压缩");
|
|
|
+ }else{
|
|
|
+ //压缩图片到指定200K以内,不管你的图片有多少兆,都不会超过200kb,精度还算可以,不会模糊
|
|
|
+ byte[] compressed = compressPicForScale(sbytes, 200);
|
|
|
+
|
|
|
+ FileOutputStream fileOutputStream = new FileOutputStream(targetFile.toFile());
|
|
|
+ fileOutputStream.write(compressed);
|
|
|
+ fileOutputStream.close();
|
|
|
+
|
|
|
+ System.out.println("已处理: " + relativePath + " (" + sourceFile.toFile().length()/1024 + "KB -> " + targetFile.toFile().length()/1024 + "KB)");
|
|
|
+ }
|
|
|
+ } catch (IOException e) {
|
|
|
+ System.err.println("处理文件失败: " + sourceFile + " - " + e.getMessage());
|
|
|
+ }
|
|
|
+ });
|
|
|
+
|
|
|
+ }
|
|
|
+
|
|
|
+ private static boolean isImageFile(String fileName) {
|
|
|
+ String lowerFileName = fileName.toLowerCase();
|
|
|
+ return lowerFileName.endsWith(".jpg") || lowerFileName.endsWith(".jpeg") ||
|
|
|
+ lowerFileName.endsWith(".png") || lowerFileName.endsWith(".bmp") ||
|
|
|
+ lowerFileName.endsWith(".gif") || lowerFileName.endsWith(".webp");
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+}
|