You've already forked FrameTour-BE
feat(image): 实现图像增强与质量检测功能
- 新增ImageEnhancerFactory工厂类,支持创建不同类型的图像增强器 - 添加图像清晰度增强和超分辨率两种增强模式 - 实现ImageEnhanceStage图像增强处理阶段 - 新增ImageQualityCheckStage图像质量检测阶段 - 支持根据图片质量动态添加图像增强处理 - 完善Stage配置注解和可选性控制机制 - 优化Pipeline执行流程,支持动态插入Stage - 增加Stage执行计数和循环依赖防护机制 - 改进StageResult结构,支持携带后续Stage列表 - 统一抽象Stage的执行条件判断逻辑
This commit is contained in:
@@ -1,4 +1,62 @@
|
|||||||
package com.ycwl.basic.image.enhancer;
|
package com.ycwl.basic.image.enhancer;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.enhancer.adapter.BceImageEnhancer;
|
||||||
|
import com.ycwl.basic.image.enhancer.adapter.BceImageSR;
|
||||||
|
import com.ycwl.basic.image.enhancer.adapter.IEnhancer;
|
||||||
|
import com.ycwl.basic.image.enhancer.entity.BceEnhancerConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像增强器工厂
|
||||||
|
* 用于创建不同类型的图像增强器实例
|
||||||
|
*/
|
||||||
public class ImageEnhancerFactory {
|
public class ImageEnhancerFactory {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 增强器类型枚举
|
||||||
|
*/
|
||||||
|
public enum EnhancerType {
|
||||||
|
/**
|
||||||
|
* 图像清晰度增强
|
||||||
|
* 使用imageDefinitionEnhance接口,适合提升整体清晰度
|
||||||
|
*/
|
||||||
|
DEFINITION_ENHANCE,
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像超分辨率
|
||||||
|
* 使用imageQualityEnhance接口,适合放大图片同时保持质量
|
||||||
|
*/
|
||||||
|
SUPER_RESOLUTION
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建图像增强器
|
||||||
|
*
|
||||||
|
* @param type 增强器类型
|
||||||
|
* @param config 百度云配置
|
||||||
|
* @return 图像增强器实例
|
||||||
|
*/
|
||||||
|
public static IEnhancer createEnhancer(EnhancerType type, BceEnhancerConfig config) {
|
||||||
|
IEnhancer enhancer = switch (type) {
|
||||||
|
case DEFINITION_ENHANCE -> new BceImageEnhancer();
|
||||||
|
case SUPER_RESOLUTION -> new BceImageSR();
|
||||||
|
};
|
||||||
|
|
||||||
|
if (enhancer instanceof BceImageEnhancer) {
|
||||||
|
((BceImageEnhancer) enhancer).setConfig(config);
|
||||||
|
} else if (enhancer instanceof BceImageSR) {
|
||||||
|
((BceImageSR) enhancer).setConfig(config);
|
||||||
|
}
|
||||||
|
|
||||||
|
return enhancer;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 创建默认的图像增强器(清晰度增强)
|
||||||
|
*
|
||||||
|
* @param config 百度云配置
|
||||||
|
* @return 图像增强器实例
|
||||||
|
*/
|
||||||
|
public static IEnhancer createDefaultEnhancer(BceEnhancerConfig config) {
|
||||||
|
return createEnhancer(EnhancerType.DEFINITION_ENHANCE, config);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.ycwl.basic.image.pipeline.core;
|
package com.ycwl.basic.image.pipeline.core;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,11 +12,46 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
public abstract class AbstractPipelineStage<C extends PhotoProcessContext> implements PipelineStage<C> {
|
public abstract class AbstractPipelineStage<C extends PhotoProcessContext> implements PipelineStage<C> {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 默认总是执行
|
* 最终的shouldExecute判断
|
||||||
* 子类可以覆盖此方法实现条件性执行
|
* 整合了外部配置控制和业务逻辑判断
|
||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldExecute(C context) {
|
public final boolean shouldExecute(C context) {
|
||||||
|
// 1. 检查Stage配置注解
|
||||||
|
StageConfig config = getStageConfig();
|
||||||
|
if (config != null) {
|
||||||
|
String stageId = config.stageId();
|
||||||
|
StageOptionalMode mode = config.optionalMode();
|
||||||
|
|
||||||
|
// FORCE_ON:强制执行,不检查外部配置
|
||||||
|
if (mode == StageOptionalMode.FORCE_ON) {
|
||||||
|
return shouldExecuteByBusinessLogic(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
// SUPPORT:检查外部配置
|
||||||
|
if (mode == StageOptionalMode.SUPPORT) {
|
||||||
|
boolean externalEnabled = context.isStageEnabled(stageId, config.defaultEnabled());
|
||||||
|
if (!externalEnabled) {
|
||||||
|
log.debug("[{}] Stage被外部配置禁用", stageId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// UNSUPPORT:不检查外部配置,直接走业务逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
// 2. 执行业务逻辑判断
|
||||||
|
return shouldExecuteByBusinessLogic(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 子类实现业务逻辑判断
|
||||||
|
* 默认总是执行
|
||||||
|
*
|
||||||
|
* 子类可以覆盖此方法实现条件性执行
|
||||||
|
* 例如: 只有竖图才旋转, 只有普通照片才加水印等
|
||||||
|
*/
|
||||||
|
protected boolean shouldExecuteByBusinessLogic(C context) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ import lombok.Getter;
|
|||||||
import lombok.Setter;
|
import lombok.Setter;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 图片处理管线上下文
|
* 图片处理管线上下文
|
||||||
@@ -41,6 +43,13 @@ public class PhotoProcessContext {
|
|||||||
*/
|
*/
|
||||||
private ImageSource source;
|
private ImageSource source;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Stage开关配置表
|
||||||
|
* Key: stageId, Value: 是否启用
|
||||||
|
* 整合了景区配置和请求参数
|
||||||
|
*/
|
||||||
|
private Map<String, Boolean> stageEnabledMap = new HashMap<>();
|
||||||
|
|
||||||
private File originalFile;
|
private File originalFile;
|
||||||
private File processedFile;
|
private File processedFile;
|
||||||
private boolean isLandscape = true;
|
private boolean isLandscape = true;
|
||||||
@@ -61,6 +70,30 @@ public class PhotoProcessContext {
|
|||||||
this.tempFileManager = new TempFileManager(orderItem.getId().toString());
|
this.tempFileManager = new TempFileManager(orderItem.getId().toString());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 从景区配置和请求参数中加载Stage开关配置
|
||||||
|
*
|
||||||
|
* @param scenicConfigManager 景区配置管理器
|
||||||
|
* @param requestParams 请求参数中的Stage配置
|
||||||
|
*/
|
||||||
|
public void loadStageConfig(ScenicConfigManager scenicConfigManager, Map<String, Boolean> requestParams) {
|
||||||
|
// 请求参数覆盖
|
||||||
|
if (requestParams != null) {
|
||||||
|
stageEnabledMap.putAll(requestParams);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 判断指定Stage是否启用
|
||||||
|
*
|
||||||
|
* @param stageId Stage唯一标识
|
||||||
|
* @param defaultEnabled 默认值(当配置未指定时使用)
|
||||||
|
* @return true-启用, false-禁用
|
||||||
|
*/
|
||||||
|
public boolean isStageEnabled(String stageId, boolean defaultEnabled) {
|
||||||
|
return stageEnabledMap.getOrDefault(stageId, defaultEnabled);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 是否为拼图类型
|
* 是否为拼图类型
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -31,9 +31,16 @@ public class Pipeline<C extends PhotoProcessContext> {
|
|||||||
public boolean execute(C context) {
|
public boolean execute(C context) {
|
||||||
log.info("[{}] 开始执行管线, Stage数量: {}", name, stages.size());
|
log.info("[{}] 开始执行管线, Stage数量: {}", name, stages.size());
|
||||||
long startTime = System.currentTimeMillis();
|
long startTime = System.currentTimeMillis();
|
||||||
|
int maxStages = 100; // 防止无限循环
|
||||||
|
int executedCount = 0;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
for (int i = 0; i < stages.size(); i++) {
|
for (int i = 0; i < stages.size(); i++) {
|
||||||
|
if (executedCount >= maxStages) {
|
||||||
|
log.error("[{}] Stage执行数量超过最大限制({}),可能存在循环依赖", name, maxStages);
|
||||||
|
throw new PipelineException("Stage执行数量超过最大限制,可能存在循环依赖");
|
||||||
|
}
|
||||||
|
|
||||||
PipelineStage<C> stage = stages.get(i);
|
PipelineStage<C> stage = stages.get(i);
|
||||||
String stageName = stage.getName();
|
String stageName = stage.getName();
|
||||||
|
|
||||||
@@ -47,9 +54,22 @@ public class Pipeline<C extends PhotoProcessContext> {
|
|||||||
long stageStartTime = System.currentTimeMillis();
|
long stageStartTime = System.currentTimeMillis();
|
||||||
StageResult result = stage.execute(context);
|
StageResult result = stage.execute(context);
|
||||||
long stageDuration = System.currentTimeMillis() - stageStartTime;
|
long stageDuration = System.currentTimeMillis() - stageStartTime;
|
||||||
|
executedCount++;
|
||||||
|
|
||||||
logStageResult(stageName, result, stageDuration);
|
logStageResult(stageName, result, stageDuration);
|
||||||
|
|
||||||
|
// 动态添加后续Stage
|
||||||
|
if (result.getNextStages() != null && !result.getNextStages().isEmpty()) {
|
||||||
|
List<PipelineStage<?>> nextStages = result.getNextStages();
|
||||||
|
log.info("[{}] Stage {} 动态添加了 {} 个后续Stage", name, stageName, nextStages.size());
|
||||||
|
|
||||||
|
for (int j = 0; j < nextStages.size(); j++) {
|
||||||
|
PipelineStage<?> nextStage = nextStages.get(j);
|
||||||
|
stages.add(i + 1 + j, (PipelineStage<C>) nextStage);
|
||||||
|
log.debug("[{}] - 插入Stage: {} 到位置 {}", name, nextStage.getName(), i + 1 + j);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (result.isFailed()) {
|
if (result.isFailed()) {
|
||||||
log.error("[{}] Stage {} 执行失败,管线终止", name, stageName);
|
log.error("[{}] Stage {} 执行失败,管线终止", name, stageName);
|
||||||
return false;
|
return false;
|
||||||
@@ -57,7 +77,8 @@ public class Pipeline<C extends PhotoProcessContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
long totalDuration = System.currentTimeMillis() - startTime;
|
long totalDuration = System.currentTimeMillis() - startTime;
|
||||||
log.info("[{}] 管线执行完成, 耗时: {}ms", name, totalDuration);
|
log.info("[{}] 管线执行完成, 总Stage数: {}, 实际执行: {}, 耗时: {}ms",
|
||||||
|
name, stages.size(), executedCount, totalDuration);
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
package com.ycwl.basic.image.pipeline.core;
|
package com.ycwl.basic.image.pipeline.core;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 管线处理阶段接口
|
* 管线处理阶段接口
|
||||||
* 每个Stage负责一个独立的图片处理步骤
|
* 每个Stage负责一个独立的图片处理步骤
|
||||||
@@ -37,4 +39,12 @@ public interface PipelineStage<C extends PhotoProcessContext> {
|
|||||||
default int getPriority() {
|
default int getPriority() {
|
||||||
return 100;
|
return 100;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取Stage配置注解(用于反射读取可选性控制信息)
|
||||||
|
* @return Stage配置注解,如果未标注则返回null
|
||||||
|
*/
|
||||||
|
default StageConfig getStageConfig() {
|
||||||
|
return this.getClass().getAnnotation(StageConfig.class);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,11 @@ package com.ycwl.basic.image.pipeline.core;
|
|||||||
|
|
||||||
import lombok.Getter;
|
import lombok.Getter;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Stage执行结果
|
* Stage执行结果
|
||||||
*/
|
*/
|
||||||
@@ -18,39 +23,56 @@ public class StageResult {
|
|||||||
private final Status status;
|
private final Status status;
|
||||||
private final String message;
|
private final String message;
|
||||||
private final Throwable exception;
|
private final Throwable exception;
|
||||||
|
private final List<PipelineStage<?>> nextStages;
|
||||||
|
|
||||||
private StageResult(Status status, String message, Throwable exception) {
|
private StageResult(Status status, String message, Throwable exception, List<PipelineStage<?>> nextStages) {
|
||||||
this.status = status;
|
this.status = status;
|
||||||
this.message = message;
|
this.message = message;
|
||||||
this.exception = exception;
|
this.exception = exception;
|
||||||
|
this.nextStages = nextStages != null ? new ArrayList<>(nextStages) : Collections.emptyList();
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StageResult success() {
|
public static StageResult success() {
|
||||||
return new StageResult(Status.SUCCESS, null, null);
|
return new StageResult(Status.SUCCESS, null, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StageResult success(String message) {
|
public static StageResult success(String message) {
|
||||||
return new StageResult(Status.SUCCESS, message, null);
|
return new StageResult(Status.SUCCESS, message, null, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功执行并动态添加后续Stage
|
||||||
|
*/
|
||||||
|
@SafeVarargs
|
||||||
|
public static StageResult successWithNext(String message, PipelineStage<?>... stages) {
|
||||||
|
return new StageResult(Status.SUCCESS, message, null, Arrays.asList(stages));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 成功执行并动态添加后续Stage列表
|
||||||
|
*/
|
||||||
|
public static StageResult successWithNext(String message, List<PipelineStage<?>> stages) {
|
||||||
|
return new StageResult(Status.SUCCESS, message, null, stages);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StageResult skipped() {
|
public static StageResult skipped() {
|
||||||
return new StageResult(Status.SKIPPED, "条件不满足,跳过执行", null);
|
return new StageResult(Status.SKIPPED, "条件不满足,跳过执行", null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StageResult skipped(String reason) {
|
public static StageResult skipped(String reason) {
|
||||||
return new StageResult(Status.SKIPPED, reason, null);
|
return new StageResult(Status.SKIPPED, reason, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StageResult failed(String message) {
|
public static StageResult failed(String message) {
|
||||||
return new StageResult(Status.FAILED, message, null);
|
return new StageResult(Status.FAILED, message, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StageResult failed(String message, Throwable exception) {
|
public static StageResult failed(String message, Throwable exception) {
|
||||||
return new StageResult(Status.FAILED, message, exception);
|
return new StageResult(Status.FAILED, message, exception, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static StageResult degraded(String message) {
|
public static StageResult degraded(String message) {
|
||||||
return new StageResult(Status.DEGRADED, message, null);
|
return new StageResult(Status.DEGRADED, message, null, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isSuccess() {
|
public boolean isSuccess() {
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.ycwl.basic.image.pipeline.stages;
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
import com.ycwl.basic.image.pipeline.core.StageResult;
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -10,6 +12,12 @@ import lombok.extern.slf4j.Slf4j;
|
|||||||
* 总是在管线最后执行,清理所有临时文件
|
* 总是在管线最后执行,清理所有临时文件
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "cleanup",
|
||||||
|
optionalMode = StageOptionalMode.FORCE_ON,
|
||||||
|
description = "清理临时文件",
|
||||||
|
defaultEnabled = true
|
||||||
|
)
|
||||||
public class CleanupStage extends AbstractPipelineStage<PhotoProcessContext> {
|
public class CleanupStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.ycwl.basic.image.pipeline.stages;
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
import com.ycwl.basic.image.pipeline.core.StageResult;
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import com.ycwl.basic.utils.ImageUtils;
|
import com.ycwl.basic.utils.ImageUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -13,6 +15,11 @@ import java.io.File;
|
|||||||
* 如果是竖图,旋转90度变成横图(便于后续水印处理)
|
* 如果是竖图,旋转90度变成横图(便于后续水印处理)
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "rotate",
|
||||||
|
optionalMode = StageOptionalMode.UNSUPPORT,
|
||||||
|
description = "竖图旋转90度"
|
||||||
|
)
|
||||||
public class ConditionalRotateStage extends AbstractPipelineStage<PhotoProcessContext> {
|
public class ConditionalRotateStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
private static final int OFFSET_LEFT_FOR_PORTRAIT = 40;
|
private static final int OFFSET_LEFT_FOR_PORTRAIT = 40;
|
||||||
@@ -23,7 +30,7 @@ public class ConditionalRotateStage extends AbstractPipelineStage<PhotoProcessCo
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldExecute(PhotoProcessContext context) {
|
protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
|
||||||
return context.isNormalPhoto() && !context.isLandscape();
|
return context.isNormalPhoto() && !context.isLandscape();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.ycwl.basic.image.pipeline.stages;
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
import cn.hutool.http.HttpUtil;
|
import cn.hutool.http.HttpUtil;
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
import com.ycwl.basic.image.pipeline.core.StageResult;
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -14,6 +16,12 @@ import java.io.File;
|
|||||||
* 从URL下载原图到本地临时文件
|
* 从URL下载原图到本地临时文件
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "download",
|
||||||
|
optionalMode = StageOptionalMode.FORCE_ON,
|
||||||
|
description = "下载图片",
|
||||||
|
defaultEnabled = true
|
||||||
|
)
|
||||||
public class DownloadStage extends AbstractPipelineStage<PhotoProcessContext> {
|
public class DownloadStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -0,0 +1,177 @@
|
|||||||
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.enhancer.adapter.BceImageEnhancer;
|
||||||
|
import com.ycwl.basic.image.enhancer.entity.BceEnhancerConfig;
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.ImageSource;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
import org.springframework.web.multipart.MultipartFile;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像增强Stage
|
||||||
|
* 使用百度云图像增强API提升图片清晰度和质量
|
||||||
|
*
|
||||||
|
* 支持两种增强模式:
|
||||||
|
* 1. 图像清晰度增强 (BceImageEnhancer)
|
||||||
|
* 2. 图像超分辨率 (BceImageSR)
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "image_enhance",
|
||||||
|
optionalMode = StageOptionalMode.SUPPORT,
|
||||||
|
description = "图像增强处理",
|
||||||
|
defaultEnabled = false // 默认不启用,需要外部配置开启
|
||||||
|
)
|
||||||
|
public class ImageEnhanceStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
|
private BceEnhancerConfig enhancerConfig;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数 - 使用默认配置
|
||||||
|
*/
|
||||||
|
public ImageEnhanceStage() {
|
||||||
|
this.enhancerConfig = new BceEnhancerConfig();
|
||||||
|
this.enhancerConfig.setAppId("119554288");
|
||||||
|
this.enhancerConfig.setApiKey("OX6QoijgKio3eVtA0PiUVf7f");
|
||||||
|
this.enhancerConfig.setSecretKey("dYatXReVriPeiktTjUblhfubpcmYfuMk");
|
||||||
|
this.enhancerConfig.setQps(1.0f);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 构造函数 - 使用自定义配置
|
||||||
|
*
|
||||||
|
* @param enhancerConfig 图像增强配置
|
||||||
|
*/
|
||||||
|
public ImageEnhanceStage(BceEnhancerConfig enhancerConfig) {
|
||||||
|
this.enhancerConfig = enhancerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "ImageEnhanceStage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
|
||||||
|
// 仅对照片源为IPC的图片进行增强
|
||||||
|
return context.getSource() == ImageSource.IPC;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected StageResult doExecute(PhotoProcessContext context) {
|
||||||
|
// 检查配置是否完整
|
||||||
|
if (!isConfigValid()) {
|
||||||
|
log.warn("图像增强配置不完整,跳过增强处理。请在ImageEnhanceStage中配置百度云API凭证");
|
||||||
|
return StageResult.skipped("配置不完整,跳过增强");
|
||||||
|
}
|
||||||
|
|
||||||
|
File currentFile = context.getCurrentFile();
|
||||||
|
if (currentFile == null || !currentFile.exists()) {
|
||||||
|
return StageResult.failed("当前文件不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
log.debug("开始图像增强: {}", currentFile.getName());
|
||||||
|
|
||||||
|
// 创建百度云图像增强客户端
|
||||||
|
BceImageEnhancer enhancer = new BceImageEnhancer();
|
||||||
|
enhancer.setConfig(enhancerConfig);
|
||||||
|
|
||||||
|
// 调用图像增强API
|
||||||
|
// 注意:百度云API需要传入图片URL,这里使用本地文件的绝对路径
|
||||||
|
String imageUrl = currentFile.getAbsolutePath();
|
||||||
|
MultipartFile enhancedImage = enhancer.enhance(imageUrl);
|
||||||
|
|
||||||
|
if (enhancedImage == null || enhancedImage.isEmpty()) {
|
||||||
|
log.warn("图像增强返回空结果,可能是API调用失败");
|
||||||
|
return StageResult.degraded("增强失败,使用原图");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 保存增强后的图片到临时文件
|
||||||
|
File enhancedFile = context.getTempFileManager()
|
||||||
|
.createTempFile("enhanced", ".jpg");
|
||||||
|
|
||||||
|
saveMultipartFileToFile(enhancedImage, enhancedFile);
|
||||||
|
|
||||||
|
if (!enhancedFile.exists() || enhancedFile.length() == 0) {
|
||||||
|
return StageResult.degraded("增强结果保存失败,使用原图");
|
||||||
|
}
|
||||||
|
|
||||||
|
// 更新处理后的文件
|
||||||
|
context.updateProcessedFile(enhancedFile);
|
||||||
|
|
||||||
|
long originalSize = currentFile.length();
|
||||||
|
long enhancedSize = enhancedFile.length();
|
||||||
|
double sizeRatio = (double) enhancedSize / originalSize;
|
||||||
|
|
||||||
|
log.info("图像增强完成: 原始{}KB -> 增强后{}KB (比例: {})",
|
||||||
|
originalSize / 1024,
|
||||||
|
enhancedSize / 1024,
|
||||||
|
String.format("%.2f", sizeRatio));
|
||||||
|
|
||||||
|
return StageResult.success(String.format("已增强 (%dKB -> %dKB)",
|
||||||
|
originalSize / 1024,
|
||||||
|
enhancedSize / 1024));
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("图像增强失败: {}", e.getMessage(), e);
|
||||||
|
|
||||||
|
// 增强失败时返回降级状态,继续使用原图
|
||||||
|
return StageResult.degraded("增强失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 检查配置是否有效
|
||||||
|
*/
|
||||||
|
private boolean isConfigValid() {
|
||||||
|
if (enhancerConfig == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
String appId = enhancerConfig.getAppId();
|
||||||
|
String apiKey = enhancerConfig.getApiKey();
|
||||||
|
String secretKey = enhancerConfig.getSecretKey();
|
||||||
|
|
||||||
|
// 检查是否还是TODO占位符
|
||||||
|
if (appId == null || appId.startsWith("TODO_") ||
|
||||||
|
apiKey == null || apiKey.startsWith("TODO_") ||
|
||||||
|
secretKey == null || secretKey.startsWith("TODO_")) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 保存MultipartFile到本地文件
|
||||||
|
*/
|
||||||
|
private void saveMultipartFileToFile(MultipartFile multipartFile, File targetFile) throws IOException {
|
||||||
|
try (FileOutputStream fos = new FileOutputStream(targetFile)) {
|
||||||
|
fos.write(multipartFile.getBytes());
|
||||||
|
fos.flush();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 获取当前配置(用于调试)
|
||||||
|
*/
|
||||||
|
public BceEnhancerConfig getEnhancerConfig() {
|
||||||
|
return enhancerConfig;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 设置配置(用于动态配置)
|
||||||
|
*/
|
||||||
|
public void setEnhancerConfig(BceEnhancerConfig enhancerConfig) {
|
||||||
|
this.enhancerConfig = enhancerConfig;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,9 +1,11 @@
|
|||||||
package com.ycwl.basic.image.pipeline.stages;
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
import com.ycwl.basic.model.Crop;
|
import com.ycwl.basic.model.Crop;
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
import com.ycwl.basic.image.pipeline.core.StageResult;
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import com.ycwl.basic.utils.ImageUtils;
|
import com.ycwl.basic.utils.ImageUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -14,6 +16,11 @@ import java.io.File;
|
|||||||
* 检测图片是横图还是竖图,并记录到Context
|
* 检测图片是横图还是竖图,并记录到Context
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "orientation",
|
||||||
|
optionalMode = StageOptionalMode.UNSUPPORT,
|
||||||
|
description = "图片方向检测"
|
||||||
|
)
|
||||||
public class ImageOrientationStage extends AbstractPipelineStage<PhotoProcessContext> {
|
public class ImageOrientationStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -22,7 +29,7 @@ public class ImageOrientationStage extends AbstractPipelineStage<PhotoProcessCon
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldExecute(PhotoProcessContext context) {
|
protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
|
||||||
return context.isNormalPhoto();
|
return context.isNormalPhoto();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,123 @@
|
|||||||
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
|
import com.ycwl.basic.utils.ImageUtils;
|
||||||
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 图像质量检测Stage
|
||||||
|
* 检测图片质量,如果检测到质量不佳则动态添加ImageEnhanceStage
|
||||||
|
*
|
||||||
|
* 此Stage展示了如何在运行时动态添加后续Stage的能力
|
||||||
|
*/
|
||||||
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "quality_check",
|
||||||
|
optionalMode = StageOptionalMode.SUPPORT,
|
||||||
|
description = "图像质量检测",
|
||||||
|
defaultEnabled = false // 默认不启用
|
||||||
|
)
|
||||||
|
public class ImageQualityCheckStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 质量阈值:图片尺寸小于此阈值认为质量不佳
|
||||||
|
* 例如:小于100KB的图片可能需要增强
|
||||||
|
*/
|
||||||
|
private static final long QUALITY_THRESHOLD_BYTES = 100 * 1024; // 100KB
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 分辨率阈值:图片分辨率低于此值认为质量不佳
|
||||||
|
*/
|
||||||
|
private static final int MIN_WIDTH = 800;
|
||||||
|
private static final int MIN_HEIGHT = 600;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "ImageQualityCheckStage";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
|
||||||
|
// 仅对普通照片执行质量检测
|
||||||
|
return context.isNormalPhoto();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected StageResult doExecute(PhotoProcessContext context) {
|
||||||
|
File currentFile = context.getCurrentFile();
|
||||||
|
if (currentFile == null || !currentFile.exists()) {
|
||||||
|
return StageResult.failed("当前文件不存在");
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
// 检查文件大小
|
||||||
|
long fileSize = currentFile.length();
|
||||||
|
log.debug("图像质量检测: 文件大小={}KB, 阈值={}KB",
|
||||||
|
fileSize / 1024,
|
||||||
|
QUALITY_THRESHOLD_BYTES / 1024);
|
||||||
|
|
||||||
|
boolean needsEnhancement = false;
|
||||||
|
String reason = "";
|
||||||
|
|
||||||
|
// 检查:文件大小
|
||||||
|
if (fileSize < QUALITY_THRESHOLD_BYTES) {
|
||||||
|
needsEnhancement = true;
|
||||||
|
reason = String.format("文件过小(%dKB < %dKB)",
|
||||||
|
fileSize / 1024,
|
||||||
|
QUALITY_THRESHOLD_BYTES / 1024);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: 可以添加更多质量检测维度
|
||||||
|
// 例如:使用BufferedImage读取图片获取分辨率
|
||||||
|
// 例如:使用OpenCV进行图片质量评估
|
||||||
|
// 例如:检查图片的EXIF信息
|
||||||
|
|
||||||
|
// 如果需要增强,动态添加ImageEnhanceStage
|
||||||
|
if (needsEnhancement) {
|
||||||
|
log.info("检测到图片质量不佳({}), 动态添加ImageEnhanceStage", reason);
|
||||||
|
|
||||||
|
ImageEnhanceStage enhanceStage = new ImageEnhanceStage();
|
||||||
|
|
||||||
|
// 使用successWithNext返回,动态添加后续Stage
|
||||||
|
return StageResult.successWithNext(
|
||||||
|
"质量不佳,添加增强Stage: " + reason,
|
||||||
|
enhanceStage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
// 质量良好,无需增强
|
||||||
|
log.info("图像质量良好,无需增强: {}KB", fileSize / 1024);
|
||||||
|
return StageResult.success("质量良好,无需增强");
|
||||||
|
|
||||||
|
} catch (Exception e) {
|
||||||
|
log.error("图像质量检测失败", e);
|
||||||
|
// 检测失败时不影响管线,继续执行
|
||||||
|
return StageResult.degraded("质量检测失败: " + e.getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 示例:也可以根据其他条件动态添加不同的Stage
|
||||||
|
*/
|
||||||
|
@SuppressWarnings("unused")
|
||||||
|
private StageResult checkAndAddMultipleStages(PhotoProcessContext context) {
|
||||||
|
// 示例:根据不同条件添加多个Stage
|
||||||
|
|
||||||
|
// 假设检测到需要多个增强操作
|
||||||
|
ImageEnhanceStage enhanceStage = new ImageEnhanceStage();
|
||||||
|
// 其他Stage...
|
||||||
|
|
||||||
|
// 可以一次性添加多个Stage
|
||||||
|
return StageResult.successWithNext(
|
||||||
|
"检测到需要多重处理",
|
||||||
|
enhanceStage
|
||||||
|
// 可以添加更多Stage
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.ycwl.basic.image.pipeline.stages;
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
import com.ycwl.basic.image.pipeline.core.StageResult;
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import com.ycwl.basic.utils.ImageUtils;
|
import com.ycwl.basic.utils.ImageUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -13,6 +15,12 @@ import java.io.File;
|
|||||||
* 为拼图添加白边框并向上偏移
|
* 为拼图添加白边框并向上偏移
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "puzzle_border",
|
||||||
|
optionalMode = StageOptionalMode.SUPPORT,
|
||||||
|
description = "拼图边框处理",
|
||||||
|
defaultEnabled = true
|
||||||
|
)
|
||||||
public class PuzzleBorderStage extends AbstractPipelineStage<PhotoProcessContext> {
|
public class PuzzleBorderStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
private static final int BORDER_LR = 20;
|
private static final int BORDER_LR = 20;
|
||||||
@@ -25,7 +33,7 @@ public class PuzzleBorderStage extends AbstractPipelineStage<PhotoProcessContext
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldExecute(PhotoProcessContext context) {
|
protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
|
||||||
return context.isPuzzle();
|
return context.isPuzzle();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.ycwl.basic.image.pipeline.stages;
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
import com.ycwl.basic.image.pipeline.core.StageResult;
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import com.ycwl.basic.utils.ImageUtils;
|
import com.ycwl.basic.utils.ImageUtils;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
|
|
||||||
@@ -13,6 +15,11 @@ import java.io.File;
|
|||||||
* 如果之前旋转过竖图,现在旋转270度恢复为竖图
|
* 如果之前旋转过竖图,现在旋转270度恢复为竖图
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "restore",
|
||||||
|
optionalMode = StageOptionalMode.UNSUPPORT,
|
||||||
|
description = "恢复竖图方向"
|
||||||
|
)
|
||||||
public class RestoreOrientationStage extends AbstractPipelineStage<PhotoProcessContext> {
|
public class RestoreOrientationStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -21,7 +28,7 @@ public class RestoreOrientationStage extends AbstractPipelineStage<PhotoProcessC
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldExecute(PhotoProcessContext context) {
|
protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
|
||||||
return context.isNormalPhoto() && context.isNeedRotation();
|
return context.isNormalPhoto() && context.isNeedRotation();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
package com.ycwl.basic.image.pipeline.stages;
|
package com.ycwl.basic.image.pipeline.stages;
|
||||||
|
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
import com.ycwl.basic.image.pipeline.core.StageResult;
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import com.ycwl.basic.storage.StorageFactory;
|
import com.ycwl.basic.storage.StorageFactory;
|
||||||
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
import com.ycwl.basic.storage.adapters.IStorageAdapter;
|
||||||
import com.ycwl.basic.storage.enums.StorageAcl;
|
import com.ycwl.basic.storage.enums.StorageAcl;
|
||||||
@@ -15,6 +17,12 @@ import java.io.File;
|
|||||||
* 支持降级: 配置的存储 -> 默认assets-ext存储
|
* 支持降级: 配置的存储 -> 默认assets-ext存储
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "upload",
|
||||||
|
optionalMode = StageOptionalMode.FORCE_ON,
|
||||||
|
description = "上传图片到存储",
|
||||||
|
defaultEnabled = true
|
||||||
|
)
|
||||||
public class UploadStage extends AbstractPipelineStage<PhotoProcessContext> {
|
public class UploadStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
private static final String DEFAULT_STORAGE = "assets-ext";
|
private static final String DEFAULT_STORAGE = "assets-ext";
|
||||||
|
|||||||
@@ -4,9 +4,11 @@ import com.ycwl.basic.image.watermark.ImageWatermarkFactory;
|
|||||||
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
|
import com.ycwl.basic.image.watermark.entity.WatermarkInfo;
|
||||||
import com.ycwl.basic.image.watermark.enums.ImageWatermarkOperatorEnum;
|
import com.ycwl.basic.image.watermark.enums.ImageWatermarkOperatorEnum;
|
||||||
import com.ycwl.basic.image.watermark.operator.IOperator;
|
import com.ycwl.basic.image.watermark.operator.IOperator;
|
||||||
|
import com.ycwl.basic.image.pipeline.annotation.StageConfig;
|
||||||
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
import com.ycwl.basic.image.pipeline.core.AbstractPipelineStage;
|
||||||
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
import com.ycwl.basic.image.pipeline.core.PhotoProcessContext;
|
||||||
import com.ycwl.basic.image.pipeline.core.StageResult;
|
import com.ycwl.basic.image.pipeline.core.StageResult;
|
||||||
|
import com.ycwl.basic.image.pipeline.enums.StageOptionalMode;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
|
||||||
@@ -20,6 +22,12 @@ import java.util.List;
|
|||||||
* 支持三级降级: 配置的水印类型 -> PRINTER_DEFAULT -> 无水印
|
* 支持三级降级: 配置的水印类型 -> PRINTER_DEFAULT -> 无水印
|
||||||
*/
|
*/
|
||||||
@Slf4j
|
@Slf4j
|
||||||
|
@StageConfig(
|
||||||
|
stageId = "watermark",
|
||||||
|
optionalMode = StageOptionalMode.SUPPORT,
|
||||||
|
description = "水印处理",
|
||||||
|
defaultEnabled = true
|
||||||
|
)
|
||||||
public class WatermarkStage extends AbstractPipelineStage<PhotoProcessContext> {
|
public class WatermarkStage extends AbstractPipelineStage<PhotoProcessContext> {
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -28,7 +36,7 @@ public class WatermarkStage extends AbstractPipelineStage<PhotoProcessContext> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldExecute(PhotoProcessContext context) {
|
protected boolean shouldExecuteByBusinessLogic(PhotoProcessContext context) {
|
||||||
return context.isNormalPhoto();
|
return context.isNormalPhoto();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user