or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

docs

context-management.mdindex.mdlegacy-api.mdoutput.mdtransformations.md
tile.json

transformations.mddocs/

Image Transformations

Core transformation operations for manipulating images including resize, rotate, flip, crop, and extent modifications. All operations support method chaining and lazy execution.

Capabilities

ImageManipulatorContext

The main class for chaining image transformation operations. All methods return the same context instance to enable fluent method chaining.

/**
 * Context for chaining image manipulation operations with lazy execution
 */
class ImageManipulatorContext {
  resize(size: { width?: number | null; height?: number | null }): ImageManipulatorContext;
  rotate(degrees: number): ImageManipulatorContext;
  flip(flipType: FlipType): ImageManipulatorContext;
  crop(rect: { originX: number; originY: number; width: number; height: number }): ImageManipulatorContext;
  extent(options: { backgroundColor?: string | null; originX?: number; originY?: number; width: number; height: number }): ImageManipulatorContext;
  reset(): ImageManipulatorContext;
  renderAsync(): Promise<ImageRef>;
}

Resize Operation

Resizes the image to specified dimensions with automatic aspect ratio preservation when only one dimension is provided.

/**
 * Resizes the image to the given size
 * @param size - Target dimensions. If only width or height specified, other dimension calculated to preserve aspect ratio
 * @returns ImageManipulatorContext for method chaining
 */
resize(size: { width?: number | null; height?: number | null }): ImageManipulatorContext;

Usage Examples:

import { ImageManipulator } from "expo-image-manipulator";

// Resize to exact dimensions
const result1 = await ImageManipulator.manipulate(imageUri)
  .resize({ width: 300, height: 200 })
  .renderAsync();

// Resize width only (height calculated to preserve aspect ratio)
const result2 = await ImageManipulator.manipulate(imageUri)
  .resize({ width: 400 })
  .renderAsync();

// Resize height only (width calculated to preserve aspect ratio)  
const result3 = await ImageManipulator.manipulate(imageUri)
  .resize({ height: 300 })
  .renderAsync();

// Multiple resize operations can be chained
const result4 = await ImageManipulator.manipulate(imageUri)
  .resize({ width: 800 })
  .resize({ height: 600 }) // This will override previous resize
  .renderAsync();

Rotate Operation

Rotates the image by the specified number of degrees. Positive values rotate clockwise, negative values rotate counter-clockwise.

/**
 * Rotates the image by the given number of degrees
 * @param degrees - Rotation angle in degrees. Positive for clockwise, negative for counter-clockwise
 * @returns ImageManipulatorContext for method chaining
 */
rotate(degrees: number): ImageManipulatorContext;

Usage Examples:

// Rotate 90 degrees clockwise
const result1 = await ImageManipulator.manipulate(imageUri)
  .rotate(90)
  .renderAsync();

// Rotate 45 degrees counter-clockwise
const result2 = await ImageManipulator.manipulate(imageUri)
  .rotate(-45)
  .renderAsync();

// Multiple rotations are cumulative
const result3 = await ImageManipulator.manipulate(imageUri)
  .rotate(90)
  .rotate(90) // Total 180 degrees
  .renderAsync();

// Combine with other operations
const result4 = await ImageManipulator.manipulate(imageUri)
  .resize({ width: 300 })
  .rotate(90)
  .renderAsync();

Flip Operation

Flips the image vertically or horizontally. Only one flip operation per transformation chain is supported.

/**
 * Flips the image vertically or horizontally
 * @param flipType - Direction to flip: FlipType.Vertical or FlipType.Horizontal
 * @returns ImageManipulatorContext for method chaining
 */
flip(flipType: FlipType): ImageManipulatorContext;

Usage Examples:

import { FlipType } from "expo-image-manipulator";

// Flip horizontally (mirror left-right)
const result1 = await ImageManipulator.manipulate(imageUri)
  .flip(FlipType.Horizontal)
  .renderAsync();

// Flip vertically (mirror top-bottom)
const result2 = await ImageManipulator.manipulate(imageUri)
  .flip(FlipType.Vertical)
  .renderAsync();

// Using enum values
const result3 = await ImageManipulator.manipulate(imageUri)
  .flip(FlipType.Horizontal)
  .renderAsync();

// Combine with rotation for complex transformations
const result4 = await ImageManipulator.manipulate(imageUri)
  .rotate(90)
  .flip(FlipType.Horizontal)
  .renderAsync();

// For both horizontal and vertical flip, use separate operations
const result5 = await ImageManipulator.manipulate(imageUri)
  .flip(FlipType.Horizontal)
  .renderAsync();

const result6 = await ImageManipulator.manipulate(result5.uri)
  .flip(FlipType.Vertical)
  .renderAsync();

Crop Operation

