Exposes sharp and ffprobe with their own vocabulary — operations are named what sharp names them, ffprobe fields come back spelled the way ffprobe spells them — so the tools' own documentation applies and there is no house dialect to learn. Safety comes from one architectural invariant rather than from filtering: the caller never supplies a path, a URL or a protocol. Input is an id we issued, output is a name we chose. That removes the entire class of attack that makes "just pass the flags through" a remote shell, which is precisely what makes it safe to open up everything else. docs/SECURITY.md has the reasoning and the specific attacks. The vocabulary is a data table, so the validator and docs/SHARP.md are generated from one source and cannot drift. Two things are deliberately absent from it: withMetadata, because that is how a client's GPS coordinates get published, and limitInputPixels, because a caller who could raise it could turn a 1 KB PNG into a 40 GB allocation. Verified against a running server, not asserted: traversal ids rejected, unknown operations and typo'd parameters rejected by name, out-of-range values rejected with the bound, a GPS-tagged photo coming out clean end to end, video probe, Range requests, and a rejected upload leaving nothing on disk. Found while building: config threw at import if AV_CLUB_TOKEN was unset, so generating documentation required a production secret. The token is read at boot in server.ts now — still a refusal to start, no longer a module-scope landmine. ffmpeg is designed in docs/API.md and not built yet. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
492 lines
13 KiB
Markdown
492 lines
13 KiB
Markdown
# sharp — the operation vocabulary
|
||
|
||
**Generated from `src/sharp/vocabulary.ts` by `scripts/gen-docs.ts`. Do not edit by hand —
|
||
run `bun run docs`.**
|
||
|
||
Every operation is named what sharp names it and takes sharp's own arguments, so
|
||
[sharp's documentation](https://sharp.pixelplumbing.com/api-operation) describes what each one
|
||
*does*. This page describes what av-club *accepts*: the bounds, which exist because an unbounded
|
||
number here is a denial of service rather than a picture.
|
||
|
||
Requests go to `POST /v1/sharp` — see [API.md](API.md) for the envelope.
|
||
|
||
```json
|
||
{
|
||
"input": "as_9f86d081884c7d659a2feaa0c55ad015",
|
||
"options": { "failOn": "warning" },
|
||
"pipeline": [
|
||
{ "rotate": {} },
|
||
{ "resize": { "width": 1200, "fit": "inside", "withoutEnlargement": true } }
|
||
],
|
||
"output": { "format": "avif", "options": { "quality": 55 } }
|
||
}
|
||
```
|
||
|
||
## Three things that catch people
|
||
|
||
**`rotate` with no angle applies the EXIF orientation.** Output is re-encoded and metadata is
|
||
dropped, so a photo that looked upright in a phone's gallery arrives sideways on the web unless you
|
||
include `{ "rotate": {} }`. This is the most commonly forgotten operation.
|
||
|
||
**`resize` enlarges by default.** A 300px source asked for 800px comes back 800px and soft. Pass
|
||
`withoutEnlargement: true` unless you actually want that.
|
||
|
||
**Metadata is always stripped and there is no way to keep it.** `withMetadata` is deliberately not
|
||
in this vocabulary — it is how a client's GPS coordinates end up published. Dimensions come back in
|
||
the response instead.
|
||
|
||
## Input options
|
||
|
||
sharp's constructor options, passed as `options`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `failOn` | `none` · `truncated` · `error` · `warning`. How strict to be about a damaged file. sharp's default is 'warning'. |
|
||
| `density` | number, 1–2400. DPI for vector input. |
|
||
| `pages` | integer, -1–1000. Pages to read from a multi-page input. -1 for all. |
|
||
| `page` | integer, 0–100000. First page to read. |
|
||
| `animated` | boolean. Read all frames of an animated GIF/WebP. Equivalent to pages: -1. |
|
||
| `ignoreIcc` | boolean. Ignore any embedded ICC profile. |
|
||
| `autoOrient` | boolean. Apply EXIF orientation on load. See the note about rotate() in docs/SHARP.md. |
|
||
| `sequentialRead` | boolean |
|
||
| `level` | integer, 0–256. Level to extract from a multi-level input. |
|
||
| `subifd` | integer, -1–100000. Subldeaf IFD to extract from an OME-TIFF. |
|
||
|
||
`limitInputPixels` is **not** accepted: it is the decompression-bomb guard and is set by the
|
||
server. A 1 KB PNG can expand to tens of gigabytes.
|
||
|
||
## Operations
|
||
|
||
32 operations, run in the order given.
|
||
|
||
### `resize`
|
||
|
||
Resize to given dimensions.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `width` | integer, 1–16383 |
|
||
| `height` | integer, 1–16383 |
|
||
| `fit` | `cover` · `contain` · `fill` · `inside` · `outside`. How the image fits the box. Default 'cover'. |
|
||
| `position` | `centre` · `center` · `top` · `right top` · `right` · `right bottom` · `bottom` · `left bottom` · `left` · `left top` · `north` · `northeast` · `east` · `southeast` · `south` · `southwest` · `west` · `northwest` · `entropy` · `attention`. Which part survives when fit is 'cover'. 'attention' picks the busiest region. |
|
||
| `background` | colour — a CSS string like `#ffffff`, or `{r, g, b, alpha}`. Fill colour when fit is 'contain'. |
|
||
| `kernel` | `nearest` · `linear` · `cubic` · `mitchell` · `lanczos2` · `lanczos3` |
|
||
| `withoutEnlargement` | boolean. Never scale UP. Almost always what you want — see docs/SHARP.md. |
|
||
| `withoutReduction` | boolean. Never scale DOWN. |
|
||
| `fastShrinkOnLoad` | boolean |
|
||
|
||
### `extend`
|
||
|
||
Add pixels to the edges.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `top` | integer, 0–16383 |
|
||
| `bottom` | integer, 0–16383 |
|
||
| `left` | integer, 0–16383 |
|
||
| `right` | integer, 0–16383 |
|
||
| `extendWith` | `background` · `copy` · `repeat` · `mirror` |
|
||
| `background` | colour — a CSS string like `#ffffff`, or `{r, g, b, alpha}` |
|
||
|
||
### `extract`
|
||
|
||
Crop to a region.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `left` | integer, 0–16383 |
|
||
| `top` | integer, 0–16383 |
|
||
| `width` | integer, 1–16383 |
|
||
| `height` | integer, 1–16383 |
|
||
|
||
### `trim`
|
||
|
||
Trim uniform borders.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `background` | colour — a CSS string like `#ffffff`, or `{r, g, b, alpha}` |
|
||
| `threshold` | number, 0–255 |
|
||
| `lineArt` | boolean |
|
||
|
||
### `rotate`
|
||
|
||
Rotate. With no angle, applies the EXIF orientation — see docs/SHARP.md.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `angle` | number, -3600–3600. Multiples of 90 are lossless; anything else needs a background. |
|
||
| `background` | colour — a CSS string like `#ffffff`, or `{r, g, b, alpha}` |
|
||
|
||
### `flip`
|
||
|
||
Mirror vertically.
|
||
|
||
Takes `flip` directly — `{ "flip": { "flip": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `flip` | boolean |
|
||
|
||
### `flop`
|
||
|
||
Mirror horizontally.
|
||
|
||
Takes `flop` directly — `{ "flop": { "flop": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `flop` | boolean |
|
||
|
||
### `sharpen`
|
||
|
||
Sharpen.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `sigma` | number, 0.000001–10 |
|
||
| `m1` | number, 0–1000000 |
|
||
| `m2` | number, 0–1000000 |
|
||
| `x1` | number, 0–1000000 |
|
||
| `y2` | number, 0–1000000 |
|
||
| `y3` | number, 0–1000000 |
|
||
|
||
### `blur`
|
||
|
||
Gaussian blur.
|
||
|
||
Takes `sigma` directly — `{ "blur": { "sigma": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `sigma` | number, 0.3–1000 |
|
||
|
||
### `median`
|
||
|
||
Median filter — good for noise.
|
||
|
||
Takes `size` directly — `{ "median": { "size": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `size` | integer, 1–1000 |
|
||
|
||
### `dilate`
|
||
|
||
Morphological dilate.
|
||
|
||
Takes `width` directly — `{ "dilate": { "width": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `width` | integer, 1–1000 |
|
||
|
||
### `erode`
|
||
|
||
Morphological erode.
|
||
|
||
Takes `width` directly — `{ "erode": { "width": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `width` | integer, 1–1000 |
|
||
|
||
### `flatten`
|
||
|
||
Composite transparency onto a background.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `background` | colour — a CSS string like `#ffffff`, or `{r, g, b, alpha}` |
|
||
|
||
### `unflatten`
|
||
|
||
Make pure white pixels transparent.
|
||
|
||
_Takes no options._
|
||
|
||
### `gamma`
|
||
|
||
Apply gamma correction.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `gamma` | number, 1–3 |
|
||
| `gammaOut` | number, 1–3 |
|
||
|
||
### `negate`
|
||
|
||
Invert.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `alpha` | boolean. Also invert the alpha channel. |
|
||
|
||
### `normalise`
|
||
|
||
Stretch the histogram to full range.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `lower` | number, 0–99 |
|
||
| `upper` | number, 1–100 |
|
||
|
||
### `clahe`
|
||
|
||
Contrast-limited adaptive histogram equalisation.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `width` | integer, 1–16383 |
|
||
| `height` | integer, 1–16383 |
|
||
| `maxSlope` | integer, 0–100 |
|
||
|
||
### `convolve`
|
||
|
||
Apply a convolution kernel.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `width` | integer, 1–100 |
|
||
| `height` | integer, 1–100 |
|
||
| `kernel` | array of 1–10000 numbers, each -1000–1000 |
|
||
| `scale` | number, -10000–10000 |
|
||
| `offset` | number, -10000–10000 |
|
||
|
||
### `threshold`
|
||
|
||
Reduce to black and white at a cutoff.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `threshold` | integer, 0–255 |
|
||
| `greyscale` | boolean |
|
||
|
||
### `linear`
|
||
|
||
Multiply and add: out = in * a + b.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `a` | array of 1–4 numbers, each -1000–1000 |
|
||
| `b` | array of 1–4 numbers, each -1000–1000 |
|
||
|
||
### `recomb`
|
||
|
||
Recombine channels with a 3x3 matrix.
|
||
|
||
Takes `matrix` directly — `{ "recomb": { "matrix": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `matrix` | array of 9 numbers, each -100–100 |
|
||
|
||
### `modulate`
|
||
|
||
Adjust brightness, saturation, hue and lightness.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `brightness` | number, 0–100 |
|
||
| `saturation` | number, 0–100 |
|
||
| `hue` | number, -3600–3600. Degrees. |
|
||
| `lightness` | number, -100–100 |
|
||
|
||
### `tint`
|
||
|
||
Tint with a colour.
|
||
|
||
Takes `color` directly — `{ "tint": { "color": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `color` | colour — a CSS string like `#ffffff`, or `{r, g, b, alpha}` |
|
||
|
||
### `greyscale`
|
||
|
||
Convert to greyscale.
|
||
|
||
Takes `greyscale` directly — `{ "greyscale": { "greyscale": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `greyscale` | boolean |
|
||
|
||
### `toColourspace`
|
||
|
||
Convert to a colourspace.
|
||
|
||
Takes `colourspace` directly — `{ "toColourspace": { "colourspace": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `colourspace` | `srgb` · `rgb` · `cmyk` · `lab` · `b-w` · `hsv` · `scrgb` · `lch` · `grey16` · `rgb16` |
|
||
|
||
### `pipelineColourspace`
|
||
|
||
Set the colourspace operations are performed in.
|
||
|
||
Takes `colourspace` directly — `{ "pipelineColourspace": { "colourspace": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `colourspace` | `srgb` · `rgb` · `cmyk` · `lab` · `b-w` · `hsv` · `scrgb` · `lch` · `grey16` · `rgb16` |
|
||
|
||
### `removeAlpha`
|
||
|
||
Drop the alpha channel.
|
||
|
||
_Takes no options._
|
||
|
||
### `ensureAlpha`
|
||
|
||
Add an alpha channel if absent.
|
||
|
||
Takes `alpha` directly — `{ "ensureAlpha": { "alpha": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `alpha` | number, 0–1 |
|
||
|
||
### `extractChannel`
|
||
|
||
Keep one channel.
|
||
|
||
Takes `channel` directly — `{ "extractChannel": { "channel": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `channel` | `red` · `green` · `blue` · `alpha` · `0` · `1` · `2` · `3` |
|
||
|
||
### `bandbool`
|
||
|
||
Boolean-combine all channels into one.
|
||
|
||
Takes `operator` directly — `{ "bandbool": { "operator": … } }`.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `operator` | `and` · `or` · `eor` |
|
||
|
||
### `composite`
|
||
|
||
Overlay another asset. `input` is an asset id, never a path.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `input` | **asset id** (never a path). The asset to overlay. Must already be uploaded. |
|
||
| `blend` | `clear` · `source` · `over` · `in` · `out` · `atop` · `dest` · `dest-over` · `dest-in` · `dest-out` · `dest-atop` · `xor` · `add` · `saturate` · `multiply` · `screen` · `overlay` · `darken` · `lighten` · `colour-dodge` · `color-dodge` · `colour-burn` · `color-burn` · `hard-light` · `soft-light` · `difference` · `exclusion` |
|
||
| `gravity` | `centre` · `center` · `north` · `northeast` · `east` · `southeast` · `south` · `southwest` · `west` · `northwest` |
|
||
| `top` | integer, 0–16383 |
|
||
| `left` | integer, 0–16383 |
|
||
| `tile` | boolean |
|
||
| `premultiplied` | boolean |
|
||
|
||
## Output formats
|
||
|
||
Given as `output.format`, with `output.options` carrying the encoder settings. Defaults to `webp`.
|
||
|
||
### `jpeg`
|
||
|
||
JPEG.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `quality` | integer, 1–100 |
|
||
| `progressive` | boolean |
|
||
| `chromaSubsampling` | `4:4:4` · `4:2:2` · `4:2:0` |
|
||
| `optimiseCoding` | boolean |
|
||
| `mozjpeg` | boolean. Turns on a bundle of mozjpeg settings at once. |
|
||
| `trellisQuantisation` | boolean |
|
||
| `overshootDeringing` | boolean |
|
||
| `optimiseScans` | boolean |
|
||
|
||
### `png`
|
||
|
||
PNG.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `progressive` | boolean |
|
||
| `compressionLevel` | integer, 0–9 |
|
||
| `adaptiveFiltering` | boolean |
|
||
| `palette` | boolean. Quantise to a palette — much smaller for flat graphics. |
|
||
| `quality` | integer, 0–100 |
|
||
| `effort` | integer, 1–10 |
|
||
| `colours` | integer, 2–256 |
|
||
| `dither` | number, 0–1 |
|
||
|
||
### `webp`
|
||
|
||
WebP.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `quality` | integer, 1–100 |
|
||
| `alphaQuality` | integer, 0–100 |
|
||
| `lossless` | boolean |
|
||
| `nearLossless` | boolean |
|
||
| `smartSubsample` | boolean |
|
||
| `preset` | `default` · `photo` · `picture` · `drawing` · `icon` · `text` |
|
||
| `effort` | integer, 0–6 |
|
||
| `loop` | integer, 0–100000 |
|
||
| `minSize` | boolean |
|
||
| `mixed` | boolean |
|
||
|
||
### `avif`
|
||
|
||
AVIF. Smaller than WebP at the same quality, slower to encode.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `quality` | integer, 1–100 |
|
||
| `lossless` | boolean |
|
||
| `effort` | integer, 0–9. Higher is smaller and much slower. |
|
||
| `chromaSubsampling` | `4:4:4` · `4:2:0` |
|
||
| `bitdepth` | `8` · `10` · `12` |
|
||
|
||
### `tiff`
|
||
|
||
TIFF.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `quality` | integer, 1–100 |
|
||
| `compression` | `none` · `jpeg` · `deflate` · `packbits` · `ccittfax4` · `lzw` · `webp` · `zstd` · `jp2k` |
|
||
| `predictor` | `none` · `horizontal` · `float` |
|
||
| `pyramid` | boolean |
|
||
| `tile` | boolean |
|
||
| `tileWidth` | integer, 1–16383 |
|
||
| `tileHeight` | integer, 1–16383 |
|
||
| `xres` | number, 0.01–100000 |
|
||
| `yres` | number, 0.01–100000 |
|
||
| `resolutionUnit` | `inch` · `cm` |
|
||
| `bitdepth` | `1` · `2` · `4` · `8` |
|
||
|
||
### `gif`
|
||
|
||
GIF.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `reuse` | boolean |
|
||
| `progressive` | boolean |
|
||
| `colours` | integer, 2–256 |
|
||
| `effort` | integer, 1–10 |
|
||
| `dither` | number, 0–1 |
|
||
| `interFrameMaxError` | number, 0–32 |
|
||
| `interPaletteMaxError` | number, 0–256 |
|
||
| `loop` | integer, 0–100000 |
|
||
|
||
### `jp2`
|
||
|
||
JPEG 2000.
|
||
|
||
| Parameter | Accepts |
|
||
|---|---|
|
||
| `quality` | integer, 1–100 |
|
||
| `lossless` | boolean |
|
||
| `tileWidth` | integer, 1–16383 |
|
||
| `tileHeight` | integer, 1–16383 |
|
||
| `chromaSubsampling` | `4:4:4` · `4:2:2` · `4:2:0` |
|