Fix ImagePipeline operation rendering
Update MaskOperation to store mask dimensions for reconstruction. Implement proper operation rendering in ImagePipeline: - Apply mask+inpaint operations with proper mask reconstruction - Handle adjustment operations by type (brightness/contrast/saturation) - Scale masks when rendering previews at reduced resolution Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -172,14 +172,20 @@ final class EditorViewModel {
|
|||||||
|
|
||||||
// Add operation to project
|
// Add operation to project
|
||||||
if var project = project {
|
if var project = project {
|
||||||
let maskData = MaskData(from: mask)?.data ?? Data()
|
if let maskDataObj = MaskData(from: mask) {
|
||||||
let maskOp = MaskOperation(toolType: toolTypeForCurrentTool(), maskData: maskData)
|
let maskOp = MaskOperation(
|
||||||
|
toolType: toolTypeForCurrentTool(),
|
||||||
|
maskData: maskDataObj.data,
|
||||||
|
maskWidth: maskDataObj.width,
|
||||||
|
maskHeight: maskDataObj.height
|
||||||
|
)
|
||||||
let inpaintOp = InpaintOperation(maskOperationId: maskOp.id, featherAmount: Float(featherAmount))
|
let inpaintOp = InpaintOperation(maskOperationId: maskOp.id, featherAmount: Float(featherAmount))
|
||||||
|
|
||||||
project.addOperation(.mask(maskOp))
|
project.addOperation(.mask(maskOp))
|
||||||
project.addOperation(.inpaint(inpaintOp))
|
project.addOperation(.inpaint(inpaintOp))
|
||||||
self.project = project
|
self.project = project
|
||||||
}
|
}
|
||||||
|
}
|
||||||
} catch {
|
} catch {
|
||||||
errorMessage = error.localizedDescription
|
errorMessage = error.localizedDescription
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,12 +24,16 @@ struct MaskOperation: Codable, Identifiable {
|
|||||||
let id: UUID
|
let id: UUID
|
||||||
let toolType: ToolType
|
let toolType: ToolType
|
||||||
let maskData: Data
|
let maskData: Data
|
||||||
|
let maskWidth: Int
|
||||||
|
let maskHeight: Int
|
||||||
let timestamp: Date
|
let timestamp: Date
|
||||||
|
|
||||||
init(id: UUID = UUID(), toolType: ToolType, maskData: Data, timestamp: Date = Date()) {
|
init(id: UUID = UUID(), toolType: ToolType, maskData: Data, maskWidth: Int, maskHeight: Int, timestamp: Date = Date()) {
|
||||||
self.id = id
|
self.id = id
|
||||||
self.toolType = toolType
|
self.toolType = toolType
|
||||||
self.maskData = maskData
|
self.maskData = maskData
|
||||||
|
self.maskWidth = maskWidth
|
||||||
|
self.maskHeight = maskHeight
|
||||||
self.timestamp = timestamp
|
self.timestamp = timestamp
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import UIKit
|
|||||||
actor ImagePipeline {
|
actor ImagePipeline {
|
||||||
|
|
||||||
private let context: CIContext
|
private let context: CIContext
|
||||||
|
private let inpaintEngine = InpaintEngine()
|
||||||
|
|
||||||
init() {
|
init() {
|
||||||
self.context = CIContext(options: [
|
self.context = CIContext(options: [
|
||||||
@@ -29,12 +30,17 @@ actor ImagePipeline {
|
|||||||
// Scale down for preview if needed
|
// Scale down for preview if needed
|
||||||
var image = originalImage
|
var image = originalImage
|
||||||
|
|
||||||
|
let scaleFactor: CGFloat
|
||||||
if image.width > maxSize || image.height > maxSize {
|
if image.width > maxSize || image.height > maxSize {
|
||||||
let scale = CGFloat(maxSize) / CGFloat(max(image.width, image.height))
|
scaleFactor = CGFloat(maxSize) / CGFloat(max(image.width, image.height))
|
||||||
image = try scaleImage(image, scale: scale)
|
image = try scaleImage(image, scale: scaleFactor)
|
||||||
|
} else {
|
||||||
|
scaleFactor = 1.0
|
||||||
}
|
}
|
||||||
|
|
||||||
// Apply operations (placeholder for now)
|
// Apply operations
|
||||||
|
image = try await applyOperations(operations, to: image, scaleFactor: scaleFactor)
|
||||||
|
|
||||||
return image
|
return image
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -43,7 +49,68 @@ actor ImagePipeline {
|
|||||||
operations: [EditOperation]
|
operations: [EditOperation]
|
||||||
) async throws -> CGImage {
|
) async throws -> CGImage {
|
||||||
// Apply operations at full resolution
|
// Apply operations at full resolution
|
||||||
return originalImage
|
var image = originalImage
|
||||||
|
image = try await applyOperations(operations, to: image, scaleFactor: 1.0)
|
||||||
|
return image
|
||||||
|
}
|
||||||
|
|
||||||
|
private func applyOperations(
|
||||||
|
_ operations: [EditOperation],
|
||||||
|
to image: CGImage,
|
||||||
|
scaleFactor: CGFloat
|
||||||
|
) async throws -> CGImage {
|
||||||
|
var currentImage = image
|
||||||
|
|
||||||
|
// Group mask and inpaint operations
|
||||||
|
var pendingMask: MaskOperation?
|
||||||
|
|
||||||
|
for operation in operations {
|
||||||
|
switch operation {
|
||||||
|
case .mask(let maskOp):
|
||||||
|
pendingMask = maskOp
|
||||||
|
|
||||||
|
case .inpaint:
|
||||||
|
if let maskOp = pendingMask {
|
||||||
|
let maskData = MaskData(
|
||||||
|
width: maskOp.maskWidth,
|
||||||
|
height: maskOp.maskHeight,
|
||||||
|
data: maskOp.maskData
|
||||||
|
)
|
||||||
|
if let mask = maskData.toCGImage() {
|
||||||
|
// Scale mask if needed
|
||||||
|
let scaledMask: CGImage
|
||||||
|
if scaleFactor != 1.0 {
|
||||||
|
scaledMask = try scaleImage(mask, scale: scaleFactor)
|
||||||
|
} else {
|
||||||
|
scaledMask = mask
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply inpainting
|
||||||
|
currentImage = try await inpaintEngine.inpaint(
|
||||||
|
image: currentImage,
|
||||||
|
mask: scaledMask
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pendingMask = nil
|
||||||
|
|
||||||
|
case .adjustment(let adjustment):
|
||||||
|
currentImage = applyAdjustment(adjustment, to: currentImage) ?? currentImage
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return currentImage
|
||||||
|
}
|
||||||
|
|
||||||
|
private func applyAdjustment(_ adjustment: AdjustmentOperation, to image: CGImage) -> CGImage? {
|
||||||
|
switch adjustment.type {
|
||||||
|
case .brightness:
|
||||||
|
return applyColorAdjustment(to: image, brightness: adjustment.value)
|
||||||
|
case .contrast:
|
||||||
|
return applyColorAdjustment(to: image, contrast: adjustment.value)
|
||||||
|
case .saturation:
|
||||||
|
return applyColorAdjustment(to: image, saturation: adjustment.value)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func applyColorAdjustment(
|
func applyColorAdjustment(
|
||||||
|
|||||||
Reference in New Issue
Block a user