This commit is contained in:
2025-11-03 15:26:52 +08:00
parent 6b36f0ee52
commit 89b37907e7
3 changed files with 84 additions and 54 deletions

View File

@@ -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
View File

@@ -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>

View File

@@ -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