@@ -4,6 +4,7 @@ import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page ;
import com.rj.entity.ImageModel ;
import com.rj.service.IImageModelService ;
import com.rj.utils.ImageConversionUtil ;
import io.swagger.v3.oas.annotations.Operation ;
import io.swagger.v3.oas.annotations.Parameter ;
import io.swagger.v3.oas.annotations.tags.Tag ;
@@ -21,6 +22,8 @@ import jakarta.validation.constraints.NotBlank;
import java.time.LocalDateTime ;
import java.util.HashMap ;
import java.util.Map ;
import java.util.List ;
import java.util.ArrayList ;
import org.springframework.http.HttpEntity ;
import org.springframework.http.HttpHeaders ;
import org.springframework.http.HttpMethod ;
@@ -553,6 +556,9 @@ public class ImageModelController {
if ( modelName ! = null & & ! modelName . trim ( ) . isEmpty ( ) ) {
queryWrapper . like ( ImageModel : : getModelName , modelName ) ;
}
if ( imageName ! = null & & ! imageName . trim ( ) . isEmpty ( ) ) {
queryWrapper . like ( ImageModel : : getImageName , imageName ) ;
}
if ( imageType ! = null & & ! imageType . trim ( ) . isEmpty ( ) ) {
queryWrapper . eq ( ImageModel : : getImageType , imageType ) ;
}
@@ -560,9 +566,9 @@ public class ImageModelController {
queryWrapper . ge ( ImageModel : : getCreateTime , startTime ) ;
}
if ( endTime ! = null & & ! endTime . trim ( ) . isEmpty ( ) ) {
queryWrapper . le ( ImageModel : : getCre ateTime , endTime ) ;
queryWrapper . le ( ImageModel : : getUpd ateTime , endTime ) ;
}
// 按创建时间降序排列
queryWrapper . orderByDesc ( ImageModel : : getUpdateTime ) ;
@@ -673,7 +679,7 @@ public class ImageModelController {
}
/**
* 图像处理接口
* 图像处理接口,根据给的素材生成图片
*/
@PostMapping ( " /image-background " )
@Operation ( summary = " 图像处理 " , description = " 基于参考图像和提示词进行图像处理 " )
@@ -713,6 +719,8 @@ public class ImageModelController {
return ResponseEntity . status ( HttpStatus . INTERNAL_SERVER_ERROR ) . body ( result ) ;
}
}
@Autowired
ImageConversionUtil imageConversionUtil ;
/**
* 执行图像处理的方法 - 调用阿里云API
*/
@@ -725,15 +733,77 @@ public class ImageModelController {
request . getBaseImageUrl ( ) , request . getRefImageUrl ( ) ) ;
// 处理引导图像RGBA转换( 如果存在引导图像)
if ( request . getRef ImageUrl ( ) ! = null & & ! request . getRef ImageUrl ( ) . trim ( ) . isEmpty ( ) ) {
if ( request . getBase ImageUrl ( ) ! = null & & ! request . getBase ImageUrl ( ) . trim ( ) . isEmpty ( ) ) {
log . info ( " 检测到引导图像, 开始进行RGBA转换处理 " ) ;
String processedRefImageUrl = processRefImageForRGBA ( request . getRef ImageUrl ( ) ) ;
byte [ ] bytes = imageConversionUtil . convertImageToAliyunFormatAdvanced ( request . getBase ImageUrl ( ) ) ;
String processedRefImageUrl = uploadFile ( bytes ) ;
if ( processedRefImageUrl ! = null ) {
log . info ( " 引导 图像RGBA转换完成, 新URL: {}" , processedRefImageUrl ) ;
request . setRef ImageUrl ( processedRefImageUrl ) ;
log . info ( " 产品主图baseImage 图像RGBA转换完成, 新URL: {}" , processedRefImageUrl ) ;
request . setBase ImageUrl ( processedRefImageUrl ) ;
}
}
// 处理前景边缘图像转换
if ( request . getReferenceEdge ( ) ! = null & & request . getReferenceEdge ( ) . getForegroundEdge ( ) ! = null ) {
String [ ] originalForegroundEdges = request . getReferenceEdge ( ) . getForegroundEdge ( ) ;
String [ ] backgroundEdges = request . getReferenceEdge ( ) . getBackgroundEdge ( ) ;
List < String > processedForegroundEdges = new ArrayList < > ( ) ;
List < String > processedbackgroundEdges = new ArrayList < > ( ) ;
// 1, 背景图边处理
for ( String backgroundEdge : backgroundEdges ) {
byte [ ] bytes = imageConversionUtil . convertImageToAliyunFormatAdvanced ( backgroundEdge ) ;
String processedRefImageUrl = uploadFile ( bytes ) ;
if ( processedRefImageUrl ! = null ) {
log . info ( " 产品主图baseImage图像RGBA转换完成, 新URL: {} " , processedRefImageUrl ) ;
processedbackgroundEdges . add ( processedRefImageUrl ) ;
}
}
// 2, 前景图边处理
for ( String foregroundEdgeUrl : originalForegroundEdges ) {
if ( foregroundEdgeUrl ! = null & & ! foregroundEdgeUrl . trim ( ) . isEmpty ( ) ) {
log . info ( " 开始进行ForegroundEdge的RGBA转换处理: {} " , foregroundEdgeUrl ) ;
try {
byte [ ] bytes = imageConversionUtil . convertImageToAliyunFormatAdvanced ( foregroundEdgeUrl ) ;
if ( bytes ! = null ) {
String processedRefImageUrl = uploadFile ( bytes ) ;
if ( processedRefImageUrl ! = null & & ! processedRefImageUrl . trim ( ) . isEmpty ( ) ) {
log . info ( " ForegroundEdge图像RGBA转换完成, 新URL: {} " , processedRefImageUrl ) ;
processedForegroundEdges . add ( processedRefImageUrl ) ;
} else {
log . warn ( " ForegroundEdge图像上传失败, 跳过此URL: {} " , foregroundEdgeUrl ) ;
}
} else {
log . warn ( " ForegroundEdge图像转换失败, 跳过此URL: {} " , foregroundEdgeUrl ) ;
}
} catch ( Exception e ) {
log . error ( " 处理ForegroundEdge图像时发生异常: {} " , foregroundEdgeUrl , e ) ;
}
} else {
log . warn ( " 发现空的ForegroundEdge URL, 跳过处理 " ) ;
}
}
// 只有当成功处理了至少一个URL时才更新
if ( ! processedForegroundEdges . isEmpty ( ) ) {
String [ ] newForegroundEdges = processedForegroundEdges . toArray ( new String [ 0 ] ) ;
request . getReferenceEdge ( ) . setForegroundEdge ( newForegroundEdges ) ;
log . info ( " 成功处理{}个ForegroundEdge图像 " , newForegroundEdges . length ) ;
} else {
log . warn ( " 没有成功处理任何ForegroundEdge图像, 将使用原始URL " ) ;
}
if ( ! processedbackgroundEdges . isEmpty ( ) ) {
String [ ] processedbackgroundEdgess = processedbackgroundEdges . toArray ( new String [ 0 ] ) ;
request . getReferenceEdge ( ) . setBackgroundEdge ( processedbackgroundEdgess ) ;
log . info ( " 成功处理{}个processedbackgroundEdgess e图像 " , processedbackgroundEdgess . length ) ;
}
}
// 构建阿里云请求参数
Map < String , Object > aliyunRequest = buildAliyunRequest ( request ) ;
@@ -778,30 +848,25 @@ public class ImageModelController {
}
/**
* 处理引导图像RGBA转换
*
*
* 下载引导图像, 转换为RGBA格式, 上传到MinIO并生成新的临时访问链接
* 上传到MinIO并生成新的临时访问链接
*
* @param refImageUrl 原始引导图像URL
* @param
* @return 处理后的RGBA图像临时访问链接, 如果处理失败返回null
*/
private String processRefImageForRGBA ( String refImageUrl ) {
private String uploadFile ( byte [ ] originalImageBytes ) {
try {
log . info ( " 开始处理引导图像RGBA转换, 原始URL: {} " , refImageUrl );
log . info ( " 开始处理引导图像RGBA转换, 原始URL: " ) ;
// 1. 下载原始图像
byte [ ] originalImageBytes = downloadImageFromUrl ( refImageUrl ) ;
log . info ( " 原始图像下载完成,大小: {} bytes " , originalImageBytes . length ) ;
// 2. 转换为RGBA格式
byte [ ] rgbaImageBytes = convertImageToRGBA ( originalImageBytes ) ;
log . info ( " 图像RGBA转换完成, 大小: {} bytes " , rgbaImageBytes . length ) ;
// 3. 生成唯一文件名
String uniqueFileName = generateUniqueFileName ( " png " ) ;
// 4. 上传RGBA图像到MinIO
String materialUrl = minIOService . uploadFile ( rgba ImageBytes, uniqueFileName , " image/png " ) ;
String materialUrl = minIOService . uploadFile ( original ImageBytes, uniqueFileName , " image/png " ) ;
log . info ( " RGBA图像上传到MinIO成功: {} " , materialUrl ) ;
// 5. 生成7天临时访问链接
@@ -811,7 +876,7 @@ public class ImageModelController {
return materialTempUrl ;
} catch ( Exception e ) {
log . error ( " 处理引导图像RGBA转换失败: {} " , refImageUrl , e ) ;
log . error ( " 处理引导图像RGBA转换失败: {} " , e ) ;
return null ;
}
}
@@ -823,7 +888,7 @@ public class ImageModelController {
* @return 图像字节数组
* @throws IOException 下载失败时抛出异常
*/
private byte [ ] downloadImageFromUrl ( String imageUrl ) throws IOException {
private byte [ ] downloadImageFromUrl11 ( String imageUrl ) throws IOException {
try {
log . info ( " 开始下载图像: {} " , imageUrl ) ;
@@ -847,69 +912,7 @@ public class ImageModelController {
}
}
/**
* 将图像转换为RGBA格式
*
* @param imageBytes 原始图像字节数组
* @return RGBA格式的图像字节数组
* @throws IOException 转换失败时抛出异常
*/
private byte [ ] convertImageToRGBA ( byte [ ] imageBytes ) throws IOException {
try {
log . info ( " 开始转换图像为RGBA格式 " ) ;
// 从字节数组读取图像
ByteArrayInputStream bais = new ByteArrayInputStream ( imageBytes ) ;
java . awt . image . BufferedImage originalImage = javax . imageio . ImageIO . read ( bais ) ;
if ( originalImage = = null ) {
throw new IllegalArgumentException ( " 无法读取图像文件 " ) ;
}
int width = originalImage . getWidth ( ) ;
int height = originalImage . getHeight ( ) ;
// 验证图像尺寸
int maxDimension = Math . max ( width , height ) ;
if ( maxDimension > 2048 ) {
throw new IllegalArgumentException ( " 图像长边不能超过2048像素, 当前尺寸: " + width + " x " + height ) ;
}
log . info ( " 原始图像尺寸: {}x{} " , width , height ) ;
// 创建RGBA格式的图像
java . awt . image . BufferedImage rgbaImage = new java . awt . image . BufferedImage (
width , height , java . awt . image . BufferedImage . TYPE_INT_ARGB ) ;
// 获取图形上下文
java . awt . Graphics2D g2d = rgbaImage . createGraphics ( ) ;
// 设置渲染提示以获得更好的质量
g2d . setRenderingHint ( java . awt . RenderingHints . KEY_INTERPOLATION ,
java . awt . RenderingHints . VALUE_INTERPOLATION_BILINEAR ) ;
g2d . setRenderingHint ( java . awt . RenderingHints . KEY_RENDERING ,
java . awt . RenderingHints . VALUE_RENDER_QUALITY ) ;
g2d . setRenderingHint ( java . awt . RenderingHints . KEY_ANTIALIASING ,
java . awt . RenderingHints . VALUE_ANTIALIAS_ON ) ;
// 绘制原始图像到RGBA图像上
g2d . drawImage ( originalImage , 0 , 0 , null ) ;
g2d . dispose ( ) ;
// 将RGBA图像转换为字节数组
ByteArrayOutputStream baos = new ByteArrayOutputStream ( ) ;
javax . imageio . ImageIO . write ( rgbaImage , " PNG " , baos ) ;
byte [ ] rgbaBytes = baos . toByteArray ( ) ;
log . info ( " 图像RGBA转换完成, 大小: {} bytes " , rgbaBytes . length ) ;
return rgbaBytes ;
} catch ( Exception e ) {
log . error ( " 转换图像为RGBA格式失败 " , e ) ;
throw new IOException ( " 转换图像为RGBA格式失败: " + e . getMessage ( ) , e ) ;
}
}
/**
* 生成唯一文件名
*
@@ -940,11 +943,76 @@ public class ImageModelController {
// 构建reference_edge参数
if ( request . getReferenceEdge ( ) ! = null ) {
Map < String , Object > referenceEdge = new HashMap < > ( ) ;
referenceEdge . put ( " foreground_edge " , request . getReferenceEdge ( ) . getForegroundEdge ( ) ) ;
referenceEdge . put ( " background_edge " , request . getReferenceEdge ( ) . getBackgroundEdge ( ) ) ;
referenceEdge . put ( " foreground_edge_prompt " , request . getReferenceEdge ( ) . getForegroundEdgePrompt ( ) ) ;
referenceEdge . put ( " background_edge_prompt " , request . getReferenceEdge ( ) . getBackgroundEdgePrompt ( ) ) ;
// 处理前景边缘URL, 过滤掉null值和无效URL
if ( request . getReferenceEdge ( ) . getForegroundEdge ( ) ! = null ) {
List < String > validForegroundEdges = new ArrayList < > ( ) ;
for ( String url : request . getReferenceEdge ( ) . getForegroundEdge ( ) ) {
if ( isValidUrl ( url ) ) {
validForegroundEdges . add ( url ) ;
} else {
log . warn ( " 跳过无效的前景边缘URL: {} " , url ) ;
}
}
if ( ! validForegroundEdges . isEmpty ( ) ) {
referenceEdge . put ( " foreground_edge " , validForegroundEdges . toArray ( new String [ 0 ] ) ) ;
log . info ( " 添加{}个有效的前景边缘URL " , validForegroundEdges . size ( ) ) ;
} else {
log . warn ( " 没有有效的前景边缘URL " ) ;
}
}
// 处理背景边缘URL, 过滤掉null值和无效URL
if ( request . getReferenceEdge ( ) . getBackgroundEdge ( ) ! = null ) {
List < String > validBackgroundEdges = new ArrayList < > ( ) ;
for ( String url : request . getReferenceEdge ( ) . getBackgroundEdge ( ) ) {
if ( isValidUrl ( url ) ) {
validBackgroundEdges . add ( url ) ;
} else {
log . warn ( " 跳过无效的背景边缘URL: {} " , url ) ;
}
}
if ( ! validBackgroundEdges . isEmpty ( ) ) {
referenceEdge . put ( " background_edge " , validBackgroundEdges . toArray ( new String [ 0 ] ) ) ;
log . info ( " 添加{}个有效的背景边缘URL " , validBackgroundEdges . size ( ) ) ;
} else {
log . warn ( " 没有有效的背景边缘URL " ) ;
}
}
// 处理前景边缘提示词, 过滤掉null值
if ( request . getReferenceEdge ( ) . getForegroundEdgePrompt ( ) ! = null ) {
List < String > validForegroundPrompts = new ArrayList < > ( ) ;
for ( String prompt : request . getReferenceEdge ( ) . getForegroundEdgePrompt ( ) ) {
if ( prompt ! = null & & ! prompt . trim ( ) . isEmpty ( ) ) {
validForegroundPrompts . add ( prompt ) ;
}
}
if ( ! validForegroundPrompts . isEmpty ( ) ) {
referenceEdge . put ( " foreground_edge_prompt " , validForegroundPrompts . toArray ( new String [ 0 ] ) ) ;
}
}
// 处理背景边缘提示词, 过滤掉null值
if ( request . getReferenceEdge ( ) . getBackgroundEdgePrompt ( ) ! = null ) {
List < String > validBackgroundPrompts = new ArrayList < > ( ) ;
for ( String prompt : request . getReferenceEdge ( ) . getBackgroundEdgePrompt ( ) ) {
if ( prompt ! = null & & ! prompt . trim ( ) . isEmpty ( ) ) {
validBackgroundPrompts . add ( prompt ) ;
}
}
if ( ! validBackgroundPrompts . isEmpty ( ) ) {
referenceEdge . put ( " background_edge_prompt " , validBackgroundPrompts . toArray ( new String [ 0 ] ) ) ;
}
}
// 只有当referenceEdge不为空时才添加到input中
if ( ! referenceEdge . isEmpty ( ) ) {
input . put ( " reference_edge " , referenceEdge ) ;
log . info ( " 添加reference_edge参数, 包含{}个字段 " , referenceEdge . size ( ) ) ;
} else {
log . warn ( " reference_edge参数为空, 跳过添加 " ) ;
}
}
aliyunRequest . put ( " input " , input ) ;
@@ -1156,6 +1224,32 @@ public class ImageModelController {
}
}
/**
* 验证URL是否有效
*
* @param url 要验证的URL
* @return 是否为有效URL
*/
private boolean isValidUrl ( String url ) {
if ( url = = null | | url . trim ( ) . isEmpty ( ) ) {
return false ;
}
try {
// 基本URL格式验证
if ( ! url . startsWith ( " http:// " ) & & ! url . startsWith ( " https:// " ) ) {
return false ;
}
// 尝试解析URL
new java . net . URL ( url ) ;
return true ;
} catch ( Exception e ) {
log . warn ( " URL格式无效: {} " , url ) ;
return false ;
}
}
/**
* 生成请求ID
*/