Crops the image to a rectangular region specified by origin coordinates and dimensions.

/**
 * Crops the image to the given rectangle's origin and size
 * @param rect - Rectangle defining the crop area with top-left origin and dimensions
 * @returns ImageManipulatorContext for method chaining
 */
crop(rect: { originX: number; originY: number; width: number; height: number }): ImageManipulatorContext;

Usage Examples:

// Crop a 200x200 square from top-left corner
const result1 = await ImageManipulator.manipulate(imageUri)
  .crop({ originX: 0, originY: 0, width: 200, height: 200 })
  .renderAsync();

// Crop from center (assuming 800x600 original)
const result2 = await ImageManipulator.manipulate(imageUri)
  .crop({ originX: 200, originY: 150, width: 400, height: 300 })
  .renderAsync();

// Crop after resize for precise control
const result3 = await ImageManipulator.manipulate(imageUri)
  .resize({ width: 800 })
  .crop({ originX: 100, originY: 50, width: 600, height: 400 })
  .renderAsync();

// Multiple crops can be applied sequentially
const result4 = await ImageManipulator.manipulate(imageUri)
  .crop({ originX: 50, originY: 50, width: 400, height: 400 })
  .crop({ originX: 100, originY: 100, width: 200, height: 200 })
  .renderAsync();

Extent Operation (Web Only)

Sets the image size and offset, filling unfilled areas with a background color. This operation is only available on web platforms.

/**
 * Set the image size and offset. If enlarged, unfilled areas are set to backgroundColor
 * @param options - Extent configuration with size, position, and background color
 * @returns ImageManipulatorContext for method chaining
 * @platform web
 */
extent(options: {
  backgroundColor?: string | null;
  originX?: number;
  originY?: number;
  width: number;
  height: number;
}): ImageManipulatorContext;

Usage Examples:

// Extend image to larger canvas with white background
const result1 = await ImageManipulator.manipulate(imageUri)
  .extent({
    width: 800,
    height: 600,
    backgroundColor: '#FFFFFF'
  })
  .renderAsync();

// Position image within larger canvas
const result2 = await ImageManipulator.manipulate(imageUri)
  .extent({
    width: 1000,
    height: 800,
    originX: 100,
    originY: 150,
    backgroundColor: 'transparent'
  })
  .renderAsync();

// Combine with other operations
const result3 = await ImageManipulator.manipulate(imageUri)
  .resize({ width: 300 })
  .extent({
    width: 500,
    height: 500,
    originX: 100,
    originY: 100,
    backgroundColor: '#F0F0F0'
  })
  .renderAsync();

Reset Operation

Resets the manipulation context to the originally loaded image, discarding all pending transformations.

/**
 * Resets the manipulator context to the originally loaded image
 * @returns ImageManipulatorContext with all transformations cleared
 */
reset(): ImageManipulatorContext;

Usage Examples:

// Reset after applying transformations
const context = ImageManipulator.manipulate(imageUri);

// Apply some transformations
context.resize({ width: 300 }).rotate(90).flip('horizontal');

// Reset to original image
context.reset();

// Apply different transformations
const result = await context
  .resize({ width: 500 })
  .crop({ originX: 0, originY: 0, width: 400, height: 400 })
  .renderAsync();

Render Operation

Executes all queued transformation operations and returns a reference to the resulting image.

/**
 * Awaits for all manipulation tasks to finish and resolves with a reference to the result image
 * @returns Promise that resolves to ImageRef representing the manipulated image
 */
renderAsync(): Promise<ImageRef>;

Usage Examples:

// Simple render after transformations
const context = ImageManipulator.manipulate(imageUri);
const image = await context
  .resize({ width: 400 })
  .rotate(45)
  .renderAsync();

// Multiple renders from same context (re-executes all operations)
const context2 = ImageManipulator.manipulate(imageUri)
  .resize({ width: 300 })
  .flip('horizontal');

const image1 = await context2.renderAsync();
const image2 = await context2.renderAsync(); // Same result as image1

// Save rendered images
const result1 = await image1.saveAsync();
const result2 = await image2.saveAsync();

// Clean up
context2.release();
image1.release();
image2.release();

Type Definitions

/**
 * Flip direction enumeration
 */
enum FlipType {
  Vertical = 'vertical',
  Horizontal = 'horizontal'
}

/**
 * Rectangle definition for crop operations
 */
interface CropRect {
  originX: number;
  originY: number;
  width: number;
  height: number;
}

/**
 * Size specification for resize operations
 */
interface ResizeSize {
  width?: number | null;
  height?: number | null;
}

/**
 * Options for extent operations (Web only)
 */
interface ExtentOptions {
  backgroundColor?: string | null;
  originX?: number;
  originY?: number;
  width: number;
  height: number;
}