Skip to content

Source Sets

Source sets allow specifying an entire set of sources, each with a different size, that should be used for drawing a block. The appropriate source is then dynamically chosen based on the current drawing size. This allows using the same scene to render a preview on a mobile screen using a small image file and a high-resolution file for print in the backend.

This guide will show you how to specify source sets both for existing blocks and when defining assets.

Drawing

When an image needs to be drawn, the current drawing size in screen pixels is calculated and the engine looks up the most appropriate source file to draw at that resolution.

  1. If a source set is set, the source with the closest size exceeding the drawing size is used
  2. If no source set is set, the full resolution image is downscaled to a maximum edge length of 4096 (configurable via maxImageSize setting) and drawn to the target area

This also gives more control about up- and downsampling to you, as all intermediate resolutions can be generated using tooling of your choice.

Source sets are also used during export of your designs and will resolve to the best matching asset for the export resolution.

Setup the scene

We first create a new scene with a new page.

document.getElementById('cesdk_container').append(engine.element);
const scene = engine.scene.create();
const page = engine.block.create('page');
engine.block.setWidth(page, 800);
engine.block.setHeight(page, 600);
engine.block.appendChild(scene, page);
engine.scene.zoomToBlock(page, 50, 50, 50, 50);

Using a Source Set for an existing Block

To make use of a source set for an existing image fill, we use the setSourceSet API. This defines a set of sources and specifies height and width for each of these sources. The engine then chooses the appropriate source during drawing. You may query an existing source set using getSourceSet. You can add sources to an existing source set with addImageFileURIToSourceSet.

let block = engine.block.create('graphic');
engine.block.setShape(block, engine.block.createShape('rect'));
const imageFill = engine.block.createFill('image');
engine.block.setSourceSet(imageFill, 'fill/image/sourceSet', [
{
uri: 'https://img.ly/static/ubq_samples/sample_1_512x341.jpg',
width: 512,
height: 341
},
{
uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg',
width: 1024,
height: 683
},
{
uri: 'https://img.ly/static/ubq_samples/sample_1_2048x1366.jpg',
width: 2048,
height: 1366
}
]);
engine.block.setFill(block, imageFill);
console.log(engine.block.getSourceSet(imageFill, 'fill/image/sourceSet'));
engine.block.appendChild(page, block);

Using a Source Set in an Asset

For assets, source sets can be defined in the payload.sourceSet field. This is directly translated to the sourceSet property when applying the asset. The resulting block is configured in the same way as the one described above. The code demonstrates how to add an asset that defines a source set to a local source and how applyAsset handles a populated payload.sourceSet.

const assetWithSourceSet = {
id: 'my-image',
meta: {
kind: 'image',
fillType: '//ly.img.ubq/fill/image'
},
payload: {
sourceSet: [
{
uri: 'https://img.ly/static/ubq_samples/sample_1_512x341.jpg',
width: 512,
height: 341
},
{
uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg',
width: 1024,
height: 683
},
{
uri: 'https://img.ly/static/ubq_samples/sample_1_2048x1366.jpg',
width: 2048,
height: 1366
}
]
}
};

Video Source Sets

Source sets can also be used for video fills. This is done by setting the sourceSet property of the video fill. The engine will then use the source with the closest size exceeding the drawing size.

Thumbnails will use the smallest source if features/matchThumbnailSourceToFill is disabled, which is the default.

For low end devices or scenes with large videos, you can force the preview to always use the smallest source when editing by enabling features/forceLowQualityVideoPreview. On export, the highest quality source is used in any case.

const videoFill = engine.block.createFill('video');
engine.block.setSourceSet(videoFill, 'fill/video/sourceSet', [
{
uri: 'https://img.ly/static/example-assets/sourceset/1x.mp4',
width: 1920,
height: 1080
}
]);
await engine.block.addVideoFileURIToSourceSet(
videoFill,
'fill/video/sourceSet',
'https://img.ly/static/example-assets/sourceset/2x.mp4'
);

Full Code

Here’s the full code:

import CreativeEngine from 'https://cdn.img.ly/packages/imgly/cesdk-engine/1.51.0/index.js';
const config = {
license: 'mtLT-_GJwMhE7LDnO8KKEma7qSuzWuDxiKuQcxHKmz3fjaXWY2lT3o3Z2VdL5twm',
baseURL: './release/assets',
};
CreativeEngine.init(config).then(async engine => {
document.getElementById('cesdk_container').append(engine.element);
const scene = engine.scene.create();
const page = engine.block.create('page');
engine.block.setWidth(page, 800);
engine.block.setHeight(page, 600);
engine.block.appendChild(scene, page);
engine.scene.zoomToBlock(page, 50, 50, 50, 50);
let block = engine.block.create('graphic');
engine.block.setShape(block, engine.block.createShape('rect'));
const imageFill = engine.block.createFill('image');
engine.block.setSourceSet(imageFill, 'fill/image/sourceSet', [
{
uri: 'https://img.ly/static/ubq_samples/sample_1_512x341.jpg',
width: 512,
height: 341,
},
{
uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg',
width: 1024,
height: 683,
},
{
uri: 'https://img.ly/static/ubq_samples/sample_1_2048x1366.jpg',
width: 2048,
height: 1366,
},
]);
engine.block.setFill(block, imageFill);
console.log(engine.block.getSourceSet(imageFill, 'fill/image/sourceSet'));
engine.block.appendChild(page, block);
const assetWithSourceSet = {
id: 'my-image',
meta: {
kind: 'image',
fillType: '//ly.img.ubq/fill/image',
},
payload: {
sourceSet: [
{
uri: 'https://img.ly/static/ubq_samples/sample_1_512x341.jpg',
width: 512,
height: 341,
},
{
uri: 'https://img.ly/static/ubq_samples/sample_1_1024x683.jpg',
width: 1024,
height: 683,
},
{
uri: 'https://img.ly/static/ubq_samples/sample_1_2048x1366.jpg',
width: 2048,
height: 1366,
},
],
},
};
await engine.asset.addLocalSource('my-dynamic-images');
engine.asset.addAssetToSource('my-dynamic-images', assetWithSourceSet);
// Could also acquire the asset using `findAssets` on the source
const result = await engine.asset.defaultApplyAsset(assetWithSourceSet);
console.log(
engine.block.getSourceSet(
engine.block.getFill(result),
'fill/image/sourceSet',
),
); // Lists the entries from above again.
const videoFill = engine.block.createFill('video');
engine.block.setSourceSet(videoFill, 'fill/video/sourceSet', [
{
uri: 'https://img.ly/static/example-assets/sourceset/1x.mp4',
width: 1920,
height: 1080,
},
]);
await engine.block.addVideoFileURIToSourceSet(
videoFill,
'fill/video/sourceSet',
'https://img.ly/static/example-assets/sourceset/2x.mp4',
);
});