Skip to content

Store Custom Metadata

CE.SDK allows you to store custom metadata in your scenes. You can attach metadata to your scene or directly to your individual design blocks within the scene. This metadata is persistent across saving and loading of scenes. It simply consists of key value pairs of strings. Using any string-based serialization format such as JSON will allow you to store even complex objects. Please note that when duplicating blocks their metadata will also be duplicated.

Working with Metadata

We can add metadata to any design block using func setMetadata(_ id: DesignBlockID, key: String, value: String) throws. This also includes the scene block.

try engine.block.setMetadata(scene, key: "author", value: "img.ly")
try engine.block.setMetadata(block, key: "customer_id", value: "1234567890")
/* We can even store complex objects */
struct Payment: Encodable {
let id: Int
let method: String
let received: Bool
}
let payment = Payment(id: 5, method: "credit_card", received: true)
try engine.block.setMetadata(
block,
key: "payment",
value: String(data: JSONEncoder().encode(payment), encoding: .utf8)!
)

We can retrieve metadata from any design block or scene using func getMetadata(_ id: DesignBlockID, key: String) throws. Before accessing the metadata you check for its existence using func hasMetadata(_ id: DesignBlockID, key: String) throws -> Bool.

/* This will return "img.ly" */
try engine.block.getMetadata(scene, key: "author")
/* This will return "1000000" */
try engine.block.getMetadata(block, key: "customer_id")

We can query all metadata keys from any design block or scene using func findAllMetadata(_ id: DesignBlockID) throws -> [String]. For blocks without any metadata, this will return an empty list.

/* This will return ["customer_id"] */
try engine.block.findAllMetadata(block)

If you want to get rid of any metadata, you can use func removeMetadata(_ id: DesignBlockID, key: String) throws.

try engine.block.removeMetadata(block, key: "payment")
/* This will return false */
try engine.block.hasMetadata(block, key: "payment")

Metadata will automatically be saved and loaded as part the scene. So you don’t have to worry about it getting lost or having to save it separately.

/* We save our scene and reload it from scratch */
let sceneString = try await engine.scene.saveToString()
scene = try await engine.scene.load(from: sceneString)
/* This still returns "img.ly" */
try engine.block.getMetadata(scene, key: "author")
/* And this still returns "1234567890" */
try engine.block.getMetadata(block, key: "customer_id")

Full Code

Here’s the full code:

import Foundation
import IMGLYEngine
@MainActor
func storeMetadata(engine: Engine) async throws {
var scene = try await engine.scene.create(fromImage:
.init(string: "https://img.ly/static/ubq_samples/imgly_logo.jpg")!)
let block = try engine.block.find(byType: .graphic).first!
try engine.block.setMetadata(scene, key: "author", value: "img.ly")
try engine.block.setMetadata(block, key: "customer_id", value: "1234567890")
/* We can even store complex objects */
struct Payment: Encodable {
let id: Int
let method: String
let received: Bool
}
let payment = Payment(id: 5, method: "credit_card", received: true)
try engine.block.setMetadata(
block,
key: "payment",
value: String(data: JSONEncoder().encode(payment), encoding: .utf8)!
)
/* This will return "img.ly" */
try engine.block.getMetadata(scene, key: "author")
/* This will return "1000000" */
try engine.block.getMetadata(block, key: "customer_id")
/* This will return ["customer_id"] */
try engine.block.findAllMetadata(block)
try engine.block.removeMetadata(block, key: "payment")
/* This will return false */
try engine.block.hasMetadata(block, key: "payment")
/* We save our scene and reload it from scratch */
let sceneString = try await engine.scene.saveToString()
scene = try await engine.scene.load(from: sceneString)
/* This still returns "img.ly" */
try engine.block.getMetadata(scene, key: "author")
/* And this still returns "1234567890" */
try engine.block.getMetadata(block, key: "customer_id")
}