Search Docs
Loading...
Skip to content

Adjust Colors

Fine-tune image-backed graphic blocks on Android by applying CE.SDK adjustment effects for brightness, contrast, saturation, and tonal refinement.

8 mins
estimated time
GitHub

Color adjustments modify the visual appearance of image-backed graphic blocks by changing properties like brightness, contrast, saturation, and color temperature. CE.SDK represents these changes as an EffectType.Adjustments block that you attach to a compatible design block.

This guide covers the default Android adjustments UI and the engine APIs you can use when your app needs to apply the same changes programmatically.

Using the Built-in Adjustments UI#

The default Android editor exposes adjustments through its built-in dock and inspector controls when the current selection allows appearance adjustments. Users can open the adjustments sheet, move sliders, and preview the result immediately.

The built-in sheet uses the same adjustments effect shown below: it creates the effect when needed, attaches it to the selected block, and writes float properties on that effect block.

Check Block Compatibility#

Before applying adjustments, verify that the target block supports effects. Scene blocks do not expose effect stacks. Pages and image-backed graphic blocks both support effects; choose the graphic block when the adjustment should affect image content rather than the entire page background.

val sceneSupportsEffects = engine.block.supportsEffects(scene)
val pageSupportsEffects = engine.block.supportsEffects(page)
val imageGraphicSupportsEffects = engine.block.supportsEffects(imageGraphicBlock)
require(!sceneSupportsEffects) { "Scenes do not support effect stacks." }
require(pageSupportsEffects) { "Pages can expose effect stacks." }
require(imageGraphicSupportsEffects) { "Image-backed graphic blocks can render adjustments." }

Create and Apply Adjustments Effect#

Create an EffectType.Adjustments block and append it to the image-backed graphic block. A block should only have one adjustments effect in its effect stack. That effect stores all color adjustment properties for the block.

val adjustmentsEffect = engine.block.createEffect(type = EffectType.Adjustments)
engine.block.appendEffect(block = imageGraphicBlock, effectBlock = adjustmentsEffect)

Modify Adjustment Properties#

Set individual adjustment values with setFloat() on the adjustments effect block. Each adjustment property uses the effect/adjustments/ prefix followed by the property name.

engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/brightness", value = 0.2F)
engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/contrast", value = 0.15F)
engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/saturation", value = 0.3F)

CE.SDK provides these adjustment properties:

PropertyDescription
brightnessOverall lightness; positive values lighten and negative values darken
contrastTonal range; positive values increase separation between light and dark
saturationColor intensity; positive values increase vibrancy and negative values desaturate
exposureExposure compensation
gammaMidtone brightness through the gamma curve
highlightsBright area intensity
shadowsDark area intensity
whitesWhite point adjustment
blacksBlack point adjustment
temperatureWarm/cool color cast; positive for warmer, negative for cooler tones
sharpnessEdge sharpness; positive values sharpen and negative values soften edges
clarityMidtone contrast

The built-in editor sliders use -1F to 1F for these adjustment properties, while setFloat() writes the float values you provide. Validate custom controls and presets before writing them.

Read Adjustment Values#

Read current adjustment values with getFloat() and the same property paths. Use findAllProperties() when you need to inspect which properties are available on the effect block.

val brightness = engine.block.getFloat(adjustmentsEffect, property = "effect/adjustments/brightness")
val contrast = engine.block.getFloat(adjustmentsEffect, property = "effect/adjustments/contrast")
val saturation = engine.block.getFloat(adjustmentsEffect, property = "effect/adjustments/saturation")
val availableProperties = engine.block.findAllProperties(adjustmentsEffect)

This is useful for custom controls, synchronization, or persisting adjustment settings in your app.

Enable and Disable Adjustments#

Toggle the adjustments effect when you need a before/after preview without losing the configured values.

engine.block.setEffectEnabled(effectBlock = adjustmentsEffect, enabled = false)
val disabledState = engine.block.isEffectEnabled(adjustmentsEffect)
engine.block.setEffectEnabled(effectBlock = adjustmentsEffect, enabled = true)
val enabledState = engine.block.isEffectEnabled(adjustmentsEffect)

Disabling the effect keeps it attached to the block. Re-enable it to render the same adjustment values again.

