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>
13 KiB
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 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 for the envelope.
{
"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 |