Search Docs
Loading...
Skip to content

Color Conversion

Convert colors between sRGB, CMYK, and spot color spaces programmatically in CE.SDK.

8 mins
estimated time
GitHub

CE.SDK supports three color spaces: sRGB, CMYK, and Spot Color. When building color interfaces or preparing designs for export, you may need to convert colors between these spaces. The engine handles the mathematical conversion automatically through the convertColorToColorSpace(color:colorSpace:) API.

This guide covers how to convert colors between sRGB and CMYK, handle spot color conversions, identify color types with enum pattern matching, and understand how tint and alpha affect conversion.

Supported Color Spaces#

CE.SDK supports conversion between three color spaces. Each is represented as a case of the Color enum:

Color Space Swift Case Use Case
sRGB Color.rgba(r:g:b:a:) (0.0-1.0) Screen display
CMYK Color.cmyk(c:m:y:k:tint:) (0.0-1.0) Print workflows
Spot Color Color.spot(name:tint:externalReference:) Specialized printing

The ColorSpace enum identifies the target of a conversion. Its cases are .sRGB, .cmyk, and .spotColor.

Setting Up Colors#

Construct a color value directly with the appropriate Color enum case:

  • An sRGB color uses Color.rgba(r:g:b:a:), where alpha controls transparency.
  • A CMYK color uses Color.cmyk(c:m:y:k:tint:), where tint controls intensity.
  • A spot color uses Color.spot(name:tint:externalReference:) and references a name defined on the editor.

Before converting a spot color, define its RGB or CMYK approximation. The approximation is also used when the spot color is rendered on screen.

engine.editor.setSpotColor(name: "Brand Red", r: 0.8, g: 0.1, b: 0.1)
engine.editor.setSpotColor(name: "Brand Red", c: 0.0, m: 0.95, y: 0.95, k: 0.1)

You can call both overloads of setSpotColor for the same name so the spot color converts cleanly into either target space.

Loading the CMYK Profile#

In Managed scenes, RGB-to-CMYK conversion uses the document CMYK profile, or the fallback profile when no document profile is available. The synchronous conversion reports COLOR.PROFILE_NOT_LOADED only while a profile from a URI loads.

Await loadCMYKProfile() before converting colors to avoid this loading error:

try await engine.editor.loadCMYKProfile()

The loading call can fail if no usable profile is available. RGB-to-CMYK conversion uses a simple formula if the profile cannot load or only converts CMYK to RGB. Legacy scenes always use the simple formula for RGB-to-CMYK conversion.

Converting to sRGB#

Use engine.editor.convertColorToColorSpace(color:colorSpace:) with colorSpace: .sRGB to convert any color to sRGB. The method throws if the conversion fails.

let cmykCyan = Color.cmyk(c: 1.0, m: 0.0, y: 0.0, k: 0.0, tint: 1.0)
try await engine.editor.loadCMYKProfile()
let cyanAsSrgb = try engine.editor.convertColorToColorSpace(color: cmykCyan, colorSpace: .sRGB)
print("CMYK cyan as sRGB: \(cyanAsSrgb)")

When converting CMYK or spot colors to sRGB, the engine returns a Color.rgba value. The result is opaque. In Managed scenes, CMYK tint scales the ink values before conversion. RGB spot tint blends toward white.

Converting to CMYK#

Use engine.editor.convertColorToColorSpace(color:colorSpace:) with colorSpace: .cmyk to convert any color to CMYK. This is essential for print workflows where colors must be in the correct space before export.

let srgbRed = Color.rgba(r: 1.0, g: 0.0, b: 0.0, a: 1.0)
let redAsCmyk = try engine.editor.convertColorToColorSpace(color: srgbRed, colorSpace: .cmyk)
print("sRGB red as CMYK: \(redAsCmyk)")

RGB alpha does not generally become CMYK tint. Preserve transparency separately. Spot colors retain a registered CMYK approximation. In Managed scenes, a spot with only an RGB approximation converts through the CMYK profile with its tint applied.

Spot colors convert into both target spaces using the approximations you registered above:

