# @wordpress/vips

Helper package to interact with [`wasm-vips`](https://github.com/kleisauke/wasm-vips).

## Installation

Install the module

``` bash
npm install @wordpress/vips --save
```

## Requirements

TypeScript consumers require TypeScript 5 or newer.

## API Reference

### cancelOperations

Cancels all ongoing image operations for a given item ID.

The onProgress callbacks check for an IDs existence in this list, killing the process if it’s absent.

*Parameters*

- *id* `ItemId`: Item ID.

*Returns*

- boolean Whether any operation was cancelled.

### compressImage

Compresses an existing image using vips.

*Parameters*

- *id* `ItemId`: Item ID.
- *buffer* `ArrayBuffer`: Original file buffer.
- *type* `string`: Mime type.
- *options* `ConvertImageOptions`: Compression options.

*Returns*

- `Promise< ArrayBuffer | ArrayBufferLike >`: Compressed file data.

### convertImageFormat

Converts an image to a different format using vips.

*Parameters*

- *id* `ItemId`: Item ID.
- *buffer* `ArrayBuffer`: Original file buffer.
- *inputType* `string`: Input mime type.
- *outputType* `string`: Output mime type.
- *options* `ConvertImageOptions`: Conversion options.

### encodePixelsAsJpeg

Encodes raw RGBA pixels as a JPEG, optionally carrying over the EXIF block from the file the pixels were decoded from.

This backs the HEIC upload path: wasm-vips ships no HEVC decoder, so the browser decodes HEIC to pixels with its platform codecs, and a canvas re-encode would drop all metadata. libvips reads the source’s EXIF from the container header alone, so no HEVC decoding is needed here either.

*Parameters*

- *id* `ItemId`: Item ID.
- *pixels* `ArrayBuffer`: Tightly packed 8-bit RGBA pixel data, as returned by `ImageData.data`.
- *width* `number`: Image width in pixels.
- *height* `number`: Image height in pixels.
- *options* `EncodePixelsOptions`: Encoding options.

*Returns*

- `Promise< ArrayBuffer | ArrayBufferLike >`: JPEG file data.

### getUltraHdrInfo

Probes a JPEG to determine whether it is an UltraHDR image with an embedded gain map.

Returns dimensions and HDR headroom on success, or `null` if the buffer is not a valid UltraHDR JPEG (no gain map, decode failure, or unsupported format).

*Parameters*

- *buffer* `ArrayBuffer`: Image buffer.

*Returns*

- `Promise< UltraHdrInfo | null >`: UltraHDR info, or null when the buffer is not UltraHDR.

### hasTransparency

Determines whether an image has visible transparency.

Channel presence alone is not enough: PNG encoders often retain an alpha channel even when every pixel is fully opaque, and animated GIFs declare a transparent color index for disposal-method frame compositing without ever rendering a visibly transparent pixel. This check loads the first frame (any transparency there is visible — there is no previous frame to inherit from) and samples the alpha channel for an actually-transparent pixel.

*Parameters*

- *buffer* `ArrayBuffer`: Original file object.

*Returns*

- `Promise< boolean >`: Whether any pixel in the image is partially or fully transparent.

### resizeImage

Resizes an image using vips.

UltraHDR JPEGs are auto-detected and preserved: libvips’s `uhdrload*` has higher priority than `jpegload*`, so `newFromBuffer`/`thumbnailBuffer` decode the gain map alongside the base image, and `jpegsave*` delegates to `uhdrsave*` on output when a gain map is attached.

Sub-sizes of animated GIF and WebP images keep every frame when `preserveAnimation` is set, as it is by default from the `wp_generate_animated_image_subsizes` filter. Cropped sizes cut every frame with the same rectangle. Animations whose decoded frames would not fit the WASM heap flatten to the first frame, so the upload gets a static sub-size rather than failing. See <https://github.com/WordPress/gutenberg/issues/80383>.

Without `preserveAnimation`, sub-sizes are generated from the first frame only, matching WordPress core’s server-side behavior: both GD and Imagick flatten animated images when resizing. Re-encoding every frame takes longer, and can produce sub-sizes larger than the original file. See <https://github.com/WordPress/gutenberg/issues/80266>.

*Parameters*

- *id* `ItemId`: Item ID.
- *buffer* `ArrayBuffer`: Original file buffer.
- *type* `string`: Mime type.
- *resize* `ImageSizeCrop`: Resize options.
- *options* `ResizeImageOptions`: Additional resize options.

*Returns*

- `Promise< { buffer: ArrayBuffer | ArrayBufferLike; width: number; height: number; originalWidth: number; originalHeight: number; } >`: Processed file data plus the old and new dimensions.

### rotateImage

Rotates an image based on EXIF orientation value.

EXIF orientation values: 1 = Normal (no rotation needed) 2 = Flipped horizontally 3 = Rotated 180° 4 = Flipped vertically 5 = Rotated 90° CCW and flipped horizontally 6 = Rotated 90° CW 7 = Rotated 90° CW and flipped horizontally 8 = Rotated 90° CCW

*Parameters*

- *id* `ItemId`: Item ID.
- *buffer* `ArrayBuffer`: Original file buffer.
- *type* `string`: Mime type.
- *orientation* `number`: EXIF orientation value (1-8).

*Returns*

- `Promise< { buffer: ArrayBuffer | ArrayBufferLike; width: number; height: number; } >`: Rotated file data plus the new dimensions.

### vipsCancelOperations

Cancels all ongoing image operations for a given item ID.

The onProgress callbacks check for an IDs existence in this list, killing the process if it’s absent.

*Parameters*

- *id* `ItemId`: Item ID.

*Returns*

- boolean Whether any operation was cancelled.

### vipsCompressImage

Compresses an existing image using vips.

*Parameters*

- *id* `ItemId`: Item ID.
- *buffer* `ArrayBuffer`: Original file buffer.
- *type* `string`: Mime type.
- *options* `ConvertImageOptions`: Compression options.

*Returns*

- `Promise< ArrayBuffer | ArrayBufferLike >`: Compressed file data.

### vipsConvertImageFormat

Converts an image to a different format using vips.

*Parameters*

- *id* `ItemId`: Item ID.
- *buffer* `ArrayBuffer`: Original file buffer.
- *inputType* `string`: Input mime type.
- *outputType* `string`: Output mime type.
- *options* `ConvertImageOptions`: Conversion options.

### vipsEncodePixelsAsJpeg

Encodes raw RGBA pixels as a JPEG, optionally carrying over the EXIF block from the file the pixels were decoded from.

This backs the HEIC upload path: wasm-vips ships no HEVC decoder, so the browser decodes HEIC to pixels with its platform codecs, and a canvas re-encode would drop all metadata. libvips reads the source’s EXIF from the container header alone, so no HEVC decoding is needed here either.

*Parameters*

- *id* `ItemId`: Item ID.
- *pixels* `ArrayBuffer`: Tightly packed 8-bit RGBA pixel data, as returned by `ImageData.data`.
- *width* `number`: Image width in pixels.
- *height* `number`: Image height in pixels.
- *options* `EncodePixelsOptions`: Encoding options.

*Returns*

- `Promise< ArrayBuffer | ArrayBufferLike >`: JPEG file data.

### vipsGetUltraHdrInfo

Probes a JPEG to determine whether it is an UltraHDR image with an embedded gain map.

Returns dimensions and HDR headroom on success, or `null` if the buffer is not a valid UltraHDR JPEG (no gain map, decode failure, or unsupported format).

*Parameters*

- *buffer* `ArrayBuffer`: Image buffer.

*Returns*

- `Promise< UltraHdrInfo | null >`: UltraHDR info, or null when the buffer is not UltraHDR.

### vipsHasTransparency

Determines whether an image has visible transparency.

Channel presence alone is not enough: PNG encoders often retain an alpha channel even when every pixel is fully opaque, and animated GIFs declare a transparent color index for disposal-method frame compositing without ever rendering a visibly transparent pixel. This check loads the first frame (any transparency there is visible — there is no previous frame to inherit from) and samples the alpha channel for an actually-transparent pixel.

*Parameters*

- *buffer* `ArrayBuffer`: Original file object.

*Returns*

- `Promise< boolean >`: Whether any pixel in the image is partially or fully transparent.

### vipsResizeImage

Resizes an image using vips.

UltraHDR JPEGs are auto-detected and preserved: libvips’s `uhdrload*` has higher priority than `jpegload*`, so `newFromBuffer`/`thumbnailBuffer` decode the gain map alongside the base image, and `jpegsave*` delegates to `uhdrsave*` on output when a gain map is attached.

Sub-sizes of animated GIF and WebP images keep every frame when `preserveAnimation` is set, as it is by default from the `wp_generate_animated_image_subsizes` filter. Cropped sizes cut every frame with the same rectangle. Animations whose decoded frames would not fit the WASM heap flatten to the first frame, so the upload gets a static sub-size rather than failing. See <https://github.com/WordPress/gutenberg/issues/80383>.

Without `preserveAnimation`, sub-sizes are generated from the first frame only, matching WordPress core’s server-side behavior: both GD and Imagick flatten animated images when resizing. Re-encoding every frame takes longer, and can produce sub-sizes larger than the original file. See <https://github.com/WordPress/gutenberg/issues/80266>.

*Parameters*

- *id* `ItemId`: Item ID.
- *buffer* `ArrayBuffer`: Original file buffer.
- *type* `string`: Mime type.
- *resize* `ImageSizeCrop`: Resize options.
- *options* `ResizeImageOptions`: Additional resize options.

*Returns*

- `Promise< { buffer: ArrayBuffer | ArrayBufferLike; width: number; height: number; originalWidth: number; originalHeight: number; } >`: Processed file data plus the old and new dimensions.

### vipsRotateImage

Rotates an image based on EXIF orientation value.

EXIF orientation values: 1 = Normal (no rotation needed) 2 = Flipped horizontally 3 = Rotated 180° 4 = Flipped vertically 5 = Rotated 90° CCW and flipped horizontally 6 = Rotated 90° CW 7 = Rotated 90° CW and flipped horizontally 8 = Rotated 90° CCW

*Parameters*

- *id* `ItemId`: Item ID.
- *buffer* `ArrayBuffer`: Original file buffer.
- *type* `string`: Mime type.
- *orientation* `number`: EXIF orientation value (1-8).

*Returns*

- `Promise< { buffer: ArrayBuffer | ArrayBufferLike; width: number; height: number; } >`: Rotated file data plus the new dimensions.