feat: 实现真正的分块处理优化 AI 增强质量

- TiledImageProcessor 重写:将大图拆分为 512×512 重叠 tiles
- 64px 重叠区域 + 线性权重混合,消除拼接接缝
- AIEnhancer 自动选择处理器:大图用 TiledImageProcessor,小图用 WholeImageProcessor
- 信息损失从 ~86% 降至 0%(1080×1920 图像不再压缩到 288×512)

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
empty
2026-01-03 21:04:22 +08:00
parent 3d1677bdb1
commit 3f503c1050
3 changed files with 464 additions and 66 deletions

View File

@@ -29,7 +29,7 @@ actor RealESRGANProcessor {
init() {}
/// Load Core ML model from bundle
/// Load Core ML model from ODR or bundle
func loadModel() async throws {
guard model == nil else {
logger.debug("Model already loaded")
@@ -38,30 +38,34 @@ actor RealESRGANProcessor {
logger.info("Loading Real-ESRGAN Core ML model...")
// Try to find model in bundle
let modelName = "RealESRGAN_x4plus"
var modelURL: URL?
// Try SPM bundle first
#if SWIFT_PACKAGE
if let url = Bundle.module.url(forResource: modelName, withExtension: "mlmodelc") {
modelURL = url
} else if let url = Bundle.module.url(forResource: modelName, withExtension: "mlpackage") {
modelURL = url
}
#endif
// Try main bundle
// 1. Try ODRManager first (supports both ODR download and bundle fallback)
var modelURL = await ODRManager.shared.getModelURL()
// 2. If ODRManager returns nil, try direct bundle lookup as fallback
if modelURL == nil {
let modelName = "RealESRGAN_x4plus"
// Try main bundle
if let url = Bundle.main.url(forResource: modelName, withExtension: "mlmodelc") {
modelURL = url
} else if let url = Bundle.main.url(forResource: modelName, withExtension: "mlpackage") {
modelURL = url
}
// Try SPM bundle (development)
#if SWIFT_PACKAGE
if modelURL == nil {
if let url = Bundle.module.url(forResource: modelName, withExtension: "mlmodelc") {
modelURL = url
} else if let url = Bundle.module.url(forResource: modelName, withExtension: "mlpackage") {
modelURL = url
}
}
#endif
}
guard let url = modelURL else {
logger.error("Model file not found: \(modelName)")
logger.error("Model not found. Please download the AI model first.")
throw AIEnhanceError.modelNotFound
}