A composable image editor powered by Core Image and Metal.
Build a photo editor with the included Photos-style UI, compose your own editing interface, or use the rendering engine on its own. Brightroom keeps edits as parameters, so you can change adjustments, revisit crops, and render again from the original image.
- A ready-to-use photo editor. Crop, rotate, straighten, apply filter presets, adjust color, and paint blur masks with
SwiftUIPhotosCropView. - Composable editing. Use
SwiftUICropViewfor a custom interface, withEditingStackmanaging the editing state, history, and rendering. - Non-destructive processing. Combine crops, effects, and masked local adjustments in an ordered feature tree.
- Custom effects and LUTs. Add your own Core Image transforms or color-cube LUTs, and save edit parameters with
ParametricDocumentCodec. - Metal-backed previews and export. Work with wide-color images and export to memory or directly to JPEG, HEIF, and PNG files.
- Local and remote images. Load images from
UIImage, data, file URLs, or remote URLs throughImageProvider. - Rendering beyond the editor. Use the parametric engine independently on iOS and macOS, including applying documents to video frames through AVFoundation compositions.
Choose the product that matches what you want to build:
| Product | Purpose | Platforms |
|---|---|---|
BrightroomUI |
Photos-style editor and reusable SwiftUI editing components | iOS 17+ |
BrightroomEngine |
Image loading, editing state and history, and asynchronous rendering | iOS 17+ |
BrightroomParametric |
Typed features, masks, document persistence, and Core Image rendering, with no third-party dependencies | iOS 17+, macOS 14+ |
The Swift package requires Swift 6.3 or later and uses Swift 6 language mode. Use an Xcode toolchain that includes Swift 6.3 or later. The built-in UI uses UIKit internally; UIKit apps can present it through UIHostingController.
Add https://github.com/FluidGroup/Brightroom.git in Xcode's package dependencies, or declare it in your Package.swift:
dependencies: [
.package(url: "https://github.com/FluidGroup/Brightroom.git", from: "5.0.0")
]For a photo editor, add BrightroomUI and BrightroomEngine to your app target. In a Swift package target, use:
.target(
name: "MyApp",
dependencies: [
.product(name: "BrightroomUI", package: "Brightroom"),
.product(name: "BrightroomEngine", package: "Brightroom"),
]
)For processing without the editor, add BrightroomParametric instead.
EditingStack owns an editing session. PhotosCropEditingModel connects that session to the built-in editor's crop, filter, adjustment, and blur controls. Keep both instances alive for the lifetime of the editor.
import BrightroomEngine
import BrightroomUI
import SwiftUI
import UIKit
/// Edits one image and delivers the exported image or a rendering error.
@MainActor
struct PhotoEditor: View {
@Environment(\.dismiss) private var dismiss
@State private var editingStack: EditingStack
@State private var editingModel: PhotosCropEditingModel
@State private var isExporting = false
private let onComplete: (Result<UIImage, Error>) -> Void
init(
image: UIImage,
onComplete: @escaping (Result<UIImage, Error>) -> Void
) {
let stack = EditingStack(imageProvider: .init(image: image))
_editingStack = State(initialValue: stack)
_editingModel = State(initialValue: PhotosCropEditingModel(editingStack: stack))
self.onComplete = onComplete
}
var body: some View {
SwiftUIPhotosCropView(
editingModel: editingModel,
onDone: {
guard !isExporting else { return }
isExporting = true
Task {
defer { isExporting = false }
do {
let rendered = try await editingStack.makeRenderer().render()
onComplete(.success(try rendered.uiImage))
} catch {
onComplete(.failure(error))
}
}
},
onCancel: { dismiss() }
)
.disabled(isExporting)
.overlay {
if isExporting {
ProgressView()
}
}
}
}The editor starts image preparation automatically. Handle the result and dismiss the editor from onComplete when appropriate. Create a new editor session when selecting a different source image.
Customize aspect ratios and filter presets through SwiftUIPhotosCropView.Options, and button labels through LocalizedStrings. For a custom layout and controls, start with SwiftUICropView. See the SwiftUI demo for complete integrations.
To export directly to disk, pass a file output to the renderer. This avoids creating a full-resolution output bitmap in memory:
let rendered = try await editingStack.makeRenderer().render(
options: .init(
output: .file(url: outputURL, fileType: .heif(quality: 0.9))
)
)Choose a writable outputURL for the destination file. The result exposes fileURL and thumbnail(maxPixelSize:). Requesting cgImage or uiImage from a file-backed result decodes the full image back into memory.
BrightroomParametric stores edits in a Swift value tree. Features are evaluated in order, and each feature receives the preceding feature's output. The source image stays separate from the document.
import BrightroomParametric
import CoreImage
/// Builds an exposure-adjusted image recipe without modifying the source.
func makeAdjustedImage(from source: CIImage) throws -> CIImage {
let document = EditingDocument(
mainTree: MainTree(features: [
.effect(ExposureFeature(value: 0.5))
])
)
return try ParametricImageRenderer().makeImage(
from: source,
document: document
)
}The returned CIImage is a lazy recipe. Use a CIContext to materialize it, or use ParametricExportRenderer to render a document to an image or file.
- Conform to
ImageEffectFeatureTypeto add a custom effect. - Combine an
EffectPipelineand aMaskTreein aLocalAdjustmentFeatureto apply effects selectively. - Use
ParametricDocumentCodecto save and restore documents. Custom persisted features also conform toPersistableFeatureand must be registered with the codec. - Use
ParametricVideoRendererto create anAVMutableVideoCompositionfor playback or export through AVFoundation.
Clone the repository with its submodules and open the development project:
git clone --recurse-submodules https://github.com/FluidGroup/Brightroom.git
cd Brightroom
open Dev/Brightroom.xcodeproj- SwiftUIDemo — the Photos-style editor, custom crop interfaces, image rendering, parametric features, and video processing on iOS.
- ParametricMacDemo — the standalone parametric engine on macOS.
Select a scheme and a matching run destination in Xcode. To build the iOS demo from the command line:
xcodebuild \
-project Dev/Brightroom.xcodeproj \
-scheme SwiftUIDemo \
-destination 'generic/platform=iOS Simulator' \
build- Parametric runtime design — the feature model, custom effects, and persistence design.
- Editing engine vision — the longer-term direction for parametric editing.
Support Brightroom on GitHub Sponsors or buy me a coffee.
Brightroom is available under the MIT license.




