From dad6666107896dbd0c9b17c512bc1cf6821bd352 Mon Sep 17 00:00:00 2001 From: zcxlsm Date: Sun, 24 Aug 2025 16:58:03 +0800 Subject: [PATCH] =?UTF-8?q?feat(ImageUtil):=20=E6=B7=BB=E5=8A=A0=E5=9B=BE?= =?UTF-8?q?=E7=89=87=E5=8E=8B=E7=BC=A9=E6=96=B9=E5=90=91=E5=A4=84=E7=90=86?= =?UTF-8?q?=E5=8A=9F=E8=83=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ruoyi-modules/Sis/pom.xml | 6 + .../dromara/sis/sdk/e8/utils/ImageUtil.java | 133 +++++++++++++++++- 2 files changed, 134 insertions(+), 5 deletions(-) diff --git a/ruoyi-modules/Sis/pom.xml b/ruoyi-modules/Sis/pom.xml index 9cdc13cc..32ca6297 100644 --- a/ruoyi-modules/Sis/pom.xml +++ b/ruoyi-modules/Sis/pom.xml @@ -140,6 +140,12 @@ 3.0.0 + + com.drewnoakes + metadata-extractor + 2.18.0 + + net.java.dev.jna jna diff --git a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/e8/utils/ImageUtil.java b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/e8/utils/ImageUtil.java index 4efff0a4..a209bd81 100644 --- a/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/e8/utils/ImageUtil.java +++ b/ruoyi-modules/Sis/src/main/java/org/dromara/sis/sdk/e8/utils/ImageUtil.java @@ -1,17 +1,21 @@ package org.dromara.sis.sdk.e8.utils; +import com.drew.imaging.ImageMetadataReader; +import com.drew.imaging.ImageProcessingException; +import com.drew.metadata.Metadata; +import com.drew.metadata.MetadataException; +import com.drew.metadata.exif.ExifIFD0Directory; import org.springframework.stereotype.Component; -import javax.imageio.IIOImage; -import javax.imageio.ImageIO; -import javax.imageio.ImageWriteParam; -import javax.imageio.ImageWriter; +import javax.imageio.*; +import javax.imageio.stream.ImageInputStream; import javax.imageio.stream.MemoryCacheImageOutputStream; 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 lsm @@ -22,7 +26,8 @@ import java.io.IOException; public class ImageUtil { public byte[] compressImageToRequirements(byte[] imageData) throws IOException { - BufferedImage image = ImageIO.read(new ByteArrayInputStream(imageData)); + // 读取图片并处理方向 + BufferedImage image = readAndFixOrientation(imageData); // 第一步:调整分辨率(不超过1000x1000) if (image.getWidth() > 1000 || image.getHeight() > 1000) { @@ -91,6 +96,124 @@ public class ImageUtil { return resizedImage; } + /** + * 读取图片并处理 EXIF 方向信息 + */ + private BufferedImage readAndFixOrientation(byte[] imageData) throws IOException { + try { + // 使用 metadata-extractor 读取 EXIF 方向信息 + Metadata metadata = ImageMetadataReader.readMetadata(new ByteArrayInputStream(imageData)); + ExifIFD0Directory directory = metadata.getFirstDirectoryOfType(ExifIFD0Directory.class); + + int orientation = 1; // 默认正常方向 + if (directory != null && directory.containsTag(ExifIFD0Directory.TAG_ORIENTATION)) { + orientation = directory.getInt(ExifIFD0Directory.TAG_ORIENTATION); + } + + // 读取图片 + ImageInputStream input = ImageIO.createImageInputStream(new ByteArrayInputStream(imageData)); + Iterator readers = ImageIO.getImageReaders(input); + + if (!readers.hasNext()) { + throw new IOException("No ImageReader found for image data"); + } + + ImageReader reader = readers.next(); + reader.setInput(input); + BufferedImage image = reader.read(0); + reader.dispose(); + + // 根据方向信息旋转图片 + return rotateImageAccordingToOrientation(image, orientation); + } catch (ImageProcessingException e) { + throw new IOException("Failed to process image metadata", e); + } catch (MetadataException e) { + throw new RuntimeException(e); + } + } + + /** + * 根据方向信息旋转图片 + */ + private BufferedImage rotateImageAccordingToOrientation(BufferedImage image, int orientation) { + int width = image.getWidth(); + int height = image.getHeight(); + + return switch (orientation) { + case 1 -> // 正常 + image; + case 2 -> // 水平翻转 + flipImage(image, true, false); + case 3 -> // 旋转180度 + rotateImage(image, 180); + case 4 -> // 垂直翻转 + flipImage(image, false, true); + case 5 -> { + image = flipImage(image, true, false); + yield rotateImage(image, 270); + } + case 6 -> // 旋转90度 + rotateImage(image, 90); + case 7 -> { + image = flipImage(image, true, false); + yield rotateImage(image, 90); + } + case 8 -> // 旋转270度 + rotateImage(image, 270); + default -> image; + }; + } + + /** + * 旋转图片 + */ + private BufferedImage rotateImage(BufferedImage image, double degrees) { + double radians = Math.toRadians(degrees); + double sin = Math.abs(Math.sin(radians)); + double cos = Math.abs(Math.cos(radians)); + + int width = image.getWidth(); + int height = image.getHeight(); + + int newWidth = (int) Math.floor(width * cos + height * sin); + int newHeight = (int) Math.floor(height * cos + width * sin); + + BufferedImage rotated = new BufferedImage(newWidth, newHeight, image.getType()); + Graphics2D g = rotated.createGraphics(); + + g.translate((newWidth - width) / 2, (newHeight - height) / 2); + g.rotate(Math.toRadians(degrees), width / 2.0, height / 2.0); + g.drawRenderedImage(image, null); + g.dispose(); + + return rotated; + } + + /** + * 翻转图片 + */ + private BufferedImage flipImage(BufferedImage image, boolean horizontal, boolean vertical) { + int width = image.getWidth(); + int height = image.getHeight(); + + BufferedImage flipped = new BufferedImage(width, height, image.getType()); + Graphics2D g = flipped.createGraphics(); + + if (horizontal && vertical) { + g.drawImage(image, width, height, -width, -height, null); + } else if (horizontal) { + g.drawImage(image, width, 0, -width, height, null); + } else if (vertical) { + g.drawImage(image, 0, height, width, -height, null); + } else { + g.drawImage(image, 0, 0, null); + } + + g.dispose(); + return flipped; + } + + private byte[] compressWithQuality(BufferedImage image, float quality) throws IOException { // 获取JPEG编码器 ImageWriter writer = ImageIO.getImageWritersByFormatName("jpeg").next();