let spot = Color.spot(name: "Brand Red", tint: 1.0, externalReference: "")
let spotAsSrgb = try engine.editor.convertColorToColorSpace(color: spot, colorSpace: .sRGB)
let spotAsCmyk = try engine.editor.convertColorToColorSpace(color: spot, colorSpace: .cmyk)
print("Spot 'Brand Red' as sRGB: \(spotAsSrgb)")
print("Spot 'Brand Red' as CMYK: \(spotAsCmyk)")

Identifying Color Types#

Before converting a color, you may need to know which color space it currently uses. Swift’s enum pattern matching makes this straightforward — use a switch statement to handle each Color case, or check the colorSpace property when you only need the type.

let unknown: Color = redAsCmyk
switch unknown {
case let .rgba(r, g, b, a):
print("sRGB: r=\(r), g=\(g), b=\(b), a=\(a)")
case let .cmyk(c, m, y, k, tint):
print("CMYK: c=\(c), m=\(m), y=\(y), k=\(k), tint=\(tint)")
case let .spot(name, tint, externalReference):
print("Spot: name=\(name), tint=\(tint), ref=\(externalReference)")
@unknown default:
print("Unknown color space")
}
let space: ColorSpace = unknown.colorSpace
print("Color space: \(space)")

The colorSpace property returns a ColorSpace enum value (.sRGB, .cmyk, or .spotColor) without unpacking the underlying components.

Handling Tint and Alpha#

Alpha controls transparency. Tint controls color strength and does not generally preserve alpha:

Source Target Transformation
sRGB (alpha) CMYK Alpha is not generally preserved; keep transparency separately
CMYK (tint) sRGB Tint scales ink values; the result is opaque
Spot (tint) sRGB Tint changes the approximation; the result is opaque
Spot (tint) CMYK CMYK approximations retain tint; Managed RGB-only approximations apply tint before conversion

Practical Use Cases#

Building a Color Picker#

When displaying a color value retrieved from a block with engine.block.getColor(_:property:), convert it to sRGB to show RGB components in a custom picker. Pattern-matching on the returned .rgba case unpacks the components for display.

// Build display values for a custom color picker. The input would normally
// come from `engine.block.getColor`; here a literal stands in for a real
// block color.
let pickerInput: Color = .cmyk(c: 0.5, m: 0.0, y: 1.0, k: 0.0, tint: 1.0)
let pickerSrgb = try engine.editor.convertColorToColorSpace(color: pickerInput, colorSpace: .sRGB)
if case let .rgba(r, g, b, _) = pickerSrgb {
print("R: \(Int(r * 255)), G: \(Int(g * 255)), B: \(Int(b * 255))")
}

Export Preparation#

Before PDF export for print, check the current color space and convert to CMYK only when needed. Skipping the conversion for colors that are already CMYK avoids unnecessary gamut shifts.

// Before PDF export, ensure each color is in CMYK. Skip conversion when it
// already is.
let exportInput: Color = .rgba(r: 0.2, g: 0.4, b: 0.9, a: 1.0)
if case .cmyk = exportInput {
print("Already CMYK: \(exportInput)")
} else {
let cmyk = try engine.editor.convertColorToColorSpace(color: exportInput, colorSpace: .cmyk)
print("Converted to CMYK: \(cmyk)")
}

Troubleshooting#

Issue Cause Solution
Spot color converts to unexpected values Spot color not defined Call setSpotColor(name:r:g:b:) or setSpotColor(name:c:m:y:k:) before conversion
Colors look different after conversion Color gamut differences Some sRGB colors cannot be exactly represented in CMYK
Mixing up Color cases Direct property access on the wrong case Use a switch statement or if case pattern matching to safely unpack components

API Reference#

Method Description
engine.editor.convertColorToColorSpace(color:colorSpace:) Convert a color to the target color space. Returns a Color enum value matching the requested space.
engine.editor.setSpotColor(name:r:g:b:) Define a spot color with an RGB approximation. Components range from 0.0 to 1.0.
engine.editor.setSpotColor(name:c:m:y:k:) Define a spot color with a CMYK approximation. Components range from 0.0 to 1.0.
Type Description
Color.rgba(r:g:b:a:) sRGB color for screen display. Alpha controls transparency.
Color.cmyk(c:m:y:k:tint:) CMYK color for print. Tint controls ink strength.
Color.spot(name:tint:externalReference:) Named color for specialized printing.
ColorSpace Enum with cases .sRGB, .cmyk, and .spotColor.