Search
Loading...
Skip to content

Rotate Images

The CreativeEditor SDK (CE.SDK) ships with a headless Server Mode for Node.js that lets you process scenes without rendering a UI. This guide covers how to script precise rotations against CE.SDK’s server APIs so your Node.js services can rotate assets on demand.

Requirements#

  • Node.js 18 or newer
  • CE.SDK package in your app: npm install @cesdk/node
  • CESDK_BASE_URL pointing to your CE.SDK asset bundle (path or HTTPS)

What You’ll Learn#

  • Rotate image blocks by precise angles with JavaScript.
  • Apply the same rotation to multiple blocks in one pass.
  • Restore the original orientation or limit rotation to specific increments.

When to use#

Image rotation is a frequent step in backend workflows. Use server-side rotation when you need to:

  • Normalize user uploads before downstream processing.
  • Generate asset variations (for example, preview thumbnails) on your backend.
  • Enforce template rules during automated rendering jobs.

Use these server-side rendering patterns to run asset generation and template enforcement jobs without opening the client editor.

How to Use#

Test a sample file
  1. At the root of your Node.js project, run npm install @cesdk/node.
  2. Add your license key to .env: LICENSE_KEY="<your_license_key>".
  3. Create a file named rotate.js.
  4. Paste the following script into rotate.js:
rotate.js
import 'dotenv/config';
import fs from 'fs/promises';
import path from 'path';
import CreativeEngine from '@cesdk/node';
// Configuration for the engine
const config = {
license: process.env.LICENSE_KEY,
baseURL: 'https://cdn.img.ly/packages/imgly/cesdk-node/1.60.0/assets'
};
// Start CreativeEngine
CreativeEngine.init(config).then(async (engine) => {
console.log('CE.SDK Engine initialized');
// Load the demo scene from IMG.LY CDN
try {
await engine.addDefaultAssetSources();
await engine.scene.loadFromURL(
'https://cdn.img.ly/assets/demo/v1/ly.img.template/templates/cesdk_instagram_photo_1.scene'
);
// Grab the first page
const [page] = engine.block.findByType('page');
// Collect every graphic block
const graphics = engine.block.findByType('graphic');
if (graphics.length === 0) {
throw new Error('No graphic blocks found to rotate.');
}
// Loop through the graphics and rotate each one by 45°
graphics.forEach((blockId) => {
engine.block.setFloat(blockId, 'rotation', Math.PI / 4);
});
// Export the updated page to a PNG
const blob = await engine.block.export(page, { mimeType: 'image/png' });
// Convert the blob to a buffer
const arrayBuffer = await blob.arrayBuffer();
// Set an output directory
const outputDir = path.resolve('.');
await fs.mkdir(outputDir, { recursive: true });
const pattern = /^example-output\((\d+)\)\.png$/;
const nextIndex =
(await fs.readdir(outputDir))
.map((file) => pattern.exec(file)?.[1])
.filter(Boolean)
.map(Number)
.reduce((max, n) => Math.max(max, n), 0) + 1;
// Pick and output filename
const outputName = `example-rotated(${nextIndex}).png`;
const outputPath = path.join(outputDir, outputName);
// Write the buffer to disk
await fs.writeFile(outputPath, Buffer.from(arrayBuffer));
console.log(`Export completed: ${outputName}`);
} catch (error) {
console.error('Error processing scene:', error);
} finally {
engine.dispose();
}
});
  1. Run node rotate.js.
  2. The script downloads a sample, rotates it by 45°, and stores the export alongside the script (change the output location by updating const outputDir).
  1. After starting the CreativeEditor and loading the scene from the image, return every page in the scene:
const [page] = engine.block.findByType('page');
  1. Collect all graphic blocks on the page:
const graphics = engine.block.findByType('graphic');
if (graphics.length === 0) {
throw new Error('No graphic blocks found to rotate.');
}
  1. Check every graphic block ID:
graphics.forEach((blockId) => {
// Rotation function
});

Now, you’re ready to call the rotation functions.

Rotate an image#

Combine the setRotation function with Math.PI. For example, to rotate an image by 45°:

engine.block.setRotation(blockId, Math.PI / 4);

Rotate multiple blocks together#

Grouping keeps relative positions intact when you need to rotate blocks together.

const groupId = engine.block.group(graphics);
engine.block.setFloat(groupId, 'rotation', Math.PI / 4);

If you run this inside a batch job, and later jobs need different rotations, remember to either:

  1. Ungroup the scene.
  2. Duplicate the scene.

To rotate every graphic block in the scene without grouping:

const graphics = engine.block.findByType('graphic');
if (graphics.length === 0) {
throw new Error('No graphic blocks found to rotate.');
}
graphics.forEach((blockId) => {
engine.block.setFloat(blockId, 'transform/rotation', Math.PI / 4);
});

Reset rotation to the original orientation#

engine.block.setFloat(blockId, 'rotation', 0);

Use this to revert to the original orientation after exporting an alternate angle.

Snap rotation to fixed increments#

Snap the rotation to fixed increments before saving the scene for later editing:

graphics.forEach((blockId) => {
const targetAngle = Math.PI / 3; // 60° in radians
const step = Math.PI / 2;
const snapped = Math.round(targetAngle / step) * step;
engine.block.setFloat(blockId, 'rotation', snapped); // Rotation function
});

Valid steps include 15deg, 45deg, 90deg, or 360deg (no constraint).

Troubleshooting#

IssueResolution
Image fails to loadVerify the URI is reachable from your server or switch to a file URI inside the asset bundle.
Rotation has no effectEnsure your code appends the block to a page before setting rotation.
Engine keeps runningCall engine.dispose() once exports complete to free native resources.

Next steps#

API reference

API FunctionUsage
block.findByTypeLocate pages or block types before applying transforms.
block.groupGroup blocks for collective transforms.
block.setFloatSet numeric transforms (use ‘transform/rotation’ for single blocks, ‘rotation’ for groups).
block.exportRender a page to an image or document.
scene.createStart a new scene when running headless jobs.