导出设备数据
This commit is contained in:
@ -3,18 +3,43 @@ package com.fuyuanshen.common.core.utils.file;
|
||||
import lombok.extern.slf4j.Slf4j;
|
||||
|
||||
import javax.imageio.ImageIO;
|
||||
import javax.imageio.ImageWriteParam;
|
||||
import javax.imageio.ImageWriter;
|
||||
import java.awt.*;
|
||||
import java.awt.image.BufferedImage;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.util.Iterator;
|
||||
|
||||
/**
|
||||
* 图片压缩工具类
|
||||
*
|
||||
* @author AprilWind
|
||||
*/
|
||||
@Slf4j
|
||||
public class ImageCompressUtil {
|
||||
|
||||
/**
|
||||
* 默认压缩目标大小(100KB)
|
||||
*/
|
||||
private static final int DEFAULT_COMPRESS_SIZE = 100 * 1024;
|
||||
|
||||
/**
|
||||
* 默认触发压缩的大小(1MB)
|
||||
*/
|
||||
private static final int DEFAULT_TRIGGER_SIZE = 1024 * 1024;
|
||||
|
||||
/**
|
||||
* 压缩图片到指定大小以下(默认100KB)
|
||||
*
|
||||
* @param imageData 原始图片数据
|
||||
* @return 压缩后的图片数据
|
||||
*/
|
||||
public static byte[] compressImage(byte[] imageData) {
|
||||
return compressImage(imageData, DEFAULT_COMPRESS_SIZE);
|
||||
}
|
||||
|
||||
/**
|
||||
* 压缩图片到指定大小以下
|
||||
*
|
||||
@ -36,24 +61,54 @@ public class ImageCompressUtil {
|
||||
return imageData;
|
||||
}
|
||||
|
||||
// 计算压缩比例
|
||||
double scale = Math.sqrt((double) maxSize / imageData.length);
|
||||
// 确保至少压缩到一半大小,避免压缩效果不明显
|
||||
scale = Math.max(scale, 0.5);
|
||||
// 检查图片是否包含透明度
|
||||
boolean hasAlpha = hasAlpha(originalImage);
|
||||
String formatName = hasAlpha ? "png" : "jpg";
|
||||
|
||||
// 压缩图片
|
||||
byte[] compressedData = compressImageByScale(originalImage, scale);
|
||||
// 对于小尺寸PNG图片可跳过压缩以保持图像质量
|
||||
if ("png".equals(formatName) && imageData.length <= 2 * maxSize) {
|
||||
log.debug("PNG图片大小适中({} bytes),跳过压缩", imageData.length);
|
||||
return imageData;
|
||||
}
|
||||
|
||||
// 先尝试质量压缩
|
||||
byte[] compressedData = compressImageQuality(originalImage, formatName, 0.8f);
|
||||
|
||||
// 如果质量压缩后仍大于目标大小,则进行尺寸压缩
|
||||
if (compressedData.length > maxSize) {
|
||||
// 计算缩放比例
|
||||
double scale = Math.sqrt((double) maxSize / compressedData.length);
|
||||
scale = Math.max(scale, 0.5); // 最小缩放到原来的一半
|
||||
|
||||
// 尺寸压缩
|
||||
compressedData = compressImageByScale(originalImage, scale, formatName);
|
||||
}
|
||||
|
||||
// 如果压缩后还是太大,继续压缩
|
||||
int attempts = 0;
|
||||
while (compressedData.length > maxSize && attempts < 5) {
|
||||
scale *= 0.8; // 每次缩小20%
|
||||
compressedData = compressImageByScale(originalImage, scale);
|
||||
// 优先降低质量
|
||||
float quality = Math.max(0.1f, 0.8f - attempts * 0.1f);
|
||||
compressedData = compressImageQuality(originalImage, formatName, quality);
|
||||
|
||||
// 如果质量压缩不够,再缩小尺寸
|
||||
if (compressedData.length > maxSize) {
|
||||
double scale = 0.9 - attempts * 0.1; // 逐步缩小尺寸
|
||||
scale = Math.max(scale, 0.5);
|
||||
compressedData = compressImageByScale(originalImage, scale, formatName);
|
||||
}
|
||||
attempts++;
|
||||
}
|
||||
|
||||
log.info("图片压缩完成,原始大小: {} bytes, 压缩后大小: {} bytes, 压缩比例: {}",
|
||||
imageData.length, compressedData.length, String.format("%.2f", scale));
|
||||
log.info("图片压缩完成,原始大小: {} bytes, 压缩后大小: {} bytes, 压缩率: {}%",
|
||||
imageData.length, compressedData.length,
|
||||
String.format("%.2f", (1.0 - (double) compressedData.length / imageData.length) * 100));
|
||||
|
||||
// 如果压缩后反而变大了,则使用原始数据
|
||||
if (compressedData.length >= imageData.length) {
|
||||
log.debug("压缩后数据变大,使用原始数据");
|
||||
return imageData;
|
||||
}
|
||||
|
||||
return compressedData;
|
||||
} catch (Exception e) {
|
||||
@ -62,16 +117,16 @@ public class ImageCompressUtil {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 按比例缩放图片
|
||||
*
|
||||
* @param originalImage 原始图片
|
||||
* @param scale 缩放比例
|
||||
* @param formatName 图片格式
|
||||
* @return 缩放后的图片数据
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private static byte[] compressImageByScale(BufferedImage originalImage, double scale) throws IOException {
|
||||
private static byte[] compressImageByScale(BufferedImage originalImage, double scale, String formatName) throws IOException {
|
||||
int width = (int) (originalImage.getWidth() * scale);
|
||||
int height = (int) (originalImage.getHeight() * scale);
|
||||
|
||||
@ -79,13 +134,73 @@ public class ImageCompressUtil {
|
||||
Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
|
||||
BufferedImage bufferedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
||||
Graphics2D g2d = bufferedImage.createGraphics();
|
||||
|
||||
// 绘制缩放后的图片
|
||||
g2d.drawImage(scaledImage, 0, 0, null);
|
||||
g2d.dispose();
|
||||
|
||||
// 输出为JPEG格式
|
||||
// 输出为指定格式
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(bufferedImage, "jpg", baos);
|
||||
ImageIO.write(bufferedImage, formatName, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
}
|
||||
/**
|
||||
* 按质量压缩图片
|
||||
*
|
||||
* @param originalImage 原始图片
|
||||
* @param formatName 图片格式
|
||||
* @param quality 压缩质量(0.1-1.0)
|
||||
* @return 压缩后的图片数据
|
||||
* @throws IOException IO异常
|
||||
*/
|
||||
private static byte[] compressImageQuality(BufferedImage originalImage, String formatName, float quality) throws IOException {
|
||||
// 创建压缩参数
|
||||
Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
|
||||
if (!writers.hasNext()) {
|
||||
log.warn("找不到合适的图片写入器");
|
||||
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||
ImageIO.write(originalImage, formatName, baos);
|
||||
return baos.toByteArray();
|
||||
}
|
||||
|
||||
ImageWriter writer = writers.next();
|
||||
ImageWriteParam param = writer.getDefaultWriteParam();
|
||||
|
||||
// 设置压缩参数
|
||||
if (param.canWriteCompressed()) {
|
||||
param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
||||
param.setCompressionQuality(quality);
|
||||
}
|
||||
|
||||
// 写入压缩后的图片数据
|
||||
ByteArrayOutputStream compressedOutputStream = new ByteArrayOutputStream();
|
||||
writer.setOutput(ImageIO.createImageOutputStream(compressedOutputStream));
|
||||
writer.write(null, new javax.imageio.IIOImage(originalImage, null, null), param);
|
||||
writer.dispose();
|
||||
|
||||
return compressedOutputStream.toByteArray();
|
||||
}
|
||||
|
||||
/**
|
||||
* 检查图片是否包含透明度
|
||||
*
|
||||
* @param image 图片
|
||||
* @return 是否包含透明度
|
||||
*/
|
||||
private static boolean hasAlpha(BufferedImage image) {
|
||||
return image.getType() == BufferedImage.TYPE_4BYTE_ABGR ||
|
||||
image.getType() == BufferedImage.TYPE_INT_ARGB ||
|
||||
image.getColorModel().hasAlpha();
|
||||
}
|
||||
|
||||
/**
|
||||
* 判断图片是否需要压缩(超过1MB)
|
||||
*
|
||||
* @param imageData 图片数据
|
||||
* @return 是否需要压缩
|
||||
*/
|
||||
public static boolean needCompress(byte[] imageData) {
|
||||
return imageData.length > DEFAULT_TRIGGER_SIZE;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user