You can insert images into a scene using CE.SDK, either through the prebuilt UI for iOS or programmatically via Swift for all platforms. This gives you the flexibility to build interactive design workflows, enable user-generated content, or automate image placement based on logic or data.
What You’ll Learn#
- Two ways to insert images:
- Programmatically (iOS/macOS/catalyst) by creating a graphic block, applying an image fill, and setting its position/size/rotation/z-index.
- With Editor UI (iOS Only) using the controls and asset libraries of a prebuilt editor such as the Design Editor or Photo Editor.
- Supported image sources such as bundled assets, app file URLs, and remote URLs.
- Practical transforms after insertion such as move, scale, rotate and order.
When to Use It#
- You’re building custom UI or automation flow to add images to compositions.
- You want a ready-made editing experience on iOS with an image picker and panels.
Inserting Images Using the UI#
CE.SDK’s UI includes a built-in image tool that lets users add images from device sources directly onto the canvas. Once inserted, users can move, resize, crop, rotate, or stack images visually.
Supported image sources:
- Photo Roll (Photos app)
- Disk (Files app)
- Camera (device camera)
- Image (project asset library)
In the Asset Library, a user can add images from the Photos app, the camera or the Files app.
You can customize how the image tool appears in the user interface.
Inserting Images Programmatically#
For apps with automation, batch workflows, or logic-driven design experiences, you can insert images into a scene using the block API and the graphics engine.
Here’s how to do it:
// 1. Create a graphic blocklet imageBlock = try engine.block.create(.graphic)
// 2. Create a shape for the imagelet shape = try engine.block.createShape(.rect)try engine.block.setShape(imageBlock, shape: shape)
// 3. Create an image filllet imageFill = try engine.block.createFill(.image)try engine.block.setString( imageFill, property: "fill/image/imageFileURI", value: "https://img.ly/static/ubq_samples/sample_4.jpg")try engine.block.setFill(imageBlock, fill: imageFill)
// 4. (Optional) Set semantic kind to "image" for claritytry engine.block.setKind(imageBlock, kind: "image")
// 5. Add image to the scenelet page = try engine.block.find(byType: .page).first!try engine.block.appendChild(page, child: imageBlock)The shape can be any of the supported shapes .rect, .star, etc and masks the inserted image. The asset URI in step 3 can either be a remote URL or a local asset URI represented as a String.
For assets in the app bundle, get a URL:
let url = Bundle.main.url(forResource: "poster", withExtension: "jpg")For file assets, use the standard FileManager:
let docs = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]let file = docs.appendingPathComponent("uploads/avatar.png")When working with the asset catalog, you can apply an image that’s an AssetResult either to:
- The scene directly
- A block
In the code below assetList is an AssetQueryResult which is the result of a call to findAssets to get assets from an asset catalog.
guard let newAsset = assetList.assets.first else { return }
// Creates a new block that contains the imagelet imageBlock = try await engine.asset.defaultApplyAsset(assetResult: newAsset)
// Applies the image to a block that already existstry await engine.asset.defaultApplyAssetToBlock(assetResult: newAsset, block: someBlock)Image Properties#
After inserting the image, you can change the block’s layout properties using standard methods in the engine.block API.
Positioning#
Refer to the guide in the Transform Section for Move for more details and other options.
// Set X/Y position on the canvas (in absolute units)try engine.block.setPositionX(imageBlock, value: 100)try engine.block.setPositionY(imageBlock, value: 200)Scaling#
Refer to the guide in the Transform Section for Scale for more details and other options.
// Uniform scaletry engine.block.setFloat(imageBlock, property: "transform/scale/x", value: 1.5)try engine.block.setFloat(imageBlock, property: "transform/scale/y", value: 1.5)
// Non-uniform (stretching)try engine.block.setFloat(imageBlock, property: "transform/scale/x", value: 2.0)try engine.block.setFloat(imageBlock, property: "transform/scale/y", value: 1.0)Rotation#
Refer to the guide in the Transform Section for Rotate for more details and other options.
// Rotate 45 degrees (in radians)let degrees = 45.0let radians = degrees * (.pi / 180)try engine.block.setFloat(imageBlock, property: "transform/rotation", value: Float(radians))Layering#
Control stack order using the helper methods to move blocks forward (towards the user) or backwards. You can also pin a block to the front or back of the stack.
try engine.block.bringToFront(block) // Move above siblingstry engine.block.sendToBack(block) // Move below siblingstry engine.block.bringForward(block) // One step forwardtry engine.block.sendBackward(block) // One step backward
try engine.block.setAlwaysOnTop(block, enabled: true)Insert Into an Existing Block#
If your template exposes a placeholder block or you are creating an automated workflow, you can replace an image fill instead of creating a new block. Locate the block using its name property (this pairs well with the process for text variables) or by its known id.
When you know the id of the target:
let fill = try engine.block.createFill(.image)try engine.block.setString(fill, property: "fill/image/imageFileURI", value: imageURI)try engine.block.setFill(targetBlock, fill: fill)When you’re using the name property to find the block, find(byName:) returns the block id:
guard let targetBlock = engine.block.find(byName: "HeroTile") else { return }
let fill = try engine.block.createFill(.image)try engine.block.setString(fill, property: "fill/image/imageFileURI", value: imageURI)try engine.block.setFill(targetBlock, fill: fill)Troubleshooting#
❌ Nothing appears after insert:
- Verify that the block is attached to the page.
- Verify the URL string is correct (use
.absoluteStringproperty). - Check the scene’s current zoom and camera framing.
❌ Remote images fail:
- Confirm HTTPS, CORS, or ATS settings.
- Test the URL in a browser.
❌ Pixelated result:
- Change the block size or use a higher-resolution source image.
❌ Unexpected orientation of image:
- Some formats carry EXIF orientation information. Apply
setRotationor normalize the asset during import.
Next Steps#
Now that you’ve learned about inserting images into your compositions, here are some topics to explore to deepen your understanding.
- Apply more transformations such as crop, or scale.
- Create templates for automating content creation and formatting.
- Export compositions in a variety of formats.