1
This commit is contained in:
@@ -66,7 +66,13 @@ image:
|
|||||||
项目已添加以下依赖:
|
项目已添加以下依赖:
|
||||||
|
|
||||||
1. **Thumbnailator** (0.4.20):图片处理库
|
1. **Thumbnailator** (0.4.20):图片处理库
|
||||||
2. **webp-imageio** (0.1.0):WebP格式支持库
|
|
||||||
|
**注意**:WebP格式支持需要系统或JVM本身支持webp格式。如果系统不支持webp,转换功能会跳过webp图片并返回原URL,不会影响系统正常运行。
|
||||||
|
|
||||||
|
如需支持webp格式转换,可以:
|
||||||
|
- 使用支持webp的JVM版本
|
||||||
|
- 手动添加webp-imageio库到项目中
|
||||||
|
- 使用其他webp解码库
|
||||||
|
|
||||||
## API接口
|
## API接口
|
||||||
|
|
||||||
|
|||||||
18
pom.xml
18
pom.xml
@@ -119,12 +119,6 @@
|
|||||||
<artifactId>thumbnailator</artifactId>
|
<artifactId>thumbnailator</artifactId>
|
||||||
<version>0.4.20</version>
|
<version>0.4.20</version>
|
||||||
</dependency>
|
</dependency>
|
||||||
<!-- WebP图片格式支持 -->
|
|
||||||
<dependency>
|
|
||||||
<groupId>com.github.gotson</groupId>
|
|
||||||
<artifactId>webp-imageio</artifactId>
|
|
||||||
<version>0.1.0</version>
|
|
||||||
</dependency>
|
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
@@ -170,5 +164,17 @@
|
|||||||
<name>RocketMQ Repository</name>
|
<name>RocketMQ Repository</name>
|
||||||
<url>https://repo1.maven.org/maven2/org/apache/rocketmq/</url>
|
<url>https://repo1.maven.org/maven2/org/apache/rocketmq/</url>
|
||||||
</repository>
|
</repository>
|
||||||
|
<!-- Maven 中央仓库 -->
|
||||||
|
<repository>
|
||||||
|
<id>central</id>
|
||||||
|
<name>Maven Central Repository</name>
|
||||||
|
<url>https://repo1.maven.org/maven2</url>
|
||||||
|
<releases>
|
||||||
|
<enabled>true</enabled>
|
||||||
|
</releases>
|
||||||
|
<snapshots>
|
||||||
|
<enabled>false</enabled>
|
||||||
|
</snapshots>
|
||||||
|
</repository>
|
||||||
</repositories>
|
</repositories>
|
||||||
</project>
|
</project>
|
||||||
|
|||||||
@@ -10,12 +10,15 @@ import org.springframework.beans.factory.annotation.Autowired;
|
|||||||
import org.springframework.beans.factory.annotation.Value;
|
import org.springframework.beans.factory.annotation.Value;
|
||||||
import org.springframework.stereotype.Service;
|
import org.springframework.stereotype.Service;
|
||||||
|
|
||||||
|
import net.coobird.thumbnailator.Thumbnails;
|
||||||
import javax.imageio.ImageIO;
|
import javax.imageio.ImageIO;
|
||||||
import javax.imageio.ImageReader;
|
import javax.imageio.ImageReader;
|
||||||
import javax.imageio.stream.ImageInputStream;
|
import javax.imageio.stream.ImageInputStream;
|
||||||
import java.awt.image.BufferedImage;
|
import java.awt.image.BufferedImage;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
|
import java.io.ByteArrayOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.io.InputStream;
|
||||||
import java.nio.file.Files;
|
import java.nio.file.Files;
|
||||||
import java.nio.file.Path;
|
import java.nio.file.Path;
|
||||||
import java.nio.file.Paths;
|
import java.nio.file.Paths;
|
||||||
@@ -23,35 +26,37 @@ import java.time.LocalDateTime;
|
|||||||
import java.util.*;
|
import java.util.*;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* WebP图片IO支持
|
* WebP图片IO支持工具类
|
||||||
* 注册WebP图片格式的读写器
|
* 尝试使用可用的方式读取webp图片
|
||||||
*/
|
*/
|
||||||
class WebPImageIO {
|
class WebPImageIO {
|
||||||
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WebPImageIO.class);
|
private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(WebPImageIO.class);
|
||||||
private static volatile boolean initialized = false;
|
private static volatile boolean webpSupported = false;
|
||||||
|
private static volatile boolean checked = false;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 初始化WebP支持
|
* 检查是否支持webp格式
|
||||||
* webp-imageio库在类加载时会通过ServiceLoader自动注册到ImageIO
|
|
||||||
*/
|
*/
|
||||||
static synchronized void init() {
|
static synchronized boolean isWebPSupported() {
|
||||||
if (initialized) {
|
if (checked) {
|
||||||
return;
|
return webpSupported;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 检查是否支持webp格式
|
|
||||||
try {
|
try {
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("webp");
|
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("webp");
|
||||||
if (readers.hasNext()) {
|
webpSupported = readers.hasNext();
|
||||||
log.debug("WebP图片格式支持已启用");
|
if (webpSupported) {
|
||||||
|
log.info("WebP图片格式支持已启用");
|
||||||
} else {
|
} else {
|
||||||
log.warn("未检测到WebP图片格式支持,webp转换可能失败。请确认webp-imageio依赖已正确加载");
|
log.warn("未检测到WebP图片格式支持,webp图片转换将被跳过");
|
||||||
}
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("检查WebP支持时出错: {}", e.getMessage());
|
log.warn("检查WebP支持时出错: {}", e.getMessage());
|
||||||
|
webpSupported = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
initialized = true;
|
checked = true;
|
||||||
|
return webpSupported;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -102,8 +107,8 @@ public class ImageConvertService {
|
|||||||
String convertedUrl = convertImageUrl(imageUrl);
|
String convertedUrl = convertImageUrl(imageUrl);
|
||||||
convertedUrls.add(convertedUrl);
|
convertedUrls.add(convertedUrl);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("图片转换失败,使用原URL: {}, 错误: {}", imageUrl, e.getMessage());
|
// 转换失败时使用原URL,不中断流程
|
||||||
// 转换失败时使用原URL
|
log.warn("图片转换失败,使用原URL: {}. 错误: {}", imageUrl, e.getMessage());
|
||||||
convertedUrls.add(imageUrl);
|
convertedUrls.add(imageUrl);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -116,8 +121,9 @@ public class ImageConvertService {
|
|||||||
*
|
*
|
||||||
* @param originalUrl 原始图片URL
|
* @param originalUrl 原始图片URL
|
||||||
* @return 转换后的图片URL(如果不需要转换则返回原URL)
|
* @return 转换后的图片URL(如果不需要转换则返回原URL)
|
||||||
|
* @throws Exception 转换过程中的异常(调用方会捕获并返回原URL)
|
||||||
*/
|
*/
|
||||||
private String convertImageUrl(String originalUrl) {
|
private String convertImageUrl(String originalUrl) throws Exception {
|
||||||
if (StrUtil.isBlank(originalUrl)) {
|
if (StrUtil.isBlank(originalUrl)) {
|
||||||
return originalUrl;
|
return originalUrl;
|
||||||
}
|
}
|
||||||
@@ -127,6 +133,12 @@ public class ImageConvertService {
|
|||||||
return originalUrl;
|
return originalUrl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 检查系统是否支持webp转换
|
||||||
|
if (!WebPImageIO.isWebPSupported()) {
|
||||||
|
log.debug("系统不支持webp格式,跳过转换: {}", originalUrl);
|
||||||
|
throw new IOException("系统不支持webp格式转换");
|
||||||
|
}
|
||||||
|
|
||||||
// 检查是否已转换
|
// 检查是否已转换
|
||||||
Optional<ImageConversion> existing = imageConversionRepository.findByOriginalUrl(originalUrl);
|
Optional<ImageConversion> existing = imageConversionRepository.findByOriginalUrl(originalUrl);
|
||||||
if (existing.isPresent()) {
|
if (existing.isPresent()) {
|
||||||
@@ -136,14 +148,9 @@ public class ImageConvertService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 执行转换
|
// 执行转换
|
||||||
try {
|
String convertedUrl = performConversion(originalUrl);
|
||||||
String convertedUrl = performConversion(originalUrl);
|
log.info("图片转换成功: {} -> {}", originalUrl, convertedUrl);
|
||||||
log.info("图片转换成功: {} -> {}", originalUrl, convertedUrl);
|
return convertedUrl;
|
||||||
return convertedUrl;
|
|
||||||
} catch (Exception e) {
|
|
||||||
log.error("图片转换失败: {}, 错误: {}", originalUrl, e.getMessage(), e);
|
|
||||||
throw e;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -202,34 +209,45 @@ public class ImageConvertService {
|
|||||||
// 转换图片格式
|
// 转换图片格式
|
||||||
BufferedImage bufferedImage = null;
|
BufferedImage bufferedImage = null;
|
||||||
try {
|
try {
|
||||||
// 初始化WebP支持
|
// 检查是否支持webp格式
|
||||||
WebPImageIO.init();
|
boolean webpSupported = WebPImageIO.isWebPSupported();
|
||||||
|
|
||||||
// 尝试使用ImageIO读取
|
if (webpSupported) {
|
||||||
BufferedImage tempImage = null;
|
// 如果支持webp,尝试使用ImageIO读取
|
||||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(imageData)) {
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(imageData)) {
|
||||||
tempImage = ImageIO.read(bais);
|
bufferedImage = ImageIO.read(bais);
|
||||||
}
|
|
||||||
|
|
||||||
if (tempImage != null) {
|
|
||||||
bufferedImage = tempImage;
|
|
||||||
} else {
|
|
||||||
// 如果ImageIO无法读取,尝试使用WebP特定的读取器
|
|
||||||
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("webp");
|
|
||||||
if (readers.hasNext()) {
|
|
||||||
ImageReader reader = readers.next();
|
|
||||||
try (ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
|
|
||||||
ImageInputStream iis = ImageIO.createImageInputStream(bais)) {
|
|
||||||
reader.setInput(iis);
|
|
||||||
bufferedImage = reader.read(0);
|
|
||||||
} finally {
|
|
||||||
reader.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 如果ImageIO无法读取,尝试使用WebP特定的读取器
|
||||||
if (bufferedImage == null) {
|
if (bufferedImage == null) {
|
||||||
throw new IOException("无法读取webp图片格式,请确认已添加webp-imageio依赖");
|
Iterator<ImageReader> readers = ImageIO.getImageReadersByFormatName("webp");
|
||||||
|
if (readers.hasNext()) {
|
||||||
|
ImageReader reader = readers.next();
|
||||||
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(imageData);
|
||||||
|
ImageInputStream iis = ImageIO.createImageInputStream(bais)) {
|
||||||
|
reader.setInput(iis);
|
||||||
|
bufferedImage = reader.read(0);
|
||||||
|
} finally {
|
||||||
|
reader.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// 如果不支持webp,尝试使用Thumbnailator转换
|
||||||
|
// 注意:Thumbnailator内部也使用ImageIO,所以通常也无法处理webp
|
||||||
|
try (ByteArrayInputStream bais = new ByteArrayInputStream(imageData)) {
|
||||||
|
bufferedImage = Thumbnails.of(bais)
|
||||||
|
.scale(1.0)
|
||||||
|
.asBufferedImage();
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.debug("Thumbnailator无法读取webp图片: {}", e.getMessage());
|
||||||
|
// 如果无法转换,抛出异常,后续会返回原URL
|
||||||
|
throw new IOException("当前系统不支持webp格式转换。图片将保持原格式返回。", e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bufferedImage == null) {
|
||||||
|
throw new IOException("无法读取webp图片格式。当前系统不支持webp格式转换。");
|
||||||
}
|
}
|
||||||
|
|
||||||
// 如果是RGBA格式,转换为RGB
|
// 如果是RGBA格式,转换为RGB
|
||||||
|
|||||||
Reference in New Issue
Block a user