Skip to main content

Headless rendering

PhotoEditor SDK for iOS provides a UI as well as a headless API. Learn how to render images directly from your input data.

Export without UI#

Introduced in PhotoEditor SDK v11.2.0

PhotoEditor SDK allows to generate output without interacting with the UI.

With all the changes stored in a PhotoEditModel, you will need to manually create a PhotoEditRenderer instance, as well as a Configuration and an AssetManager.

Then you can asynchronously load all the required assets before you generate the output image, as shown in this example:

let originalImage = UIImage(named: "sample_image")!
// Set up the used asset catalog and weather provider
let configuration = Configuration { builder in
builder.assetCatalog = AssetCatalog.defaultItems
builder.configureStickerToolController { options in
// Make sure to pass in your API key to display real weather data
// otherwise the sample data API is used!
let weatherProvider = OpenWeatherProvider(apiKey: nil, unit: .locale)
weatherProvider.locationAccessRequestClosure = { locationManager in
options.weatherProvider = weatherProvider
// Add custom assets if needed
let overlay = Overlay(identifier: "imgly_overlay_golden", displayName: "Golden", url: Bundle.imgly.resourceBundle.url(forResource: "imgly_overlay_golden", withExtension: "jpg"), thumbnailURL: Bundle.imgly.resourceBundle.url(forResource: "imgly_overlay_golden_thumb", withExtension: "jpg"), initialBlendMode: .lighten)
let assetManager = AssetManager()
// Get or create the model
var model = PhotoEditModel()
// Apply changes
model.overlayModel = OverlayModel(identifier: "imgly_overlay_golden", blendMode: .multiply, intensity: 1)
let renderer = PhotoEditRenderer(productType: .pesdk)
renderer.originalImage = CIImage(image: originalImage)
renderer.assetCatalog = configuration.assetCatalog
renderer.assetManager = assetManager
renderer.photoEditModel = model
assetManager.populate(renderer: renderer, model: model, configuration: configuration) { _, errors in
guard errors.isEmpty else {
renderer.generateOutputImageData(withFormat: .png, compressionQuality: 1, metadataSourcePhoto: nil) { imageData, width, height in
guard let imageData = imageData else {
print("Received image data with \(imageData.count) bytes, width: \(width) height: \(height).")