Applying Different Adjustment Styles#

Combine several adjustment properties to create a specific look. This example creates a cooler, moodier result with lower brightness, higher contrast, reduced saturation, and lower temperature.

engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/brightness", value = -0.1F)
engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/contrast", value = 0.35F)
engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/saturation", value = -0.25F)
engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/temperature", value = -0.2F)

Use the same pattern for warm, vibrant, or high-contrast styles.

Combine Adjustments with Other Effects#

Effect stacks render in order, so add effects in the order you want them to render, or use insertEffect() when a new effect needs a specific index. This example inserts a pixelize effect after the adjustments effect and reads the stack back to confirm the order.

val pixelizeEffect = engine.block.createEffect(type = EffectType.Pixelize)
engine.block.insertEffect(block = imageGraphicBlock, effectBlock = pixelizeEffect, index = 1)
val orderedEffects = engine.block.getEffects(imageGraphicBlock)

Use appendEffect() when a new effect can render after the existing stack, insertEffect() when it must occupy a specific index, and getEffects() when you need to inspect the current stack.

Refinement Adjustments#

Refinement properties help tune detail and tonal balance after the basic color correction is in place.

engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/sharpness", value = 0.3F)
engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/clarity", value = 0.25F)
engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/highlights", value = -0.15F)
engine.block.setFloat(adjustmentsEffect, property = "effect/adjustments/shadows", value = 0.2F)

The refinement properties are useful for photo enhancement:

  • Sharpness: Enhances edge definition.
  • Clarity: Increases local midtone contrast.
  • Highlights: Controls bright image areas.
  • Shadows: Controls dark image areas.

Reset Adjustments#

Reset adjustments by writing 0F to each property. This keeps the effect attached while returning it to its neutral state.

val adjustmentProperties = engine.block
.findAllProperties(adjustmentsEffect)
.filter { it.startsWith("effect/adjustments/") }
check(adjustmentProperties.isNotEmpty())
adjustmentProperties.forEach { property ->
engine.block.setFloat(adjustmentsEffect, property = property, value = 0F)
}

Remove Adjustments#

When you no longer need the adjustments effect, remove it from the block’s effect stack and destroy the effect block when it is no longer used.

val effects = engine.block.getEffects(imageGraphicBlock)
val adjustmentIndex = effects.indexOf(adjustmentsEffect)
require(adjustmentIndex >= 0) { "The adjustments effect must be attached before it can be removed." }
engine.block.removeEffect(block = imageGraphicBlock, index = adjustmentIndex)
engine.block.destroy(adjustmentsEffect)

removeEffect() takes the effect index within the block’s effect stack, so read the stack before removing the effect.

Troubleshooting#

IssueFix
Adjustments are not visibleCheck supportsEffects() on the target block, verify the effect is enabled, and make sure it was appended to the block.
Values have no visible effectConfirm the values are non-zero, the block contains image content, and the effect stack order is correct when multiple effects are attached.
Property lookup failsUse findAllProperties() on the adjustments effect and verify the effect/adjustments/ prefix.

API Reference#

APIDescription
engine.block.supportsEffects(block=_)Checks whether a design block can render effects
engine.block.createEffect(type=EffectType.Adjustments)Creates an adjustments effect block
engine.block.createEffect(type=EffectType.Pixelize)Creates a second effect used to demonstrate effect stack order
engine.block.appendEffect(block=_, effectBlock=_)Adds the effect to the end of a block’s effect stack
engine.block.insertEffect(block=_, effectBlock=_, index=_)Inserts an effect at a specific stack index
engine.block.getEffects(block=_)Returns the effects attached to a block
engine.block.removeEffect(block=_, index=_)Removes the effect at the specified stack index
engine.block.setEffectEnabled(effectBlock=_, enabled=_)Enables or disables an effect block
engine.block.isEffectEnabled(effectBlock=_)Returns whether an effect block is enabled
engine.block.setFloat(block=_, property="effect/adjustments/brightness", value=_)Writes a float adjustment value
engine.block.getFloat(block=_, property="effect/adjustments/brightness")Reads a float adjustment value
engine.block.findAllProperties(block=_)Lists the properties available on a block
engine.block.destroy(block=_)Destroys an unused effect block

Next Steps#