first
This commit is contained in:
@@ -0,0 +1,725 @@
|
||||
---
|
||||
name: sharp
|
||||
description: Process images using the sharp Node.js library. Use when the user wants to resize, convert, crop, composite, transform, or optimize images programmatically.
|
||||
---
|
||||
|
||||
# Sharp
|
||||
|
||||
API reference for sharp — a high-performance Node.js image processing library built on libvips.
|
||||
|
||||
Typically 4-5x faster than ImageMagick/GraphicsMagick. Supports JPEG, PNG, WebP, GIF, AVIF, TIFF, SVG, HEIF, JP2, and JXL.
|
||||
|
||||
Official docs: https://sharp.pixelplumbing.com
|
||||
Repository: https://github.com/lovell/sharp
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install sharp
|
||||
```
|
||||
|
||||
Requires Node.js ^18.17.0 or >= 20.3.0 (or Deno/Bun with Node-API v9).
|
||||
|
||||
## Usage
|
||||
|
||||
Sharp uses a fluent, chainable API. Every call returns a Sharp instance.
|
||||
|
||||
```js
|
||||
import sharp from 'sharp';
|
||||
|
||||
await sharp('input.jpg')
|
||||
.resize(800, 600)
|
||||
.jpeg({ quality: 80 })
|
||||
.toFile('output.jpg');
|
||||
```
|
||||
|
||||
Sharp implements `stream.Duplex` — it can be piped to/from.
|
||||
|
||||
---
|
||||
|
||||
## Constructor
|
||||
|
||||
```js
|
||||
sharp([input], [options])
|
||||
```
|
||||
|
||||
- `input` (Buffer | string | Array): Image buffer, file path, array of inputs, or omit for stream input.
|
||||
|
||||
### Options
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `failOn` | string | `'warning'` | `'none'`, `'truncated'`, `'error'`, `'warning'` |
|
||||
| `limitInputPixels` | number \| boolean | `268402689` | Max pixels; `false` to disable |
|
||||
| `unlimited` | boolean | `false` | Remove memory safety for JPEG/PNG/SVG/HEIF |
|
||||
| `autoOrient` | boolean | `false` | Auto-rotate per EXIF Orientation |
|
||||
| `sequentialRead` | boolean | `true` | Sequential vs random access |
|
||||
| `density` | number | `72` | DPI for vector images (1-100000) |
|
||||
| `ignoreIcc` | boolean | `false` | Ignore embedded ICC profile |
|
||||
| `pages` | number | `1` | Pages to extract; `-1` for all |
|
||||
| `page` | number | `0` | Starting page (zero-based) |
|
||||
| `animated` | boolean | `false` | Read all frames (equiv. `pages: -1`) |
|
||||
|
||||
### Raw Input
|
||||
|
||||
```js
|
||||
sharp(buffer, { raw: { width: 100, height: 100, channels: 4 } })
|
||||
```
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `width` | number | Pixel width |
|
||||
| `height` | number | Pixel height |
|
||||
| `channels` | number | 1-4 |
|
||||
| `premultiplied` | boolean | Skip premultiplication (default `false`) |
|
||||
|
||||
### Create New Image
|
||||
|
||||
```js
|
||||
sharp({ create: { width: 300, height: 200, channels: 4, background: '#ff0000' } })
|
||||
```
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `width` | number | Pixel width |
|
||||
| `height` | number | Pixel height |
|
||||
| `channels` | number | 3 (RGB) or 4 (RGBA) |
|
||||
| `background` | string \| Object | Color (parsed by color module) |
|
||||
| `noise` | Object | `{ type: 'gaussian', mean: 128, sigma: 30 }` |
|
||||
|
||||
### Render Text
|
||||
|
||||
```js
|
||||
sharp({ text: { text: 'Hello', font: 'Arial', dpi: 150 } })
|
||||
```
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| `text` | string | -- | UTF-8; supports Pango markup |
|
||||
| `font` | string | -- | Font name |
|
||||
| `fontfile` | string | -- | Absolute path to font file |
|
||||
| `width` | number | `0` | Word-wrap boundary; 0 = no wrap |
|
||||
| `height` | number | `0` | Max height |
|
||||
| `align` | string | `'left'` | `'left'`, `'centre'`, `'center'`, `'right'` |
|
||||
| `justify` | boolean | `false` | Text justification |
|
||||
| `dpi` | number | `72` | Render resolution |
|
||||
| `rgba` | boolean | `false` | RGBA for color emoji/Pango markup |
|
||||
| `spacing` | number | `0` | Line height in points |
|
||||
| `wrap` | string | `'word'` | `'word'`, `'char'`, `'word-char'`, `'none'` |
|
||||
|
||||
### Join Array
|
||||
|
||||
```js
|
||||
sharp([img1, img2, img3], { join: { across: 3, shim: 10 } })
|
||||
```
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| `across` | number | `1` | Images per row |
|
||||
| `animated` | boolean | `false` | Join as animated image |
|
||||
| `shim` | number | `0` | Pixel gap between images |
|
||||
| `background` | string \| Object | -- | Gap fill color |
|
||||
| `halign` | string | `'left'` | `'left'`, `'centre'`, `'right'` |
|
||||
| `valign` | string | `'top'` | `'top'`, `'centre'`, `'bottom'` |
|
||||
|
||||
### Clone
|
||||
|
||||
```js
|
||||
const pipeline = sharp('input.jpg');
|
||||
const clone1 = pipeline.clone().resize(200).toFile('thumb.jpg');
|
||||
const clone2 = pipeline.clone().resize(800).toFile('large.jpg');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Resize
|
||||
|
||||
```js
|
||||
.resize([width], [height], [options])
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `width` | number | -- | Target width (null to auto-scale) |
|
||||
| `height` | number | -- | Target height (null to auto-scale) |
|
||||
| `fit` | string | `'cover'` | `'cover'`, `'contain'`, `'fill'`, `'inside'`, `'outside'` |
|
||||
| `position` | string | `'centre'` | Gravity/position for cover/contain |
|
||||
| `background` | string \| Object | `{r:0,g:0,b:0,alpha:1}` | Fill color for `contain` |
|
||||
| `kernel` | string | `'lanczos3'` | `'nearest'`, `'linear'`, `'cubic'`, `'mitchell'`, `'lanczos2'`, `'lanczos3'` |
|
||||
| `withoutEnlargement` | boolean | `false` | Don't upscale |
|
||||
| `withoutReduction` | boolean | `false` | Don't downscale |
|
||||
| `fastShrinkOnLoad` | boolean | `true` | JPEG/WebP shrink-on-load |
|
||||
|
||||
**Fit modes:**
|
||||
- `cover` — crop to fill both dimensions
|
||||
- `contain` — letterbox within dimensions
|
||||
- `fill` — stretch to exact dimensions (ignores aspect ratio)
|
||||
- `inside` — fit within, no exceeding
|
||||
- `outside` — minimum size meeting both dimensions
|
||||
|
||||
**Position values:** `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`, `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `centre`/`center`
|
||||
|
||||
**Strategy (cover only):** `entropy`, `attention`
|
||||
|
||||
Only one resize per pipeline.
|
||||
|
||||
---
|
||||
|
||||
## Operations
|
||||
|
||||
### Rotation & Orientation
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.rotate([angle], [options])` | Rotate by degrees; omit angle for EXIF auto-rotate. `options.background` for fill color |
|
||||
| `.autoOrient()` | Auto-orient from EXIF, then remove Orientation tag |
|
||||
| `.flip([flip])` | Vertical mirror (default `true`) |
|
||||
| `.flop([flop])` | Horizontal mirror (default `true`) |
|
||||
|
||||
### Transform
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.affine(matrix, [options])` | 2x2 affine transform. Options: `background`, `idx`, `idy`, `odx`, `ody`, `interpolator` |
|
||||
| `.extend(extend)` | Add padding. Number for uniform, or `{ top, right, bottom, left, extendWith, background }`. `extendWith`: `'background'`, `'copy'`, `'repeat'`, `'mirror'` |
|
||||
| `.extract({ left, top, width, height })` | Crop region. Can be called before and/or after resize |
|
||||
| `.trim([options])` | Auto-crop to content. Options: `background` (default top-left pixel), `threshold` (default `10`), `lineArt` |
|
||||
|
||||
### Enhancement
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.sharpen([options])` | Sharpen. `options.sigma` (0.000001-10), `.m1` (flat), `.m2` (jagged), `.x1`, `.y2`, `.y3` |
|
||||
| `.blur([options])` | No args: 3x3 box blur. `options.sigma` (0.3-1000) for Gaussian. Options: `precision`, `minAmplitude` |
|
||||
| `.median([size])` | Median filter, default 3x3 |
|
||||
| `.gamma([gamma], [gammaOut])` | Gamma correction (1.0-3.0, default 2.2) |
|
||||
| `.normalise([options])` | Stretch luminance. `options.lower` (default `1`), `.upper` (default `99`) percentiles |
|
||||
| `.clahe({ width, height, [maxSlope] })` | Contrast Limited Adaptive Histogram Equalization |
|
||||
|
||||
### Morphology
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.dilate([width])` | Dilation, default 1px |
|
||||
| `.erode([width])` | Erosion, default 1px |
|
||||
|
||||
### Pixel Operations
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.negate([options])` | Invert colors. `options.alpha` (default `true`) |
|
||||
| `.threshold([value], [options])` | Binarize at threshold (0-255, default 128). `options.greyscale` (default `true`) |
|
||||
| `.boolean(operand, operator)` | Bitwise op with another image: `'and'`, `'or'`, `'eor'` |
|
||||
| `.linear([a], [b])` | Per-channel linear transform: `a * pixel + b` |
|
||||
| `.recomb(matrix)` | 3x3 or 4x4 color recombination matrix |
|
||||
| `.modulate([options])` | Adjust `brightness` (multiply), `saturation` (multiply), `hue` (degrees), `lightness` (add) |
|
||||
| `.convolve(kernel)` | Custom convolution: `{ width, height, kernel, scale, offset }` |
|
||||
| `.flatten([options])` | Merge alpha with `options.background`, remove alpha |
|
||||
| `.unflatten()` | Add alpha; white becomes transparent (experimental) |
|
||||
|
||||
---
|
||||
|
||||
## Colour
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.tint(color)` | Apply tint, preserving alpha |
|
||||
| `.greyscale([bool])` | Convert to 8-bit greyscale (alias: `.grayscale()`) |
|
||||
| `.pipelineColourspace(space)` | Set pipeline colorspace (e.g. `'rgb16'`, `'lab'`, `'grey16'`) |
|
||||
| `.toColourspace(space)` | Set output colorspace (e.g. `'srgb'`, `'cmyk'`, `'b-w'`) |
|
||||
|
||||
---
|
||||
|
||||
## Channel
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.removeAlpha()` | Remove alpha channel |
|
||||
| `.ensureAlpha([alpha])` | Add alpha if missing. `alpha`: 0 (transparent) to 1 (opaque, default) |
|
||||
| `.extractChannel(channel)` | Extract single channel: `0`-`3` or `'red'`, `'green'`, `'blue'`, `'alpha'` |
|
||||
| `.joinChannel(images, [options])` | Add channel(s) from other image(s) |
|
||||
| `.bandbool(op)` | Bitwise across all bands: `'and'`, `'or'`, `'eor'` |
|
||||
|
||||
---
|
||||
|
||||
## Composite
|
||||
|
||||
```js
|
||||
.composite(images)
|
||||
```
|
||||
|
||||
Overlay images onto the pipeline image. `images` is an array of objects:
|
||||
|
||||
| Property | Type | Default | Description |
|
||||
|----------|------|---------|-------------|
|
||||
| `input` | Buffer \| string | -- | Image data, file path, or `create`/`text` object |
|
||||
| `blend` | string | `'over'` | Blend mode |
|
||||
| `gravity` | string | `'centre'` | Placement gravity |
|
||||
| `top` | number | -- | Pixel offset from top (overrides gravity) |
|
||||
| `left` | number | -- | Pixel offset from left (overrides gravity) |
|
||||
| `tile` | boolean | `false` | Repeat overlay across image |
|
||||
| `premultiplied` | boolean | `false` | Skip premultiplication |
|
||||
| `density` | number | `72` | DPI for vector overlays |
|
||||
|
||||
**Blend modes:** `over`, `multiply`, `screen`, `overlay`, `darken`, `lighten`, `hard-light`, `soft-light`, `difference`, `exclusion`, `colour-dodge`, `colour-burn`, `add`, `saturate`, `clear`, `source`, `in`, `out`, `atop`, `dest`, `dest-over`, `dest-in`, `dest-out`, `dest-atop`, `xor`
|
||||
|
||||
```js
|
||||
await sharp('base.png')
|
||||
.composite([{ input: 'overlay.png', gravity: 'southeast' }])
|
||||
.toFile('output.png');
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Output
|
||||
|
||||
### Write to File
|
||||
|
||||
```js
|
||||
await sharp('input.jpg').resize(800).toFile('output.jpg');
|
||||
```
|
||||
|
||||
Format inferred from extension. Returns `{ format, size, width, height, channels, premultiplied }`.
|
||||
|
||||
### Write to Buffer
|
||||
|
||||
```js
|
||||
const buffer = await sharp('input.jpg').resize(800).toBuffer();
|
||||
// or with info:
|
||||
const { data, info } = await sharp('input.jpg').resize(800).toBuffer({ resolveWithObject: true });
|
||||
```
|
||||
|
||||
### Format Methods
|
||||
|
||||
#### JPEG
|
||||
|
||||
```js
|
||||
.jpeg([options])
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `quality` | number | `80` | 1-100 |
|
||||
| `progressive` | boolean | `false` | Progressive JPEG |
|
||||
| `chromaSubsampling` | string | `'4:2:0'` | `'4:2:0'` or `'4:4:4'` |
|
||||
| `mozjpeg` | boolean | `false` | MozJPEG optimizations |
|
||||
| `force` | boolean | `true` | Force JPEG output |
|
||||
|
||||
#### PNG
|
||||
|
||||
```js
|
||||
.png([options])
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `progressive` | boolean | `false` | Progressive (interlace) |
|
||||
| `compressionLevel` | number | `6` | 0-9 |
|
||||
| `adaptiveFiltering` | boolean | `false` | Adaptive row filtering |
|
||||
| `palette` | boolean | `false` | Quantise to palette |
|
||||
| `quality` | number | `100` | Palette quality (1-100) |
|
||||
| `effort` | number | `7` | CPU effort (1-10, palette mode) |
|
||||
| `colours`/`colors` | number | `256` | Max palette colors (2-256) |
|
||||
| `dither` | number | `1.0` | Floyd-Steinberg dithering level |
|
||||
| `force` | boolean | `true` | Force PNG output |
|
||||
|
||||
#### WebP
|
||||
|
||||
```js
|
||||
.webp([options])
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `quality` | number | `80` | 1-100 |
|
||||
| `alphaQuality` | number | `100` | 0-100 |
|
||||
| `lossless` | boolean | `false` | Lossless compression |
|
||||
| `nearLossless` | boolean | `false` | Near-lossless mode |
|
||||
| `smartSubsample` | boolean | `false` | Smart chroma subsampling |
|
||||
| `preset` | string | `'default'` | `'default'`, `'photo'`, `'picture'`, `'drawing'`, `'icon'`, `'text'` |
|
||||
| `effort` | number | `4` | 0-6 |
|
||||
| `loop` | number | `0` | Animation loops (0 = infinite) |
|
||||
| `delay` | number \| Array | -- | Frame delay(s) in ms |
|
||||
| `force` | boolean | `true` | Force WebP output |
|
||||
|
||||
#### AVIF
|
||||
|
||||
```js
|
||||
.avif([options])
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `quality` | number | `50` | 1-100 |
|
||||
| `lossless` | boolean | `false` | Lossless mode |
|
||||
| `effort` | number | `4` | 0-9 |
|
||||
| `chromaSubsampling` | string | `'4:4:4'` | Chroma subsampling |
|
||||
| `bitdepth` | number | `8` | 8, 10, or 12 |
|
||||
|
||||
#### GIF
|
||||
|
||||
```js
|
||||
.gif([options])
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `reuse` | boolean | `true` | Reuse palette |
|
||||
| `progressive` | boolean | `false` | Progressive (interlace) |
|
||||
| `colours`/`colors` | number | `256` | 2-256 |
|
||||
| `effort` | number | `7` | 1-10 |
|
||||
| `dither` | number | `1.0` | 0-1 |
|
||||
| `loop` | number | `0` | 0 = infinite |
|
||||
| `delay` | number \| Array | -- | Frame delay(s) in ms |
|
||||
| `force` | boolean | `true` | Force GIF output |
|
||||
|
||||
#### TIFF
|
||||
|
||||
```js
|
||||
.tiff([options])
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `quality` | number | `80` | 1-100 |
|
||||
| `compression` | string | `'jpeg'` | `'none'`, `'jpeg'`, `'deflate'`, `'packbits'`, `'lzw'`, `'webp'`, `'zstd'`, `'jp2k'`, `'ccittfax4'` |
|
||||
| `predictor` | string | `'horizontal'` | `'none'`, `'horizontal'`, `'float'` |
|
||||
| `pyramid` | boolean | `false` | Write image pyramid |
|
||||
| `tile` | boolean | `false` | Tiled TIFF |
|
||||
| `tileWidth` | number | `256` | Tile width |
|
||||
| `tileHeight` | number | `256` | Tile height |
|
||||
| `bitdepth` | number | `8` | 1, 2, 4, or 8 |
|
||||
| `force` | boolean | `true` | Force TIFF output |
|
||||
|
||||
#### HEIF
|
||||
|
||||
```js
|
||||
.heif({ compression: 'hevc' })
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `compression` | string | required | `'av1'` or `'hevc'` |
|
||||
| `quality` | number | `50` | 1-100 |
|
||||
| `lossless` | boolean | `false` | Lossless mode |
|
||||
| `effort` | number | `4` | 0-9 |
|
||||
| `bitdepth` | number | `8` | 8, 10, or 12 |
|
||||
|
||||
#### Raw
|
||||
|
||||
```js
|
||||
.raw([options])
|
||||
```
|
||||
|
||||
- `options.depth` (string, default `'uchar'`): `'char'`, `'uchar'`, `'short'`, `'ushort'`, `'int'`, `'uint'`, `'float'`, `'double'`
|
||||
|
||||
#### Tile (DZI / Zoomify / IIIF)
|
||||
|
||||
```js
|
||||
.tile([options])
|
||||
```
|
||||
|
||||
| Option | Type | Default | Description |
|
||||
|--------|------|---------|-------------|
|
||||
| `size` | number | `256` | Tile size (1-8192) |
|
||||
| `overlap` | number | `0` | Tile overlap (0-8192) |
|
||||
| `layout` | string | `'dz'` | `'dz'`, `'iiif'`, `'iiif3'`, `'zoomify'`, `'google'` |
|
||||
| `container` | string | `'fs'` | `'fs'` or `'zip'` |
|
||||
| `angle` | number | `0` | Rotation (multiple of 90) |
|
||||
| `background` | string \| Object | white | Fill color |
|
||||
|
||||
---
|
||||
|
||||
## Metadata & Stats
|
||||
|
||||
### metadata()
|
||||
|
||||
```js
|
||||
const meta = await sharp('input.jpg').metadata();
|
||||
```
|
||||
|
||||
Returns without decoding pixels:
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `format` | string | `'jpeg'`, `'png'`, `'webp'`, `'gif'`, `'svg'`, etc. |
|
||||
| `width` | number | Pixel width |
|
||||
| `height` | number | Pixel height |
|
||||
| `space` | string | Color space (`'srgb'`, `'rgb'`, `'cmyk'`, `'b-w'`, etc.) |
|
||||
| `channels` | number | Band count |
|
||||
| `depth` | string | Pixel depth (`'uchar'`, `'ushort'`, `'float'`, etc.) |
|
||||
| `density` | number | DPI |
|
||||
| `chromaSubsampling` | string | e.g. `'4:2:0'` |
|
||||
| `isProgressive` | boolean | Progressive/interlaced |
|
||||
| `hasAlpha` | boolean | Has alpha channel |
|
||||
| `hasProfile` | boolean | Has ICC profile |
|
||||
| `orientation` | number | EXIF orientation (1-8) |
|
||||
| `pages` | number | Page count |
|
||||
| `size` | number | Total bytes (Buffer/Stream input) |
|
||||
| `exif` | Buffer | Raw EXIF |
|
||||
| `icc` | Buffer | ICC profile |
|
||||
| `xmp` | Buffer | XMP data |
|
||||
|
||||
### stats()
|
||||
|
||||
```js
|
||||
const stats = await sharp('input.jpg').stats();
|
||||
```
|
||||
|
||||
Returns pixel-derived statistics:
|
||||
|
||||
| Property | Type | Description |
|
||||
|----------|------|-------------|
|
||||
| `channels` | Array | Per-channel: `min`, `max`, `sum`, `mean`, `stdev`, `minX`, `minY`, `maxX`, `maxY` |
|
||||
| `isOpaque` | boolean | Fully opaque |
|
||||
| `entropy` | number | Greyscale entropy |
|
||||
| `sharpness` | number | Laplacian sharpness |
|
||||
| `dominant` | Object | Dominant sRGB color |
|
||||
|
||||
---
|
||||
|
||||
## Metadata Preservation
|
||||
|
||||
By default, sharp strips all metadata and converts to sRGB.
|
||||
|
||||
| Method | Description |
|
||||
|--------|-------------|
|
||||
| `.keepMetadata()` | Preserve all metadata (EXIF, ICC, XMP, IPTC) |
|
||||
| `.keepExif()` | Preserve EXIF only |
|
||||
| `.withExif(exif)` | Set EXIF (replaces input). Object keyed by IFD |
|
||||
| `.withExifMerge(exif)` | Merge with existing EXIF |
|
||||
| `.keepIccProfile()` | Preserve ICC profile |
|
||||
| `.withIccProfile(icc, [options])` | Set ICC: path or `'srgb'`, `'p3'`, `'cmyk'` |
|
||||
| `.keepXmp()` | Preserve XMP |
|
||||
| `.withXmp(xmp)` | Set XMP (XML string) |
|
||||
| `.withMetadata([options])` | Preserve most metadata. Options: `orientation`, `density` |
|
||||
|
||||
---
|
||||
|
||||
## Timeout
|
||||
|
||||
```js
|
||||
.timeout({ seconds: 30 })
|
||||
```
|
||||
|
||||
Abort processing after N seconds. `0` = no timeout (default).
|
||||
|
||||
---
|
||||
|
||||
## Utility (Static)
|
||||
|
||||
| Property/Method | Description |
|
||||
|-----------------|-------------|
|
||||
| `sharp.format` | Object with available input/output format booleans |
|
||||
| `sharp.versions` | Version info for sharp, libvips, dependencies |
|
||||
| `sharp.interpolators` | Enum: `nearest`, `bilinear`, `bicubic`, `lbb`, `nohalo`, `vsqbs` |
|
||||
| `sharp.cache([options])` | Get/set cache: `{ memory: 50, files: 20, items: 100 }` |
|
||||
| `sharp.concurrency([n])` | Get/set thread count (default: CPU cores) |
|
||||
| `sharp.counters()` | Returns `{ queue, process }` |
|
||||
| `sharp.simd([bool])` | Enable/disable SIMD (default `true`) |
|
||||
| `sharp.block({ operation })` | Block specific operations |
|
||||
| `sharp.unblock({ operation })` | Unblock operations |
|
||||
|
||||
---
|
||||
|
||||
## Common Recipes
|
||||
|
||||
### Resize and convert format
|
||||
|
||||
```js
|
||||
await sharp('input.png')
|
||||
.resize(800, 600)
|
||||
.webp({ quality: 80 })
|
||||
.toFile('output.webp');
|
||||
```
|
||||
|
||||
### Resize to fit within bounds (no upscale)
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.resize(1200, 800, { fit: 'inside', withoutEnlargement: true })
|
||||
.toFile('output.jpg');
|
||||
```
|
||||
|
||||
### Create thumbnail (cover crop)
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.resize(250, 250, { fit: 'cover', position: 'attention' })
|
||||
.toFile('thumb.jpg');
|
||||
```
|
||||
|
||||
### Crop region
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.extract({ left: 100, top: 50, width: 400, height: 300 })
|
||||
.toFile('cropped.jpg');
|
||||
```
|
||||
|
||||
### Add watermark overlay
|
||||
|
||||
```js
|
||||
await sharp('photo.jpg')
|
||||
.composite([{ input: 'watermark.png', gravity: 'southeast' }])
|
||||
.toFile('watermarked.jpg');
|
||||
```
|
||||
|
||||
### Composite text overlay
|
||||
|
||||
```js
|
||||
await sharp('photo.jpg')
|
||||
.composite([{
|
||||
input: { text: { text: 'Hello World', font: 'sans', dpi: 200, rgba: true } },
|
||||
gravity: 'south'
|
||||
}])
|
||||
.toFile('annotated.jpg');
|
||||
```
|
||||
|
||||
### Convert to greyscale
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.greyscale()
|
||||
.toFile('grey.jpg');
|
||||
```
|
||||
|
||||
### Blur
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.blur({ sigma: 5 })
|
||||
.toFile('blurred.jpg');
|
||||
```
|
||||
|
||||
### Rotate
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.rotate(90)
|
||||
.toFile('rotated.jpg');
|
||||
```
|
||||
|
||||
### Auto-orient from EXIF
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.autoOrient()
|
||||
.toFile('oriented.jpg');
|
||||
```
|
||||
|
||||
### Extend with padding
|
||||
|
||||
```js
|
||||
await sharp('input.png')
|
||||
.extend({ top: 20, bottom: 20, left: 20, right: 20, background: '#ffffff' })
|
||||
.toFile('padded.png');
|
||||
```
|
||||
|
||||
### Auto-trim whitespace
|
||||
|
||||
```js
|
||||
await sharp('input.png')
|
||||
.trim({ threshold: 10 })
|
||||
.toFile('trimmed.png');
|
||||
```
|
||||
|
||||
### Optimize JPEG for web
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.resize(1920, null, { withoutEnlargement: true })
|
||||
.jpeg({ quality: 75, mozjpeg: true, progressive: true })
|
||||
.toFile('optimized.jpg');
|
||||
```
|
||||
|
||||
### Generate AVIF from JPEG
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.avif({ quality: 50, effort: 4 })
|
||||
.toFile('output.avif');
|
||||
```
|
||||
|
||||
### Extract channel
|
||||
|
||||
```js
|
||||
await sharp('input.png')
|
||||
.extractChannel('red')
|
||||
.toFile('red-channel.png');
|
||||
```
|
||||
|
||||
### Get image metadata
|
||||
|
||||
```js
|
||||
const { width, height, format, space } = await sharp('input.jpg').metadata();
|
||||
```
|
||||
|
||||
### Buffer round-trip
|
||||
|
||||
```js
|
||||
const buffer = await sharp('input.jpg')
|
||||
.resize(300)
|
||||
.png()
|
||||
.toBuffer();
|
||||
```
|
||||
|
||||
### Create solid color image
|
||||
|
||||
```js
|
||||
await sharp({ create: { width: 100, height: 100, channels: 4, background: '#ff6600' } })
|
||||
.png()
|
||||
.toFile('orange.png');
|
||||
```
|
||||
|
||||
### Join images into grid
|
||||
|
||||
```js
|
||||
await sharp(['a.png', 'b.png', 'c.png', 'd.png'], { join: { across: 2 } })
|
||||
.toFile('grid.png');
|
||||
```
|
||||
|
||||
### Preserve metadata
|
||||
|
||||
```js
|
||||
await sharp('input.jpg')
|
||||
.resize(800)
|
||||
.keepMetadata()
|
||||
.toFile('output.jpg');
|
||||
```
|
||||
|
||||
### Animated GIF resize
|
||||
|
||||
```js
|
||||
await sharp('input.gif', { animated: true })
|
||||
.resize(200)
|
||||
.gif()
|
||||
.toFile('small.gif');
|
||||
```
|
||||
|
||||
### Multiple outputs from one input
|
||||
|
||||
```js
|
||||
const pipeline = sharp('input.jpg');
|
||||
await Promise.all([
|
||||
pipeline.clone().resize(200).toFile('thumb.jpg'),
|
||||
pipeline.clone().resize(800).toFile('medium.jpg'),
|
||||
pipeline.clone().resize(1600).toFile('large.jpg'),
|
||||
]);
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Source
|
||||
|
||||
- Repository: https://github.com/lovell/sharp
|
||||
- Documentation: https://sharp.pixelplumbing.com
|
||||
- API — Constructor: https://sharp.pixelplumbing.com/api-constructor
|
||||
- API — Input: https://sharp.pixelplumbing.com/api-input
|
||||
- API — Resize: https://sharp.pixelplumbing.com/api-resize
|
||||
- API — Operations: https://sharp.pixelplumbing.com/api-operation
|
||||
- API — Colour: https://sharp.pixelplumbing.com/api-colour
|
||||
- API — Channel: https://sharp.pixelplumbing.com/api-channel
|
||||
- API — Composite: https://sharp.pixelplumbing.com/api-composite
|
||||
- API — Output: https://sharp.pixelplumbing.com/api-output
|
||||
- API — Utility: https://sharp.pixelplumbing.com/api-utility
|
||||
Reference in New Issue
Block a user