Image editor
ImageEditor resizes, crops, rotates, flips and re-encodes an image file, bound to
expo-image-manipulator. A photo from the image picker is usually
far larger than anything the app shows or uploads, and this is how it becomes a thumbnail or an
upload-sized JPEG.
import { ImageEditor } from '@ng-native/expo';
inject(ImageEditor)edit() takes the module's own actions and save options, and runs them through its contextual API:
each action applied in order, the result rendered and saved to a new file in the cache. The context
and the rendered image hold native memory that nothing else frees, so both are released once the
file is written, including when it fails.
Install
npx expo install expo-image-manipulatorimport { ImageEditor, SaveFormat, FlipType } from '@ng-native/expo/image-editor';The smallest useful example
import { Component, inject, signal } from '@angular/core';
import { ImagePicker } from '@ng-native/expo/image-picker';
import { ImageEditor, SaveFormat } from '@ng-native/expo/image-editor';
@Component({
selector: 'app-avatar',
template: `<pressable (press)="choose()"><text>Choose a photo</text></pressable>`,
})
export class Avatar {
private readonly picker = inject(ImagePicker);
private readonly editor = inject(ImageEditor);
protected readonly uri = signal<string | null>(null);
protected async choose(): Promise<void> {
const [photo] = await this.picker.pick({ mediaTypes: ['images'] });
if (!photo) return;
const avatar = await this.editor.edit(photo.uri, [{ resize: { width: 256 } }], {
format: SaveFormat.WEBP,
compress: 0.8,
});
this.uri.set(avatar?.uri ?? null);
}
}What it does
edit(uri, actions?, options?)- applies each action in order and resolves to the saved file: itsuri,widthandheight, andbase64when asked for. Each action has exactly one key:{ resize: { width?, height? } }- one side given keeps the aspect ratio.{ rotate: degrees }- clockwise.{ flip: FlipType.Horizontal }orFlipType.Vertical.{ crop: { originX, originY, width, height } }- in pixels of the image as it is at that step.{ extent: { width, height, originX?, originY?, backgroundColor? } }- on the web only, grows or shrinks the canvas, filling any new space with the color. Elsewhere it is skipped.
The options are
format(SaveFormat.JPEGby default,PNGorWEBP),compressfrom 0 to 1, andbase64.manipulate(uri)- the module's ownImageManipulatorContext, for chaining steps by hand:resize(),rotate(),flip(),crop()andreset(), thenrenderAsync()and the image'ssaveAsync(). The caller releases the context and the image once done.
SaveFormat and FlipType are exported beside the service: the module's own enums, typed as those
enums, without loading the module, so code that edits can run in a test.
Without the module
On iOS and Android, a missing expo-image-manipulator - never installed, or installed without the app
being rebuilt since - throws a MissingModuleError when the service first reaches for it. Its
message names the module and the commands that fix it; see
Using a module.
On the web, and in a test that provides no fake, edit() resolves to null and manipulate() returns null.
Reference
ImageEditorservice@ng-native/expoimport { ImageEditor } from '@ng-native/expo';Methods
edit(source: string, actions: readonly Action[] = [], options: SaveOptions = {}): Promise<ImageResult | null> Applies each action in order and saves the result as a new file: a JPEG unless format says otherwise, compress from 0 to 1, and base64 to have the contents back as well. Each action has exactly one key: resize , rotate (degrees, clockwise), flip , crop , or on the web extent .
manipulate(source: string): ImageManipulatorContext | null The module's own context for a file or data URI, for chaining steps by hand: resize() , rotate() , flip() , crop() and reset() , then renderAsync() . The caller releases it, and the image it renders, once done.