|
@@ -24,6 +24,7 @@ import javax.imageio.IIOImage;
|
|
|
import javax.imageio.ImageIO;
|
|
|
import javax.imageio.ImageWriteParam;
|
|
|
import javax.imageio.ImageWriter;
|
|
|
+import javax.imageio.stream.ImageOutputStream;
|
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
import java.awt.*;
|
|
|
import java.awt.geom.AffineTransform;
|
|
@@ -118,52 +119,173 @@ public class FileUtils {
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+// /**
|
|
|
+// * 图片缩放、压缩、旋转处理
|
|
|
+// *
|
|
|
+// * @param imageData
|
|
|
+// * @return
|
|
|
+// * @throws IOException
|
|
|
+// * @throws ImageProcessingException
|
|
|
+// * @throws MetadataException
|
|
|
+// */
|
|
|
+// public static byte[] compressImage(byte[] imageData) throws IOException, ImageProcessingException, MetadataException {
|
|
|
+// // 读取原始图像(处理旋转问题)
|
|
|
+// Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageData));
|
|
|
+// if (metadata.containsDirectoryOfType(ExifIFD0Directory.class)) {
|
|
|
+// ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
|
|
|
+// if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
|
|
|
+// // 获取 Orientation 标签的值
|
|
|
+// int orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
|
|
|
+// // 需要旋转图片
|
|
|
+// BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageData));
|
|
|
+// AffineTransform transform = new AffineTransform();
|
|
|
+// if (orientation == 6) {
|
|
|
+// transform.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
|
|
|
+// } else if (orientation == 8) {
|
|
|
+// transform.rotate(-Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
|
|
|
+// }
|
|
|
+// AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
|
|
|
+// originalImage = op.filter(originalImage, null);
|
|
|
+// ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
+// ImageIO.write(originalImage, "jpg", baos);
|
|
|
+// imageData = baos.toByteArray();
|
|
|
+// }
|
|
|
+// }
|
|
|
+// // 缩放图像
|
|
|
+// String formatName = "JPEG";
|
|
|
+// ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
|
|
|
+// BufferedImage originalImage = ImageIO.read(bais);
|
|
|
+// long sizeLimit = 366912; //358KB
|
|
|
+// int width = 768;
|
|
|
+// int height = 1024;
|
|
|
+// Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
|
|
|
+// BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
|
|
+// resizedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
|
|
|
+//
|
|
|
+// // 压缩图像
|
|
|
+// ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
+// ImageIO.write(resizedImage, formatName, baos);
|
|
|
+//
|
|
|
+// if (baos.size() <= sizeLimit) {
|
|
|
+// // 图片大小已经小于等于目标大小,直接返回原始数据
|
|
|
+// return baos.toByteArray();
|
|
|
+// }
|
|
|
+//
|
|
|
+// float quality = 0.9f; // 初始化压缩质量
|
|
|
+// int retries = 10; // 最多尝试 10 次
|
|
|
+//
|
|
|
+// while (baos.size() > sizeLimit && retries > 0) {
|
|
|
+// // 压缩图像并重新计算压缩质量
|
|
|
+// byte[] data = baos.toByteArray();
|
|
|
+// bais = new ByteArrayInputStream(data);
|
|
|
+// BufferedImage compressedImage = ImageIO.read(bais);
|
|
|
+// baos.reset();
|
|
|
+//
|
|
|
+// ImageWriter writer = null;
|
|
|
+// Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
|
|
|
+// if (writers.hasNext()) {
|
|
|
+// writer = writers.next();
|
|
|
+// } else {
|
|
|
+// throw new IllegalArgumentException("Unsupported image format: " + formatName);
|
|
|
+// }
|
|
|
+//
|
|
|
+// ImageWriteParam writeParam = writer.getDefaultWriteParam();
|
|
|
+// writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
|
|
+// writeParam.setCompressionQuality(quality);
|
|
|
+//
|
|
|
+// writer.setOutput(ImageIO.createImageOutputStream(baos));
|
|
|
+// writer.write(null, new IIOImage(compressedImage, null, null), writeParam);
|
|
|
+// writer.dispose();
|
|
|
+//
|
|
|
+// float ratio = sizeLimit * 1.0f / baos.size();
|
|
|
+// quality *= Math.sqrt(ratio);
|
|
|
+// retries--;
|
|
|
+// }
|
|
|
+//
|
|
|
+// return baos.toByteArray();
|
|
|
+// }
|
|
|
+
|
|
|
/**
|
|
|
- * 图片缩放、压缩、旋转处理
|
|
|
- *
|
|
|
- * @param imageData
|
|
|
- * @return
|
|
|
- * @throws IOException
|
|
|
- * @throws ImageProcessingException
|
|
|
- * @throws MetadataException
|
|
|
- */
|
|
|
- public static byte[] compressImage(byte[] imageData) throws IOException, ImageProcessingException, MetadataException {
|
|
|
- // 读取原始图像(处理旋转问题)
|
|
|
- Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageData));
|
|
|
- if (metadata.containsDirectoryOfType(ExifIFD0Directory.class)) {
|
|
|
- ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
|
|
|
- if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
|
|
|
- // 获取 Orientation 标签的值
|
|
|
- int orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
|
|
|
- // 需要旋转图片
|
|
|
- BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageData));
|
|
|
- AffineTransform transform = new AffineTransform();
|
|
|
- if (orientation == 6) {
|
|
|
- transform.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
|
|
|
- } else if (orientation == 8) {
|
|
|
- transform.rotate(-Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
|
|
|
+ // * 图片缩放、压缩、旋转处理
|
|
|
+ // *
|
|
|
+ // * @param imageData
|
|
|
+ // * @return
|
|
|
+ // * @throws IOException
|
|
|
+ // * @throws ImageProcessingException
|
|
|
+ // * @throws MetadataException
|
|
|
+ // */
|
|
|
+ public static byte[] compressImage(byte[] imageData) throws IOException {
|
|
|
+ if (imageData == null || imageData.length == 0) {
|
|
|
+ throw new IllegalArgumentException("图像数据不能为空");
|
|
|
+ }
|
|
|
+
|
|
|
+ try {
|
|
|
+ // 读取原始图像(处理旋转问题)
|
|
|
+ Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageData));
|
|
|
+ if (metadata.containsDirectoryOfType(ExifIFD0Directory.class)) {
|
|
|
+ ExifIFD0Directory exifIFD0Directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class);
|
|
|
+ if (exifIFD0Directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) {
|
|
|
+ // 获取 Orientation 标签的值
|
|
|
+ int orientation = exifIFD0Directory.getInt(ExifIFD0Directory.TAG_ORIENTATION);
|
|
|
+ // 需要旋转图片
|
|
|
+ BufferedImage originalImage = ImageIO.read(new ByteArrayInputStream(imageData));
|
|
|
+ if (originalImage == null) {
|
|
|
+ throw new IOException("无法读取图像数据");
|
|
|
+ }
|
|
|
+
|
|
|
+ AffineTransform transform = new AffineTransform();
|
|
|
+ if (orientation == 6) {
|
|
|
+ transform.rotate(Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
|
|
|
+ } else if (orientation == 8) {
|
|
|
+ transform.rotate(-Math.PI / 2, originalImage.getWidth() / 2, originalImage.getHeight() / 2);
|
|
|
+ }
|
|
|
+ AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
|
|
|
+ originalImage = op.filter(originalImage, null);
|
|
|
+ ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
+ ImageIO.write(originalImage, "jpg", baos);
|
|
|
+ imageData = baos.toByteArray();
|
|
|
}
|
|
|
- AffineTransformOp op = new AffineTransformOp(transform, AffineTransformOp.TYPE_BILINEAR);
|
|
|
- originalImage = op.filter(originalImage, null);
|
|
|
- ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
- ImageIO.write(originalImage, "jpg", baos);
|
|
|
- imageData = baos.toByteArray();
|
|
|
}
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 如果EXIF处理失败,继续处理原始图像数据
|
|
|
+ System.err.println("处理图像EXIF信息时出错: " + e.getMessage());
|
|
|
}
|
|
|
+
|
|
|
// 缩放图像
|
|
|
String formatName = "JPEG";
|
|
|
ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
|
|
|
BufferedImage originalImage = ImageIO.read(bais);
|
|
|
+
|
|
|
+ if (originalImage == null) {
|
|
|
+ throw new IOException("无法读取图像数据");
|
|
|
+ }
|
|
|
+
|
|
|
+ // 确保图像是兼容的格式
|
|
|
+ BufferedImage compatibleImage = convertToSupportedFormat(originalImage);
|
|
|
+
|
|
|
long sizeLimit = 366912; //358KB
|
|
|
int width = 768;
|
|
|
int height = 1024;
|
|
|
+
|
|
|
+ // 使用更高质量的缩放方法
|
|
|
Image scaledImage = originalImage.getScaledInstance(width, height, Image.SCALE_SMOOTH);
|
|
|
- BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
|
|
|
- resizedImage.getGraphics().drawImage(scaledImage, 0, 0, null);
|
|
|
+ BufferedImage resizedImage = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
|
|
|
+ Graphics2D g2d = resizedImage.createGraphics();
|
|
|
+ g2d.setRenderingHint(RenderingHints.KEY_INTERPOLATION, RenderingHints.VALUE_INTERPOLATION_BILINEAR);
|
|
|
+ g2d.drawImage(scaledImage, 0, 0, null);
|
|
|
+ g2d.dispose();
|
|
|
|
|
|
// 压缩图像
|
|
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
|
|
- ImageIO.write(resizedImage, formatName, baos);
|
|
|
+ try {
|
|
|
+ boolean success = ImageIO.write(resizedImage, formatName, baos);
|
|
|
+ if (!success) {
|
|
|
+ throw new IOException("无法写入JPEG格式图像");
|
|
|
+ }
|
|
|
+ } catch (Exception e) {
|
|
|
+ // 尝试使用ImageWriter直接写入
|
|
|
+ writeImageWithDefaultSettings(resizedImage, baos, formatName);
|
|
|
+ }
|
|
|
|
|
|
if (baos.size() <= sizeLimit) {
|
|
|
// 图片大小已经小于等于目标大小,直接返回原始数据
|
|
@@ -178,23 +300,40 @@ public class FileUtils {
|
|
|
byte[] data = baos.toByteArray();
|
|
|
bais = new ByteArrayInputStream(data);
|
|
|
BufferedImage compressedImage = ImageIO.read(bais);
|
|
|
+
|
|
|
+ if (compressedImage == null) {
|
|
|
+ throw new IOException("无法读取压缩后的图像数据");
|
|
|
+ }
|
|
|
+
|
|
|
baos.reset();
|
|
|
|
|
|
ImageWriter writer = null;
|
|
|
- Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName);
|
|
|
+ Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName.toLowerCase());
|
|
|
+ if (!writers.hasNext()) {
|
|
|
+ // 尝试其他格式
|
|
|
+ writers = ImageIO.getImageWritersByFormatName("jpeg");
|
|
|
+ }
|
|
|
+
|
|
|
if (writers.hasNext()) {
|
|
|
writer = writers.next();
|
|
|
} else {
|
|
|
throw new IllegalArgumentException("Unsupported image format: " + formatName);
|
|
|
}
|
|
|
|
|
|
- ImageWriteParam writeParam = writer.getDefaultWriteParam();
|
|
|
- writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
|
|
- writeParam.setCompressionQuality(quality);
|
|
|
+ try {
|
|
|
+ ImageWriteParam writeParam = writer.getDefaultWriteParam();
|
|
|
+ if (writeParam.canWriteCompressed()) {
|
|
|
+ writeParam.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
|
|
|
+ writeParam.setCompressionQuality(quality);
|
|
|
+ }
|
|
|
|
|
|
- writer.setOutput(ImageIO.createImageOutputStream(baos));
|
|
|
- writer.write(null, new IIOImage(compressedImage, null, null), writeParam);
|
|
|
- writer.dispose();
|
|
|
+ try (ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {
|
|
|
+ writer.setOutput(ios);
|
|
|
+ writer.write(null, new IIOImage(compressedImage, null, null), writeParam);
|
|
|
+ }
|
|
|
+ } finally {
|
|
|
+ writer.dispose();
|
|
|
+ }
|
|
|
|
|
|
float ratio = sizeLimit * 1.0f / baos.size();
|
|
|
quality *= Math.sqrt(ratio);
|
|
@@ -204,6 +343,52 @@ public class FileUtils {
|
|
|
return baos.toByteArray();
|
|
|
}
|
|
|
|
|
|
+ /**
|
|
|
+ * 转换图像为支持的格式
|
|
|
+ */
|
|
|
+ private static BufferedImage convertToSupportedFormat(BufferedImage image) {
|
|
|
+ if (image == null) return null;
|
|
|
+
|
|
|
+ // 检查是否为支持的类型
|
|
|
+ int type = image.getType();
|
|
|
+ if (type != BufferedImage.TYPE_INT_RGB && type != BufferedImage.TYPE_INT_ARGB) {
|
|
|
+ // 转换为支持的格式
|
|
|
+ BufferedImage converted = new BufferedImage(
|
|
|
+ image.getWidth(), image.getHeight(), BufferedImage.TYPE_INT_RGB);
|
|
|
+ Graphics2D g = converted.createGraphics();
|
|
|
+ g.setColor(Color.WHITE);
|
|
|
+ g.fillRect(0, 0, converted.getWidth(), converted.getHeight());
|
|
|
+ g.drawImage(image, 0, 0, null);
|
|
|
+ g.dispose();
|
|
|
+ return converted;
|
|
|
+ }
|
|
|
+ return image;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 使用默认设置写入图像
|
|
|
+ */
|
|
|
+ private static void writeImageWithDefaultSettings(BufferedImage image, ByteArrayOutputStream baos, String formatName) throws IOException {
|
|
|
+ Iterator<ImageWriter> writers = ImageIO.getImageWritersByFormatName(formatName.toLowerCase());
|
|
|
+ if (!writers.hasNext()) {
|
|
|
+ writers = ImageIO.getImageWritersByFormatName("jpeg");
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!writers.hasNext()) {
|
|
|
+ throw new IOException("找不到JPEG图像写入器");
|
|
|
+ }
|
|
|
+
|
|
|
+ ImageWriter writer = writers.next();
|
|
|
+ ImageWriteParam param = writer.getDefaultWriteParam();
|
|
|
+
|
|
|
+ try (ImageOutputStream ios = ImageIO.createImageOutputStream(baos)) {
|
|
|
+ writer.setOutput(ios);
|
|
|
+ writer.write(null, new IIOImage(image, null, null), param);
|
|
|
+ } finally {
|
|
|
+ writer.dispose();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
/**
|
|
|
* 设置图片的定位、大小和合并单元格处理
|
|
|
*
|