Files
platform/seed/skills/sharp/chat/messages.json
T
2026-02-16 19:34:35 +00:00

1 line
155 KiB
JSON
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
[{"role":"user","text":"Help me create the content for this new skill file: /home/pastilhas/projects/officer.dev/data/skills/sharp/SKILL.md\nuse https://github.com/lovell/sharp"},{"role":"assistant","text":"\n\nLet me start by reading the existing SKILL.md file and another skill's SKILL.md for reference on the format, plus fetch info about the sharp library."},{"role":"tool","toolName":"Read","toolInput":{"file_path":"/home/pastilhas/projects/officer.dev/data/skills/sharp/SKILL.md"},"toolUseId":"toolu_01UhVV2srmHDMuj76w8P8neh","output":" 1→---\n 2→name: sharp\n 3→description: \n 4→---\n 5→","isError":false},{"role":"tool","toolName":"Read","toolInput":{"file_path":"/home/pastilhas/projects/officer.dev/data/skills/ffmpeg/SKILL.md"},"toolUseId":"toolu_01UCCqYAfpLfDjgGGJywEtBr","output":" 1→---\n 2→name: ffmpeg\n 3→description: Process audio and video files using ffmpeg/ffprobe. Use when the user wants to convert, transcode, trim, merge, extract, resize, compress, or analyze multimedia files.\n 4→---\n 5→\n 6→# FFmpeg\n 7→\n 8→CLI reference for FFmpeg v8.x — a complete, cross-platform solution for recording, converting, and streaming audio and video.\n 9→\n 10→Official docs: https://www.ffmpeg.org/documentation.html\n 11→\n 12→## Tools\n 13→\n 14→| Tool | Purpose |\n 15→|------|---------|\n 16→| `ffmpeg` | Transcode, convert, filter, mux/demux multimedia |\n 17→| `ffprobe` | Analyze and inspect multimedia streams |\n 18→| `ffplay` | Play multimedia files (interactive) |\n 19→\n 20→---\n 21→\n 22→## ffmpeg\n 23→\n 24→### Synopsis\n 25→\n 26→```\n 27→ffmpeg [global_options] {[input_options] -i input_url} ... {[output_options] output_url} ...\n 28→```\n 29→\n 30→Options before `-i` apply to the input; options before the output URL apply to the output.\n 31→\n 32→### Global Options\n 33→\n 34→| Flag | Description |\n 35→|------|-------------|\n 36→| `-y` | Overwrite output files without asking |\n 37→| `-n` | Do not overwrite; exit if output exists |\n 38→| `-hide_banner` | Suppress copyright/build info banner |\n 39→| `-loglevel level` | Set log level: `quiet`, `error`, `warning`, `info` (default), `verbose`, `debug` |\n 40→| `-stats` | Print encoding progress/statistics |\n 41→| `-progress url` | Send machine-readable progress to url |\n 42→| `-report` | Dump full command line and log to a file |\n 43→| `-filter_threads n` | Number of threads for filter processing |\n 44→\n 45→### Input/Output Options\n 46→\n 47→| Flag | Description |\n 48→|------|-------------|\n 49→| `-i url` | Input file URL |\n 50→| `-f fmt` | Force input or output format |\n 51→| `-c[:stream] codec` | Select encoder/decoder; use `copy` for stream copying |\n 52→| `-t duration` | Limit duration (as input: read limit; as output: write limit) |\n 53→| `-to position` | Stop at position (timestamp) |\n 54→| `-ss position` | Seek to position (before `-i`: fast input seek; after: output seek) |\n 55→| `-sseof position` | Seek relative to end of file |\n 56→| `-itsoffset offset` | Set input time offset |\n 57→| `-itsscale scale` | Rescale input timestamps |\n 58→| `-metadata key=value` | Set metadata key/value pair |\n 59→| `-disposition value` | Set stream disposition flags |\n 60→| `-target type` | Specify target type: `vcd`, `svcd`, `dvd`, `dv`, `dv50` |\n 61→| `-stream_loop n` | Loop input stream n times (-1 = infinite) |\n 62→| `-frames[:stream] n` | Stop after n frames |\n 63→| `-fs limit` | Set file size limit in bytes |\n 64→| `-timestamp date` | Set recording timestamp |\n 65→\n 66→### Video Options\n 67→\n 68→| Flag | Description |\n 69→|------|-------------|\n 70→| `-vn` | Disable video |\n 71→| `-vcodec codec` | Set video codec (alias for `-c:v`) |\n 72→| `-r fps` | Set frame rate |\n 73→| `-fpsmax fps` | Set maximum frame rate |\n 74→| `-s WxH` | Set frame size |\n 75→| `-aspect ratio` | Set display aspect ratio (e.g. `16:9`) |\n 76→| `-pix_fmt format` | Set pixel format |\n 77→| `-vf filtergraph` | Apply video filter graph (alias for `-filter:v`) |\n 78→| `-pass n` | Two-pass encoding pass (1 or 2) |\n 79→| `-passlogfile prefix` | Two-pass log file prefix |\n 80→| `-vframes n` | Set number of video frames to output |\n 81→| `-autorotate` | Auto-rotate based on metadata (default on) |\n 82→| `-display_rotation angle` | Set video rotation metadata |\n 83→| `-display_hflip` | Horizontal flip metadata |\n 84→| `-display_vflip` | Vertical flip metadata |\n 85→| `-force_key_frames expr` | Force keyframes at specified times/expression |\n 86→| `-copyinkf` | Copy non-key frames at the beginning during stream copy |\n 87→\n 88→### Audio Options\n 89→\n 90→| Flag | Description |\n 91→|------|-------------|\n 92→| `-an` | Disable audio |\n 93→| `-acodec codec` | Set audio codec (alias for `-c:a`) |\n 94→| `-ar freq` | Set audio sample rate (Hz) |\n 95→| `-ac channels` | Set number of audio channels |\n 96→| `-af filtergraph` | Apply audio filter graph (alias for `-filter:a`) |\n 97→| `-sample_fmt fmt` | Set audio sample format |\n 98→| `-channel_layout layout` | Set audio channel layout |\n 99→| `-aq q` | Set audio quality (codec-specific VBR) |\n 100→| `-aframes n` | Set number of audio frames to output |\n 101→\n 102→### Subtitle Options\n 103→\n 104→| Flag | Description |\n 105→|------|-------------|\n 106→| `-sn` | Disable subtitles |\n 107→| `-scodec codec` | Set subtitle codec (alias for `-c:s`) |\n 108→| `-fix_sub_duration` | Fix subtitle durations to avoid overlap |\n 109→\n 110→### Stream Selection\n 111→\n 112→| Flag | Description |\n 113→|------|-------------|\n 114→| `-map input:stream` | Manually select streams for output |\n 115→| `-dn` | Disable data streams |\n 116→\n 117→Stream specifiers: `v` (video), `V` (video, no images), `a` (audio), `s` (subtitle), `d` (data). Index with `:N` (e.g. `a:0` = first audio).\n 118→\n 119→### Hardware Acceleration\n 120→\n 121→| Flag | Description |\n 122→|------|-------------|\n 123→| `-hwaccel method` | HW accel method: `cuda`, `vaapi`, `qsv`, `vulkan`, `auto` |\n 124→| `-hwaccel_device device` | Select HW device |\n 125→| `-init_hw_device type=name` | Initialize HW device |\n 126→\n 127→---\n 128→\n 129→## ffprobe\n 130→\n 131→### Synopsis\n 132→\n 133→```\n 134→ffprobe [options] input_url\n 135→```\n 136→\n 137→### Main Options\n 138→\n 139→| Flag | Description |\n 140→|------|-------------|\n 141→| `-show_format` | Show container format info |\n 142→| `-show_streams` | Show per-stream info |\n 143→| `-show_packets` | Show per-packet info |\n 144→| `-show_frames` | Show per-frame info |\n 145→| `-show_chapters` | Show chapter info |\n 146→| `-show_programs` | Show program info |\n 147→| `-show_entries section=key1,key2` | Show only specific fields |\n 148→| `-show_error` | Show probe errors |\n 149→| `-select_streams specifier` | Filter to specific streams (e.g. `v:0`, `a`) |\n 150→| `-count_frames` | Count frames per stream |\n 151→| `-count_packets` | Count packets per stream |\n 152→| `-read_intervals intervals` | Analyze specific time ranges |\n 153→\n 154→### Output Formats\n 155→\n 156→Set with `-output_format` (or `-of`, `-print_format`):\n 157→\n 158→| Format | Description |\n 159→|--------|-------------|\n 160→| `default` | `[SECTION] key=value [/SECTION]` |\n 161→| `json` | JSON output (most useful for parsing) |\n 162→| `xml` | XML output |\n 163→| `csv` | Comma-separated values |\n 164→| `flat` | Flat `key=value` per line |\n 165→| `ini` | INI-style sections |\n 166→\n 167→### Display Options\n 168→\n 169→| Flag | Description |\n 170→|------|-------------|\n 171→| `-pretty` | Human-readable units and time formatting |\n 172→| `-unit` | Show value units |\n 173→| `-sexagesimal` | Format times as HH:MM:SS.us |\n 174→| `-hide_banner` | Suppress copyright/build info |\n 175→| `-o output_url` | Write output to file instead of stdout |\n 176→\n 177→---\n 178→\n 179→## Common Codecs\n 180→\n 181→### Video Encoders\n 182→\n 183→#### libx264 (H.264)\n 184→\n 185→| Option | Description |\n 186→|--------|-------------|\n 187→| `-preset` | Speed/quality: `ultrafast`, `superfast`, `veryfast`, `faster`, `fast`, `medium` (default), `slow`, `slower`, `veryslow` |\n 188→| `-crf` | Constant quality: 0 (lossless) to 51 (worst). 18-23 is typical |\n 189→| `-profile:v` | `baseline`, `main`, `high` |\n 190→| `-tune` | `film`, `animation`, `grain`, `stillimage`, `fastdecode`, `zerolatency` |\n 191→| `-b:v` | Target bitrate (e.g. `2M`) |\n 192→\n 193→#### libx265 (H.265/HEVC)\n 194→\n 195→| Option | Description |\n 196→|--------|-------------|\n 197→| `-preset` | Same presets as x264 |\n 198→| `-crf` | 0-51, default 28. Similar quality to x264 at lower bitrate |\n 199→| `-profile:v` | `main`, `main10`, `main12` |\n 200→| `-b:v` | Target bitrate |\n 201→\n 202→#### libvpx-vp9 (VP9)\n 203→\n 204→| Option | Description |\n 205→|--------|-------------|\n 206→| `-crf` | 0-63. 31 is a good default |\n 207→| `-b:v` | Target bitrate (set to `0` for pure CRF mode) |\n 208→| `-cpu-used` | Speed: 0 (slowest/best) to 8 (fastest) |\n 209→| `-deadline` | `best`, `good` (default), `realtime` |\n 210→| `-row-mt 1` | Enable row-based multithreading |\n 211→\n 212→#### libsvtav1 (SVT-AV1)\n 213→\n 214→| Option | Description |\n 215→|--------|-------------|\n 216→| `-crf` | 0-63. 30 is a good default |\n 217→| `-preset` | 0 (slowest/best) to 13 (fastest). 8 is a good default |\n 218→| `-b:v` | Target bitrate |\n 219→\n 220→#### libaom-av1 (AOM AV1)\n 221→\n 222→| Option | Description |\n 223→|--------|-------------|\n 224→| `-crf` | 0-63 |\n 225→| `-cpu-used` | 0 (best) to 8 (fastest) |\n 226→| `-b:v` | Target bitrate (set to `0` for pure CRF mode) |\n 227→| `-tiles` | Tile columns x rows for parallelism |\n 228→\n 229→### Audio Encoders\n 230→\n 231→#### aac (Native AAC)\n 232→\n 233→| Option | Description |\n 234→|--------|-------------|\n 235→| `-b:a` | Bitrate: `128k`, `192k`, `256k` |\n 236→| `-profile:a` | `aac_low` (default), `aac_he`, `aac_he_v2` |\n 237→\n 238→#### libmp3lame (MP3)\n 239→\n 240→| Option | Description |\n 241→|--------|-------------|\n 242→| `-b:a` | CBR bitrate: `128k`, `192k`, `320k` |\n 243→| `-q:a` | VBR quality: 0 (best) to 9 (worst). 2 is a good default |\n 244→\n 245→#### libopus (Opus)\n 246→\n 247→| Option | Description |\n 248→|--------|-------------|\n 249→| `-b:a` | Bitrate: `64k` to `256k`. 128k is a good default |\n 250→| `-vbr` | `on` (default), `off`, `constrained` |\n 251→| `-application` | `audio` (default), `voip`, `lowdelay` |\n 252→\n 253→#### libvorbis (Vorbis)\n 254→\n 255→| Option | Description |\n 256→|--------|-------------|\n 257→| `-q:a` | VBR quality: -1 to 10. 5 is a good default |\n 258→| `-b:a` | ABR bitrate |\n 259→\n 260→#### flac (FLAC)\n 261→\n 262→| Option | Description |\n 263→|--------|-------------|\n 264→| `-compression_level` | 0 (fast) to 12 (best). 5 is default |\n 265→\n 266→---\n 267→\n 268→## Common Container Formats\n 269→\n 270→| Format | Extensions | Notes |\n 271→|--------|-----------|-------|\n 272→| `mp4` | .mp4, .m4a, .m4v | Use `-movflags +faststart` for web streaming |\n 273→| `matroska` | .mkv | Supports virtually all codecs |\n 274→| `webm` | .webm | VP8/VP9/AV1 + Vorbis/Opus for web |\n 275→| `avi` | .avi | Legacy; limited codec support |\n 276→| `mpegts` | .ts | Broadcast transport stream |\n 277→| `ogg` | .ogg, .ogv | Vorbis/Opus/Theora container |\n 278→| `wav` | .wav | Uncompressed PCM audio |\n 279→| `flac` | .flac | Lossless audio |\n 280→| `mp3` | .mp3 | MPEG audio layer 3 |\n 281→| `hls` | .m3u8 | HTTP Live Streaming |\n 282→| `dash` | .mpd | DASH adaptive streaming |\n 283→| `gif` | .gif | Animated GIF |\n 284→| `image2` | various | Image sequence input/output |\n 285→| `concat` | text file | Concatenation demuxer (file list) |\n 286→| `null` | — | Discard output (benchmarking) |\n 287→\n 288→---\n 289→\n 290→## Common Video Filters (`-vf`)\n 291→\n 292→| Filter | Description | Example |\n 293→|--------|-------------|---------|\n 294→| `scale=W:H` | Resize video. Use `-1` or `-2` to auto-calculate | `scale=1280:720`, `scale=-2:480` |\n 295→| `crop=W:H:X:Y` | Crop to WxH starting at X,Y | `crop=640:480:100:50` |\n 296→| `pad=W:H:X:Y:color` | Pad video with borders | `pad=1920:1080:(ow-iw)/2:(oh-ih)/2:black` |\n 297→| `overlay=X:Y` | Composite second input over first | `overlay=10:10` |\n 298→| `transpose=N` | Rotate: 0=90ccw+vflip, 1=90cw, 2=90ccw, 3=90cw+vflip | `transpose=1` |\n 299→| `hflip` / `vflip` | Horizontal / vertical flip | `hflip` |\n 300→| `rotate=angle` | Rotate by arbitrary angle (radians) | `rotate=PI/4` |\n 301→| `fps=N` | Change frame rate | `fps=30` |\n 302→| `setpts=expr` | Modify presentation timestamps | `setpts=0.5*PTS` (2x speed) |\n 303→| `trim=start:end` | Extract time range | `trim=start=10:end=20` |\n 304→| `drawtext=opts` | Overlay text | `drawtext=text='Hello':fontsize=24:x=10:y=10` |\n 305→| `fade=t=type:st=S:d=D` | Fade in/out | `fade=t=in:st=0:d=2` |\n 306→| `eq=opts` | Adjust brightness/contrast/saturation | `eq=brightness=0.1:contrast=1.2` |\n 307→| `format=pix_fmt` | Convert pixel format | `format=yuv420p` |\n 308→| `concat=n:v:a` | Concatenate segments | `concat=n=2:v=1:a=1` |\n 309→| `split` / `select` | Duplicate / select frames | `select='eq(pict_type,I)'` |\n 310→| `deinterlace` / `yadif` | Remove interlacing | `yadif=1` |\n 311→| `boxblur=R` | Apply box blur | `boxblur=5:1` |\n 312→| `subtitles=file` | Burn in subtitles from file | `subtitles=subs.srt` |\n 313→| `palettegen` / `paletteuse` | Generate/apply palette for GIF | Used in two-pass GIF creation |\n 314→| `colorchannelmixer` | Mix color channels | `colorchannelmixer=.3:.4:.3:0:.3:.4:.3:0:.3:.4:.3` (grayscale) |\n 315→\n 316→## Common Audio Filters (`-af`)\n 317→\n 318→| Filter | Description | Example |\n 319→|--------|-------------|---------|\n 320→| `volume=V` | Adjust volume | `volume=1.5`, `volume=-3dB` |\n 321→| `loudnorm` | EBU R128 loudness normalization | `loudnorm=I=-16:TP=-1.5:LRA=11` |\n 322→| `atempo=T` | Change tempo (0.5-100.0) | `atempo=2.0` (2x speed) |\n 323→| `aresample=rate` | Resample audio | `aresample=44100` |\n 324→| `amerge` | Merge audio channels | `amerge=inputs=2` |\n 325→| `afade=t=type:st=S:d=D` | Audio fade in/out | `afade=t=in:st=0:d=3` |\n 326→| `highpass=f=freq` | High-pass filter | `highpass=f=200` |\n 327→| `lowpass=f=freq` | Low-pass filter | `lowpass=f=3000` |\n 328→| `equalizer=f:t:w:g` | Parametric EQ | `equalizer=f=1000:t=q:w=1:g=5` |\n 329→| `acompressor` | Dynamic range compression | `acompressor=threshold=-20dB:ratio=4` |\n 330→| `silenceremove` | Remove silence | `silenceremove=1:0:-50dB` |\n 331→| `silencedetect` | Detect silence | `silencedetect=n=-30dB:d=2` |\n 332→| `adelay=delays` | Delay audio channels | `adelay=1000\\|1000` (ms) |\n 333→| `aecho=id:ig:delays:decays` | Add echo effect | `aecho=0.8:0.88:60:0.4` |\n 334→| `pan=layout:gains` | Remix channels | `pan=mono\\|c0=0.5*c0+0.5*c1` |\n 335→\n 336→---\n 337→\n 338→## Common Recipes\n 339→\n 340→### Convert format\n 341→\n 342→```bash\n 343→ffmpeg -i input.mkv output.mp4\n 344→```\n 345→\n 346→### Transcode with CRF quality\n 347→\n 348→```bash\n 349→ffmpeg -i input.mp4 -c:v libx264 -crf 20 -c:a aac -b:a 192k output.mp4\n 350→```\n 351→\n 352→### Extract audio\n 353→\n 354→```bash\n 355→ffmpeg -i video.mp4 -vn -c:a copy audio.m4a\n 356→```\n 357→\n 358→### Extract video (no audio)\n 359→\n 360→```bash\n 361→ffmpeg -i input.mp4 -an -c:v copy output.mp4\n 362→```\n 363→\n 364→### Trim / cut\n 365→\n 366→```bash\n 367→ffmpeg -ss 00:01:30 -to 00:03:00 -i input.mp4 -c copy output.mp4\n 368→```\n 369→\n 370→### Resize video\n 371→\n 372→```bash\n 373→ffmpeg -i input.mp4 -vf \"scale=1280:720\" -c:a copy output.mp4\n 374→```\n 375→\n 376→### Compress video (lower quality)\n 377→\n 378→```bash\n 379→ffmpeg -i input.mp4 -c:v libx264 -crf 28 -preset fast -c:a aac -b:a 128k output.mp4\n 380→```\n 381→\n 382→### Two-pass encoding\n 383→\n 384→```bash\n 385→ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 1 -f null /dev/null\n 386→ffmpeg -i input.mp4 -c:v libx264 -b:v 2M -pass 2 output.mp4\n 387→```\n 388→\n 389→### Concatenate files (concat demuxer)\n 390→\n 391→```bash\n 392→# files.txt contains:\n 393→# file 'part1.mp4'\n 394→# file 'part2.mp4'\n 395→ffmpeg -f concat -safe 0 -i files.txt -c copy output.mp4\n 396→```\n 397→\n 398→### Add subtitles (burn-in)\n 399→\n 400→```bash\n 401→ffmpeg -i input.mp4 -vf \"subtitles=subs.srt\" output.mp4\n 402→```\n 403→\n 404→### Create GIF\n 405→\n 406→```bash\n 407→ffmpeg -i input.mp4 -vf \"fps=10,scale=320:-1:flags=lanczos,split[s0][s1];[s0]palettegen[p];[s1][p]paletteuse\" output.gif\n 408→```\n 409→\n 410→### Add watermark / overlay\n 411→\n 412→```bash\n 413→ffmpeg -i video.mp4 -i logo.png -filter_complex \"overlay=10:10\" output.mp4\n 414→```\n 415→\n 416→### Change speed (video + audio)\n 417→\n 418→```bash\n 419→ffmpeg -i input.mp4 -vf \"setpts=0.5*PTS\" -af \"atempo=2.0\" output.mp4\n 420→```\n 421→\n 422→### Extract frames as images\n 423→\n 424→```bash\n 425→ffmpeg -i input.mp4 -vf \"fps=1\" frame_%04d.png\n 426→```\n 427→\n 428→### Merge audio and video\n 429→\n 430→```bash\n 431→ffmpeg -i video.mp4 -i audio.m4a -c:v copy -c:a copy -shortest output.mp4\n 432→```\n 433→\n 434→### Normalize audio loudness\n 435→\n 436→```bash\n 437→ffmpeg -i input.mp4 -af \"loudnorm=I=-16:TP=-1.5:LRA=11\" -c:v copy output.mp4\n 438→```\n 439→\n 440→### Convert to web-optimized MP4\n 441→\n 442→```bash\n 443→ffmpeg -i input.mp4 -c:v libx264 -crf 23 -preset medium -c:a aac -b:a 128k -movflags +faststart output.mp4\n 444→```\n 445→\n 446→### Probe file info (JSON)\n 447→\n 448→```bash\n 449→ffprobe -v quiet -print_format json -show_format -show_streams input.mp4\n 450→```\n 451→\n 452→### Get duration only\n 453→\n 454→```bash\n 455→ffprobe -v quiet -show_entries format=duration -of default=noprint_wrappers=1:nokey=1 input.mp4\n 456→```\n 457→\n 458→### Get resolution only\n 459→\n 460→```bash\n 461→ffprobe -v quiet -select_streams v:0 -show_entries stream=width,height -of csv=s=x:p=0 input.mp4\n 462→```\n 463→\n 464→---\n 465→\n 466→## Source\n 467→\n 468→- Website: https://ffmpeg.org/\n 469→- Documentation: https://www.ffmpeg.org/documentation.html\n 470→- CLI reference: https://www.ffmpeg.org/ffmpeg.html\n 471→- Filters reference: https://www.ffmpeg.org/ffmpeg-filters.html\n 472→- Codecs reference: https://www.ffmpeg.org/ffmpeg-codecs.html\n 473→- Formats reference: https://www.ffmpeg.org/ffmpeg-formats.html\n 474→- Wiki: https://trac.ffmpeg.org/wiki\n 475→","isError":false},{"role":"tool","toolName":"Read","toolInput":{"file_path":"/home/pastilhas/projects/officer.dev/data/skills/whisper.cpp/SKILL.md"},"toolUseId":"toolu_01DNCSj7RzRbN4Lp4FbFbnd2","output":" 1→---\n 2→name: whisper.cpp\n 3→description: Transcribe audio files to text using whisper.cpp. Use when the user wants to transcribe audio, convert speech to text, or extract text from an audio/video file.\n 4→---\n 5→\n 6→# Whisper.cpp\n 7→\n 8→API reference for the whisper.cpp HTTP server running at `http://macmini:8178`.\n 9→\n 10→whisper.cpp is a C/C++ port of OpenAI's Whisper speech recognition model. The server accepts audio files via HTTP and returns transcriptions in various formats.\n 11→\n 12→## Server\n 13→\n 14→- **Base URL:** `http://macmini:8178`\n 15→- **No authentication required**\n 16→\n 17→## Endpoints\n 18→\n 19→### POST /inference\n 20→\n 21→Transcribes an audio file. Accepts `multipart/form-data`.\n 22→\n 23→#### Example\n 24→\n 25→```bash\n 26→curl -s http://macmini:8178/inference \\\n 27→ -F file=\"@/path/to/audio.mp3\" \\\n 28→ -F temperature=\"0.0\" \\\n 29→ -F temperature_inc=\"0.2\" \\\n 30→ -F response_format=\"json\"\n 31→```\n 32→\n 33→#### Parameters\n 34→\n 35→##### File (required)\n 36→\n 37→| Parameter | Type | Description |\n 38→|-----------|------|-------------|\n 39→| `file` | file | Audio file to transcribe. Accepts at least WAV and MP3. |\n 40→\n 41→##### Response Format\n 42→\n 43→| Parameter | Type | Default | Description |\n 44→|-----------|------|---------|-------------|\n 45→| `response_format` | string | `json` | Output format: `json`, `verbose_json` (or `vjson`), `text`, `srt`, `vtt` |\n 46→\n 47→##### Language\n 48→\n 49→| Parameter | Type | Default | Description |\n 50→|-----------|------|---------|-------------|\n 51→| `language` | string | `en` | Spoken language code (e.g. `en`, `pt`, `es`, `fr`). Use `auto` for auto-detection. |\n 52→| `detect_language` | bool | `false` | Exit after detecting the language (no transcription). |\n 53→| `translate` | bool | `false` | Translate from source language to English. |\n 54→\n 55→##### Decoding\n 56→\n 57→| Parameter | Type | Default | Description |\n 58→|-----------|------|---------|-------------|\n 59→| `temperature` | float | `0.0` | Sampling temperature. `0.0` is deterministic. |\n 60→| `temperature_inc` | float | `0.2` | Temperature increment on fallback attempts. |\n 61→| `best_of` | int | `2` | Number of candidate decodings to keep. |\n 62→| `beam_size` | int | `-1` | Beam search size. `-1` disables beam search. |\n 63→| `entropy_thold` | float | `2.40` | Entropy threshold — decoder fails and retries if exceeded. |\n 64→| `logprob_thold` | float | `-1.00` | Log probability threshold for decoder failure. |\n 65→| `no_fallback` | bool | `false` | Disable temperature fallback on decode failure. |\n 66→\n 67→##### Segmentation\n 68→\n 69→| Parameter | Type | Default | Description |\n 70→|-----------|------|---------|-------------|\n 71→| `max_len` | int | `0` | Maximum segment length in characters. `0` for unlimited. |\n 72→| `max_context` | int | `-1` | Maximum text context tokens to store. `-1` for unlimited. |\n 73→| `split_on_word` | bool | `false` | Split segments at word boundaries instead of token boundaries. |\n 74→| `no_timestamps` | bool | `false` | Suppress timestamps in output. |\n 75→| `word_thold` | float | `0.01` | Word timestamp probability threshold. |\n 76→\n 77→##### Audio Processing\n 78→\n 79→| Parameter | Type | Default | Description |\n 80→|-----------|------|---------|-------------|\n 81→| `offset_t` | int | `0` | Time offset in milliseconds — skip this much audio from the start. |\n 82→| `offset_n` | int | `0` | Segment index offset. |\n 83→| `duration` | int | `0` | Duration of audio to process in milliseconds. `0` for all. |\n 84→| `audio_ctx` | int | `0` | Audio context size. `0` for all. |\n 85→\n 86→##### Speaker Diarization\n 87→\n 88→| Parameter | Type | Default | Description |\n 89→|-----------|------|---------|-------------|\n 90→| `diarize` | bool | `false` | Enable speaker diarization (requires stereo audio). |\n 91→| `tinydiarize` | bool | `false` | Enable tinydiarize (requires a tdrz model). |\n 92→\n 93→##### Voice Activity Detection (VAD)\n 94→\n 95→| Parameter | Type | Default | Description |\n 96→|-----------|------|---------|-------------|\n 97→| `vad` | bool | `false` | Enable VAD preprocessing. |\n 98→| `vad_threshold` | float | `0.50` | Speech confidence threshold (0.01.0). |\n 99→| `vad_min_speech_duration_ms` | int | `250` | Minimum speech segment duration in ms. |\n 100→| `vad_min_silence_duration_ms` | int | `100` | Minimum silence duration to split segments. |\n 101→| `vad_max_speech_duration_s` | float | `FLT_MAX` | Auto-split segments longer than this (seconds). |\n 102→| `vad_speech_pad_ms` | int | `30` | Padding added around speech segments (ms). |\n 103→| `vad_samples_overlap` | float | `0.10` | Overlap between segments (seconds). |\n 104→\n 105→##### Other\n 106→\n 107→| Parameter | Type | Default | Description |\n 108→|-----------|------|---------|-------------|\n 109→| `prompt` | string | `\"\"` | Initial prompt to condition the model (e.g. for vocabulary hints). |\n 110→| `suppress_nst` | bool | `false` | Suppress non-speech tokens. |\n 111→| `no_context` | bool | `false` | Do not use previous audio context for subsequent segments. |\n 112→| `debug_mode` | bool | `false` | Enable debug output. |\n 113→\n 114→#### Response Formats\n 115→\n 116→##### `json` (default)\n 117→\n 118→Minimal JSON with just the transcribed text.\n 119→\n 120→```json\n 121→{\"text\": \"The transcribed content goes here.\"}\n 122→```\n 123→\n 124→##### `verbose_json` (or `vjson`)\n 125→\n 126→Extended JSON including task type, language, audio duration, per-segment timestamps, token-level timing, confidence scores, and language probability distribution.\n 127→\n 128→##### `text`\n 129→\n 130→Plain text transcription. Includes speaker labels if diarization is enabled.\n 131→\n 132→##### `srt`\n 133→\n 134→SubRip subtitle format with sequential numbering, `HH:MM:SS,mmm` timestamps, and text content.\n 135→\n 136→```\n 137→1\n 138→00:00:00,000 --> 00:00:03,500\n 139→The transcribed content goes here.\n 140→```\n 141→\n 142→##### `vtt`\n 143→\n 144→WebVTT subtitle format with `WEBVTT` header and `HH:MM:SS.mmm` timestamps.\n 145→\n 146→```\n 147→WEBVTT\n 148→\n 149→00:00:00.000 --> 00:00:03.500\n 150→The transcribed content goes here.\n 151→```\n 152→\n 153→### POST /load\n 154→\n 155→Loads a different model file on the server at runtime.\n 156→\n 157→```bash\n 158→curl -s http://macmini:8178/load \\\n 159→ -F model=\"/path/to/model.bin\"\n 160→```\n 161→\n 162→| Parameter | Type | Description |\n 163→|-----------|------|-------------|\n 164→| `model` | string | Path to the model file on the server. |\n 165→\n 166→## Supported Audio Formats\n 167→\n 168→The server accepts at least WAV (16-bit PCM) and MP3 files directly. If the server was started with `--convert`, it can use ffmpeg to handle additional formats (ogg, flac, m4a, etc.).\n 169→\n 170→## Source\n 171→\n 172→- Repository: https://github.com/ggml-org/whisper.cpp\n 173→- Server docs: https://github.com/ggml-org/whisper.cpp/blob/master/examples/server/README.md\n 174→","isError":false},{"role":"assistant","text":"Now let me fetch the sharp GitHub README to understand its full API."},{"role":"tool","toolName":"Task","toolInput":{"description":"Fetch sharp API documentation","prompt":"Fetch comprehensive information about the sharp Node.js image processing library from these URLs. I need to understand its full API to write a CLI/programmatic reference document.\n\nFetch these pages and extract all relevant API details:\n\n1. https://github.com/lovell/sharp - Main README, installation, overview\n2. https://sharp.pixelplumbing.com/api-constructor - Constructor API\n3. https://sharp.pixelplumbing.com/api-input - Input options\n4. https://sharp.pixelplumbing.com/api-output - Output options (toFile, toBuffer, toFormat, jpeg, png, webp, avif, tiff, gif, heif, raw, tile)\n5. https://sharp.pixelplumbing.com/api-resize - Resize operations\n6. https://sharp.pixelplumbing.com/api-operation - Operations (rotate, flip, flop, sharpen, blur, extend, extract, trim, etc.)\n7. https://sharp.pixelplumbing.com/api-colour - Colour operations (tint, greyscale, pipelineColourspace, toColourspace)\n8. https://sharp.pixelplumbing.com/api-channel - Channel operations (removeAlpha, ensureAlpha, extractChannel, joinChannel, bandbool)\n9. https://sharp.pixelplumbing.com/api-composite - Compositing (overlay images)\n10. https://sharp.pixelplumbing.com/api-utility - Utility (metadata, stats, toBuffer, etc.)\n\nFor each page, extract:\n- Method signatures\n- Parameter names, types, defaults, and descriptions\n- Return types\n- Important notes or constraints\n\nReturn ALL the information in a structured format so I can write a comprehensive SKILL.md reference document.","subagent_type":"general-purpose"},"toolUseId":"toolu_01A3qpHESGVbcmKESYHRE39q","output":"Here is the comprehensive structured reference for the **sharp** Node.js image processing library, compiled from all 10 documentation pages.\n\n---\n\n## SHARP API REFERENCE\n\n### Overview\n\nSharp is a high-performance Node.js image processing library built on libvips. It is typically 4-5x faster than ImageMagick/GraphicsMagick. It supports JPEG, PNG, WebP, GIF, AVIF, TIFF, SVG, HEIF, JP2, and JXL formats. Licensed under Apache 2.0.\n\n**Runtime requirements:** Node.js ^18.17.0 or >= 20.3.0, Deno, or Bun (any runtime supporting Node-API v9).\n\n**Installation:** `npm install sharp`\n\n---\n\n### 1. CONSTRUCTOR\n\n**Signature:** `sharp([input], [options])`\n\n**Returns:** Sharp instance (implements `stream.Duplex`). Emits `info` and `warning` events.\n\n**`input`** (optional): `Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array | Float64Array | string | Array`\n- Buffer/typed array containing image data\n- String filesystem path\n- Array of inputs (joined together)\n- Omit for streaming input\n\n**`options`** (optional Object):\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `failOn` | string | `'warning'` | Abort sensitivity: `'none'`, `'truncated'`, `'error'`, `'warning'` |\n| `limitInputPixels` | number \\| boolean | `268402689` | Max pixels (width x height); `false` removes limit |\n| `unlimited` | boolean | `false` | Remove memory safety features for JPEG, PNG, SVG, HEIF |\n| `autoOrient` | boolean | `false` | Auto-rotate/flip per EXIF Orientation tag |\n| `sequentialRead` | boolean | `true` | Use sequential vs random access reading |\n| `density` | number | `72` | DPI for vector images (1-100000) |\n| `ignoreIcc` | boolean | `false` | Ignore embedded ICC profile |\n| `pages` | number | `1` | Pages to extract from multi-page images; `-1` for all |\n| `page` | number | `0` | Starting page index (zero-based) |\n| `animated` | boolean | `false` | Read all frames (equivalent to `pages: -1`) |\n\n**`options.raw`** (Object, for raw pixel input):\n\n| Property | Type | Required | Description |\n|---|---|---|---|\n| `width` | number | Yes | Pixel width |\n| `height` | number | Yes | Pixel height |\n| `channels` | number | Yes | 1-4 channels |\n| `premultiplied` | boolean | No (default `false`) | Skip premultiplication if already applied |\n| `pageHeight` | number | No | Frame height for animated images |\n\n**`options.create`** (Object, create a new image):\n\n| Property | Type | Required | Description |\n|---|---|---|---|\n| `width` | number | Yes | Pixel width |\n| `height` | number | Yes | Pixel height |\n| `channels` | number | Yes | 3 (RGB) or 4 (RGBA) |\n| `background` | string \\| Object | No | Color parsed by color module |\n| `pageHeight` | number | No | Frame height for animated images |\n| `noise` | Object | No | `{type: 'gaussian', mean: 128, sigma: 30}` |\n\n**`options.text`** (Object, render text as image):\n\n| Property | Type | Default | Description |\n|---|---|---|---|\n| `text` | string | -- | UTF-8 string; supports Pango markup |\n| `font` | string | -- | Font name |\n| `fontfile` | string | -- | Absolute path to font file |\n| `width` | number | `0` | Word-wrap pixel boundary; 0 = no wrap |\n| `height` | number | `0` | Max pixel height |\n| `align` | string | `'left'` | `'left'`, `'centre'`, `'center'`, `'right'` |\n| `justify` | boolean | `false` | Text justification |\n| `dpi` | number | `72` | Render resolution (ignored if height specified) |\n| `rgba` | boolean | `false` | RGBA for color emoji and Pango markup |\n| `spacing` | number | `0` | Line height in points |\n| `wrap` | string | `'word'` | `'word'`, `'char'`, `'word-char'`, `'none'` |\n\n**`options.join`** (Object, for array input composition):\n\n| Property | Type | Default | Description |\n|---|---|---|---|\n| `across` | number | `1` | Images per row |\n| `animated` | boolean | `false` | Join as animated image |\n| `shim` | number | `0` | Pixels between images |\n| `background` | string \\| Object | -- | Gap fill color |\n| `halign` | string | `'left'` | `'left'`, `'centre'`, `'center'`, `'right'` |\n| `valign` | string | `'top'` | `'top'`, `'centre'`, `'center'`, `'bottom'` |\n\n**Format-specific constructor options:**\n- `options.tiff.subifd` (number, default `-1`): OME-TIFF sub-image directory index\n- `options.svg.stylesheet` (string): Custom CSS for SVG\n- `options.svg.highBitdepth` (boolean, default `false`): 32-bit vs 8-bit per channel\n- `options.pdf.background` (string \\| Object): Fill for transparent areas\n- `options.openSlide.level` (number, default `0`): Multi-level extraction index\n- `options.jp2.oneshot` (boolean, default `false`): Single-operation tiled decoding\n\n**`clone() => Sharp`**: Returns new instance sharing parent input for multiple independent output pipelines.\n\n---\n\n### 2. INPUT / METADATA\n\n**`metadata([callback]) => Promise<Object> | Sharp`**\n\nFast access to image metadata without decoding pixels. Returns:\n\n| Property | Type | Description |\n|---|---|---|\n| `format` | string | Decoder name (jpeg, png, webp, gif, svg, etc.) |\n| `size` | number | Total bytes (Stream/Buffer input only) |\n| `width` | number | Pixel width |\n| `height` | number | Pixel height |\n| `space` | string | Color space (srgb, rgb, cmyk, lab, b-w, etc.) |\n| `channels` | number | Band count |\n| `depth` | string | Pixel format (uchar, char, ushort, float, etc.) |\n| `density` | number | DPI if present |\n| `chromaSubsampling` | string | e.g. `'4:2:0'` or `'4:4:4'` |\n| `isProgressive` | boolean | Progressive/interlaced encoding |\n| `isPalette` | boolean | Palette-based |\n| `bitsPerSample` | number | Bits per channel |\n| `pages` | number | Page count |\n| `pageHeight` | number | Height per page |\n| `loop` | number | Animation loop count |\n| `delay` | Array | Frame delays |\n| `hasAlpha` | boolean | Has alpha channel |\n| `hasProfile` | boolean | Has ICC profile |\n| `isOpaque` | boolean | Fully opaque |\n| `orientation` | number | EXIF orientation (1-8) |\n| `exif` | Buffer | EXIF data |\n| `icc` | Buffer | ICC profile |\n| `iptc` | Buffer | IPTC data |\n| `xmp` | Buffer | XMP data |\n| `xmpAsString` | string | XMP as string |\n| `dominant` | Object | Dominant sRGB color |\n\n**`stats([callback]) => Promise<Object>`**\n\nPixel-derived statistics (from original input, not after operations). Returns:\n\n| Property | Type | Description |\n|---|---|---|\n| `channels` | Array | Per-channel: min, max, sum, squaresSum, mean, stdev, minX, minY, maxX, maxY |\n| `isOpaque` | boolean | Fully opaque or no alpha |\n| `entropy` | number | Greyscale entropy estimation |\n| `sharpness` | number | Laplacian-based sharpness |\n| `dominant` | Object | Most dominant sRGB color |\n\n---\n\n### 3. RESIZE\n\n**`resize([width], [height], [options]) => Sharp`**\n\n| Option | Type | Default | Description |\n|---|---|---|---|\n| `width` | number | -- | Target width (null/undefined to auto-scale) |\n| `height` | number | -- | Target height (null/undefined to auto-scale) |\n| `fit` | string | `'cover'` | `'cover'`, `'contain'`, `'fill'`, `'inside'`, `'outside'` |\n| `position` | string | `'centre'` | Position for cover/contain (see below) |\n| `background` | string \\| Object | `{r:0,g:0,b:0,alpha:1}` | Fill color for `contain` |\n| `kernel` | string | `'lanczos3'` | `'nearest'`, `'linear'`, `'cubic'`, `'mitchell'`, `'lanczos2'`, `'lanczos3'`, `'mks2013'`, `'mks2021'` |\n| `withoutEnlargement` | boolean | `false` | Prevent upscaling |\n| `withoutReduction` | boolean | `false` | Prevent downscaling |\n| `fastShrinkOnLoad` | boolean | `true` | JPEG/WebP shrink-on-load |\n\n**Fit modes:**\n- `cover`: Crop to fill both dimensions (preserves aspect ratio)\n- `contain`: Letterbox to fit within dimensions (preserves aspect ratio)\n- `fill`: Stretch to exact dimensions (ignores aspect ratio)\n- `inside`: Fit within dimensions without exceeding (preserves aspect ratio)\n- `outside`: Minimum size while meeting dimensions (preserves aspect ratio)\n\n**Position values:** `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`, `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `centre`/`center`\n\n**Strategy (cover only):** `entropy` (Shannon entropy), `attention` (luminance/saturation/skin tone)\n\n**Constraint:** Only one resize per pipeline.\n\n---\n\n### 4. OPERATIONS\n\n**`rotate([angle], [options]) => Sharp`**\n- `angle` (number): Degrees; auto from EXIF if omitted\n- `options.background` (string \\| Object, default `'#000000'`): Fill color\n- Converts angles to valid positive rotation. One rotation per pipeline.\n\n**`autoOrient() => Sharp`**\n- Auto-orient from EXIF Orientation tag, then removes the tag.\n\n**`flip([flip]) => Sharp`**\n- `flip` (boolean, default `true`): Vertical mirror (up-down about x-axis)\n- Does not work with multi-page images.\n\n**`flop([flop]) => Sharp`**\n- `flop` (boolean, default `true`): Horizontal mirror (left-right about y-axis)\n\n**`affine(matrix, [options]) => Sharp`**\n- `matrix` (Array): 2x2 or flat length-4 transformation matrix\n- `options.background` (string \\| Object, default `'#000000'`)\n- `options.idx`, `options.idy` (number, default `0`): Input offsets\n- `options.odx`, `options.ody` (number, default `0`): Output offsets\n- `options.interpolator` (string, default `sharp.interpolators.bicubic`)\n\n**`sharpen([options], [flat], [jagged]) => Sharp`**\n- `options.sigma` (number, 0.000001-10): Gaussian mask sigma\n- `options.m1` (number, default `1.0`): Flat area sharpening (0-1000000)\n- `options.m2` (number, default `2.0`): Jagged area sharpening (0-1000000)\n- `options.x1` (number, default `2.0`): Flat/jagged threshold (0-1000000)\n- `options.y2` (number, default `10.0`): Max brightening (0-1000000)\n- `options.y3` (number, default `20.0`): Max darkening (0-1000000)\n- `flat`, `jagged` deprecated in favor of `options.m1`, `options.m2`\n\n**`median([size]) => Sharp`**\n- `size` (number, default `3`): Square mask dimension (size x size)\n\n**`blur([options]) => Sharp`**\n- Without params: 3x3 box blur\n- `options.sigma` (number, 0.3-1000): Gaussian blur sigma\n- `options.precision` (string, default `'integer'`): `'integer'`, `'float'`, `'approximate'`\n- `options.minAmplitude` (number, default `0.2`, 0.001-1): Mask accuracy\n\n**`dilate([width]) => Sharp`**\n- `width` (number, default `1`): Dilation width in pixels\n\n**`erode([width]) => Sharp`**\n- `width` (number, default `1`): Erosion width in pixels\n\n**`flatten([options]) => Sharp`**\n- `options.background` (string \\| Object, default `{r:0,g:0,b:0}`): Merge alpha with background, remove alpha\n\n**`unflatten() => Sharp`** (experimental)\n- Add alpha channel; white pixels become fully transparent.\n\n**`gamma([gamma], [gammaOut]) => Sharp`**\n- `gamma` (number, default `2.2`, 1.0-3.0)\n- `gammaOut` (number, 1.0-3.0, defaults to `gamma`)\n- JPEG/WebP inputs lose shrink-on-load optimization.\n\n**`negate([options]) => Sharp`**\n- `options.alpha` (boolean, default `true`): Whether to negate alpha channel\n\n**`normalise([options]) => Sharp`** (alias: `normalize`)\n- `options.lower` (number, default `1`): Underexposure percentile\n- `options.upper` (number, default `99`): Overexposure percentile\n- Stretches luminance to full dynamic range.\n\n**`clahe(options) => Sharp`**\n- `options.width` (number, required): Search window width\n- `options.height` (number, required): Search window height\n- `options.maxSlope` (number, default `3`, 0-100): Brightening level\n\n**`convolve(kernel) => Sharp`**\n- `kernel.width` (number, required)\n- `kernel.height` (number, required)\n- `kernel.kernel` (Array, required): width*height values\n- `kernel.scale` (number, default sum of kernel)\n- `kernel.offset` (number, default `0`)\n\n**`threshold([threshold], [options]) => Sharp`**\n- `threshold` (number, default `128`, 0-255)\n- `options.greyscale` / `options.grayscale` (boolean, default `true`)\n\n**`boolean(operand, operator, [options]) => Sharp`**\n- `operand` (Buffer \\| string): Image data or file path\n- `operator` (string): `'and'`, `'or'`, `'eor'`\n- `options.raw` (Object): `{width, height, channels}` for raw input\n\n**`linear([a], [b]) => Sharp`**\n- `a` (number \\| Array, default `[]`): Multiplier per channel\n- `b` (number \\| Array, default `[]`): Offset per channel\n- Formula: `a * input + b`\n\n**`recomb(inputMatrix) => Sharp`**\n- `inputMatrix` (Array): 3x3 or 4x4 recombination matrix\n\n**`modulate([options]) => Sharp`**\n- `options.brightness` (number): Multiplicative brightness\n- `options.saturation` (number): Saturation multiplier\n- `options.hue` (number): Hue rotation in degrees\n- `options.lightness` (number): Additive lightness\n\n**`extend(extend) => Sharp`**\n- `extend` (number \\| Object): Uniform padding or per-edge\n- `options.top`, `left`, `bottom`, `right` (number, default `0`)\n- `options.extendWith` (string, default `'background'`): `'background'`, `'copy'`, `'repeat'`, `'mirror'`\n- `options.background` (string \\| Object, default `{r:0,g:0,b:0,alpha:1}`)\n- Always applies after resize and extract.\n\n**`extract(options) => Sharp`**\n- `options.left` (number): Zero-indexed horizontal offset\n- `options.top` (number): Zero-indexed vertical offset\n- `options.width` (number): Region width\n- `options.height` (number): Region height\n- Can be called before resize (pre-resize crop) or after resize (post-resize crop), or both.\n\n**`trim([options]) => Sharp`**\n- `options.background` (string \\| Object, default top-left pixel)\n- `options.threshold` (number, default `10`): Color match tolerance\n- `options.lineArt` (boolean, default `false`): Optimize for vector/line art\n- Response info includes `trimOffsetLeft` and `trimOffsetTop`.\n\n---\n\n### 5. COLOUR\n\n**`tint(tint) => Sharp`**\n- `tint` (string \\| Object): Color parsed by color module. Preserves alpha.\n\n**`greyscale([greyscale]) => Sharp`** (alias: `grayscale`)\n- `greyscale` (boolean, default `true`): 8-bit greyscale conversion (256 shades)\n- Use `gamma()` for non-linear source spaces like sRGB.\n\n**`pipelineColourspace([colourspace]) => Sharp`** (alias: `pipelineColorspace`)\n- `colourspace` (string): `'rgb16'`, `'scrgb'`, `'lab'`, `'grey16'`, etc.\n- Sets colorspace at pipeline start; all operations execute in this space. Since v0.29.0.\n\n**`toColourspace([colourspace]) => Sharp`** (alias: `toColorspace`)\n- `colourspace` (string): `'srgb'`, `'rgb'`, `'cmyk'`, `'lab'`, `'b-w'`, etc.\n- Output colorspace. Default: web-friendly sRGB.\n\n---\n\n### 6. CHANNEL\n\n**`removeAlpha() => Sharp`**\n- Removes alpha channel. No-op if none exists.\n\n**`ensureAlpha([alpha]) => Sharp`** (since v0.21.2)\n- `alpha` (number, default `1`): Transparency level (0=transparent, 1=opaque)\n\n**`extractChannel(channel) => Sharp`**\n- `channel` (number \\| string): Zero-indexed band number, or `'red'`, `'green'`, `'blue'`, `'alpha'`\n- Output: b-w (8-bit) or grey16 (16-bit)\n\n**`joinChannel(images, options) => Sharp`**\n- `images` (string \\| Buffer \\| Array): Image source(s)\n- `options` (Object): Same as sharp() constructor options\n- Channel order: sRGB = R(0), G(1), B(2), A(3); CMYK = M(0), C(1), Y(2), K(3), A(4)\n\n**`bandbool(boolOp) => Sharp`**\n- `boolOp` (string): `'and'`, `'or'`, `'eor'`\n- Produces single-channel image from bitwise operation across all bands.\n\n---\n\n### 7. COMPOSITE\n\n**`composite(images) => Sharp`** (since v0.22.0)\n\n`images` is an Array of objects, each with:\n\n| Property | Type | Default | Description |\n|---|---|---|---|\n| `input` | Buffer \\| string | -- | Image buffer, file path, or use `create`/`text` sub-object |\n| `blend` | string | `'over'` | Blend mode (see below) |\n| `gravity` | string | `'centre'` | Overlay placement |\n| `top` | number | -- | Pixel offset from top (overrides gravity) |\n| `left` | number | -- | Pixel offset from left (overrides gravity) |\n| `tile` | boolean | `false` | Repeat overlay across entire image |\n| `premultiplied` | boolean | `false` | Avoid premultiplication |\n| `density` | number | `72` | DPI for vector overlays |\n| `autoOrient` | boolean | `false` | Apply EXIF orientation |\n| `animated` | boolean | `false` | Read all frames |\n| `raw` | Object | -- | `{width, height, channels}` for raw pixel data |\n| `failOn` | string | `'warning'` | Error sensitivity |\n| `limitInputPixels` | number \\| boolean | `268402689` | Max pixels |\n\nThe `input` property also supports `create` (with `width`, `height`, `channels`, `background`) and `text` (same properties as constructor `options.text`).\n\n**Blend modes (24):** `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`\n\n**Constraints:** All pipeline operations apply to input before compositing. Overlay images cannot exceed base image dimensions.\n\n---\n\n### 8. OUTPUT\n\n**`toFile(fileOut, [callback]) => Promise<Object>`**\n- Format inferred from extension (.jpg, .png, .webp, .avif, .tiff, .gif, .dzi, .v)\n- Returns info: `{format, size, width, height, channels, premultiplied, cropOffsetLeft, cropOffsetTop, attentionX, attentionY, pageHeight, pages, textAutofitDpi}`\n\n**`toBuffer([options], [callback]) => Promise<Buffer>`**\n- `options.resolveWithObject` (boolean, default `false`): Resolve with `{data, info}` instead of raw buffer\n\n**`toFormat(format, options) => Sharp`**\n- `format` (string \\| Object): Format ID or `{id: string}`\n\n**`jpeg([options]) => Sharp`**\n\n| Option | Type | Default |\n|---|---|---|\n| `quality` | number | `80` (1-100) |\n| `progressive` | boolean | `false` |\n| `chromaSubsampling` | string | `'4:2:0'` |\n| `optimiseCoding`/`optimizeCoding` | boolean | `true` |\n| `mozjpeg` | boolean | `false` |\n| `trellisQuantisation` | boolean | `false` |\n| `overshootDeringing` | boolean | `false` |\n| `optimiseScans`/`optimizeScans` | boolean | `false` |\n| `quantisationTable`/`quantizationTable` | number | `0` (0-8) |\n| `force` | boolean | `true` |\n\n**`png([options]) => Sharp`**\n\n| Option | Type | Default |\n|---|---|---|\n| `progressive` | boolean | `false` |\n| `compressionLevel` | number | `6` (0-9) |\n| `adaptiveFiltering` | boolean | `false` |\n| `palette` | boolean | `false` |\n| `quality` | number | `100` (enables palette) |\n| `effort` | number | `7` (1-10, enables palette) |\n| `colours`/`colors` | number | `256` (enables palette) |\n| `dither` | number | `1.0` (Floyd-Steinberg, enables palette) |\n| `force` | boolean | `true` |\n\n**`webp([options]) => Sharp`**\n\n| Option | Type | Default |\n|---|---|---|\n| `quality` | number | `80` (1-100) |\n| `alphaQuality` | number | `100` (0-100) |\n| `lossless` | boolean | `false` |\n| `nearLossless` | boolean | `false` |\n| `smartSubsample` | boolean | `false` |\n| `smartDeblock` | boolean | `false` |\n| `preset` | string | `'default'` (`default`, `photo`, `picture`, `drawing`, `icon`, `text`) |\n| `effort` | number | `4` (0-6) |\n| `loop` | number | `0` (0=infinite) |\n| `delay` | number \\| Array | -- |\n| `minSize` | boolean | `false` |\n| `mixed` | boolean | `false` |\n| `force` | boolean | `true` |\n\n**`avif([options]) => Sharp`** (since v0.27.0)\n\n| Option | Type | Default |\n|---|---|---|\n| `quality` | number | `50` (1-100) |\n| `lossless` | boolean | `false` |\n| `effort` | number | `4` (0-9) |\n| `chromaSubsampling` | string | `'4:4:4'` |\n| `bitdepth` | number | `8` (8, 10, or 12) |\n\n**`gif([options]) => Sharp`** (since v0.30.0)\n\n| Option | Type | Default |\n|---|---|---|\n| `reuse` | boolean | `true` |\n| `progressive` | boolean | `false` |\n| `colours`/`colors` | number | `256` (2-256) |\n| `effort` | number | `7` (1-10) |\n| `dither` | number | `1.0` (0-1) |\n| `interFrameMaxError` | number | `0` (0-32) |\n| `interPaletteMaxError` | number | `3` (0-256) |\n| `keepDuplicateFrames` | boolean | `false` |\n| `loop` | number | `0` |\n| `delay` | number \\| Array | -- |\n| `force` | boolean | `true` |\n\n**`heif(options) => Sharp`** (since v0.23.0, requires libvips with libheif/libde265/x265)\n\n| Option | Type | Default |\n|---|---|---|\n| `compression` | string | required (`'av1'` or `'hevc'`) |\n| `quality` | number | `50` (1-100) |\n| `lossless` | boolean | `false` |\n| `effort` | number | `4` (0-9) |\n| `chromaSubsampling` | string | `'4:4:4'` |\n| `bitdepth` | number | `8` (8, 10, or 12) |\n\n**`jp2([options]) => Sharp`** (since v0.29.1, requires custom libvips with OpenJPEG)\n\n| Option | Type | Default |\n|---|---|---|\n| `quality` | number | `80` (1-100) |\n| `lossless` | boolean | `false` |\n| `tileWidth` | number | `512` |\n| `tileHeight` | number | `512` |\n| `chromaSubsampling` | string | `'4:4:4'` |\n\n**`tiff([options]) => Sharp`**\n\n| Option | Type | Default |\n|---|---|---|\n| `quality` | number | `80` (1-100) |\n| `compression` | string | `'jpeg'` (`none`, `jpeg`, `deflate`, `packbits`, `ccittfax4`, `lzw`, `webp`, `zstd`, `jp2k`) |\n| `bigtiff` | boolean | `false` |\n| `predictor` | string | `'horizontal'` (`none`, `horizontal`, `float`) |\n| `pyramid` | boolean | `false` |\n| `tile` | boolean | `false` |\n| `tileWidth` | number | `256` |\n| `tileHeight` | number | `256` |\n| `xres` | number | `1.0` (pixels/mm) |\n| `yres` | number | `1.0` (pixels/mm) |\n| `resolutionUnit` | string | `'inch'` |\n| `bitdepth` | number | `8` (1, 2, or 4) |\n| `miniswhite` | boolean | `false` |\n| `force` | boolean | `true` |\n\n**`jxl([options]) => Sharp`** (since v0.31.3, EXPERIMENTAL, requires custom libvips with libjxl)\n\n| Option | Type | Default |\n|---|---|---|\n| `distance` | number | `1.0` (0-15) |\n| `quality` | number | -- (1-100, overrides distance) |\n| `decodingTier` | number | `0` (0-4) |\n| `lossless` | boolean | `false` |\n| `effort` | number | `7` (1-9) |\n| `loop` | number | `0` |\n| `delay` | number \\| Array | -- |\n\n**`raw([options]) => Sharp`**\n- `options.depth` (string, default `'uchar'`): `char`, `uchar`, `short`, `ushort`, `int`, `uint`, `float`, `complex`, `double`, `dpcomplex`\n\n**`tile([options]) => Sharp`**\n\n| Option | Type | Default |\n|---|---|---|\n| `size` | number | `256` (1-8192) |\n| `overlap` | number | `0` (0-8192) |\n| `angle` | number | `0` (multiple of 90) |\n| `background` | string \\| Object | `{r:255,g:255,b:255,alpha:1}` |\n| `depth` | string | -- (`onepixel`, `onetile`, `one`) |\n| `skipBlanks` | number | `-1` (or `5` for google layout) |\n| `container` | string | `'fs'` (`fs`, `zip`) |\n| `layout` | string | `'dz'` (`dz`, `iiif`, `iiif3`, `zoomify`, `google`) |\n| `centre`/`center` | boolean | `false` |\n| `id` | string | `'https://example.com/iiif'` |\n| `basename` | string | -- |\n\n**`timeout(options) => Sharp`** (since v0.29.2)\n- `options.seconds` (number): 0 = indefinite (default)\n\n---\n\n### 9. METADATA PRESERVATION (Output)\n\n**`keepExif() => Sharp`** (since v0.33.0) -- Preserve all EXIF. Not supported for TIFF output.\n\n**`withExif(exif) => Sharp`** (since v0.33.0) -- Set EXIF, ignoring input.\n- `exif`: `Object<string, Object<string, string>>` keyed by IFD (IFD0, IFD1, IFD3, etc.)\n\n**`withExifMerge(exif) => Sharp`** (since v0.33.0) -- Merge with existing EXIF.\n\n**`keepIccProfile() => Sharp`** (since v0.33.0) -- Preserve ICC profile.\n\n**`withIccProfile(icc, [options]) => Sharp`** (since v0.33.0)\n- `icc` (string): Path or built-in (`'srgb'`, `'p3'`, `'cmyk'`)\n- `options.attach` (boolean, default `true`): Include in output metadata\n\n**`keepXmp() => Sharp`** (since v0.34.3) -- Preserve XMP metadata.\n\n**`withXmp(xmp) => Sharp`** (since v0.34.3) -- Set XMP (PNG, JPEG, WebP, TIFF).\n- `xmp` (string): XMP XML string\n\n**`keepMetadata() => Sharp`** (since v0.33.0) -- Preserve all metadata (EXIF, ICC, XMP, IPTC). Default behavior strips everything and converts to sRGB.\n\n**`withMetadata([options]) => Sharp`** -- Preserve most metadata, add sRGB ICC profile.\n- `options.orientation` (number): EXIF Orientation (1-8)\n- `options.density` (number): DPI\n\n---\n\n### 10. UTILITY (Static/Module)\n\n**`sharp.format`** -- Object with booleans for available input/output formats.\n\n**`sharp.interpolators`** -- Read-only enum:\n- `nearest`, `bilinear`, `bicubic` (default), `locallyBoundedBicubic` (`'lbb'`), `nohalo`, `vertexSplitQuadraticBasisSpline` (`'vsqbs'`)\n\n**`sharp.versions`** -- Version numbers of sharp, libvips, and dependencies.\n\n**`sharp.queue`** -- EventEmitter; emits `'change'` on task queue/complete.\n\n**`sharp.cache([options]) => Object`**\n- `options` (Object \\| boolean): `{memory: 50, files: 20, items: 100}` (defaults). Returns cache stats.\n\n**`sharp.concurrency([concurrency]) => number`**\n- Default: CPU core count. Pass `0` to reset.\n\n**`sharp.counters() => Object`**\n- Returns `{queue: number, process: number}`.\n\n**`sharp.simd([simd]) => boolean`**\n- Enable/disable SIMD (default `true`).\n\n**`sharp.block(options)`** (since v0.32.4)\n- `options.operation` (Array<string>): Operation names to block.\n\n**`sharp.unblock(options)`** (since v0.32.4)\n- `options.operation` (Array<string>): Operation names to unblock.\n\n---\n\nThis covers the complete sharp API surface: constructor with all input variants (buffer, file, stream, raw, create, text, join, format-specific options), the clone method, metadata/stats, resize with all fit/position/kernel options, 22+ image operations (rotate, flip, flop, affine, sharpen, median, blur, dilate, erode, flatten, unflatten, gamma, negate, normalise, clahe, convolve, threshold, boolean, linear, recomb, modulate, extend, extract, trim), colour operations (tint, greyscale, pipelineColourspace, toColourspace), channel operations (removeAlpha, ensureAlpha, extractChannel, joinChannel, bandbool), compositing with 24 blend modes, all 12 output format methods with every option, metadata preservation methods (keepExif, withExif, withExifMerge, keepIccProfile, withIccProfile, keepXmp, withXmp, keepMetadata, withMetadata), tile output, timeout, and all static utility methods/properties.\nagentId: ac5d0fc (for resuming to continue this agent's work if needed)\n<usage>total_tokens: 35625\ntool_uses: 10\nduration_ms: 179911</usage>","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://github.com/lovell/sharp","prompt":"Extract ALL information about the sharp library: description, features, installation instructions, basic usage examples, supported formats, performance notes, requirements, and any API overview. Be comprehensive."},"toolUseId":"toolu_01DsN6npZb8dVXTeZeKeWX1B","output":"# Sharp Library: Comprehensive Overview\n\n## Description\nSharp is a high-performance Node.js image processing module designed to convert large images into smaller, web-friendly formats. It leverages libvips as its underlying image processing engine, delivering exceptional speed compared to ImageMagick and GraphicsMagick alternatives.\n\n## Core Features\n- **Image Resizing**: Typically 4x-5x faster than ImageMagick/GraphicsMagick\n- **Format Support**: JPEG, PNG, WebP, GIF, and AVIF output formats; TIFF input support\n- **Advanced Operations**: Rotation, extraction, compositing, and gamma correction\n- **Color Management**: Proper handling of color spaces, ICC profiles, and alpha transparency\n- **Quality**: Lanczos resampling maintains visual quality while prioritizing speed\n- **Streaming**: Full support for Node.js streams\n\n## Runtime Compatibility\nWorks with JavaScript runtimes supporting Node-API v9:\n- Node.js (^18.17.0 or >= 20.3.0)\n- Deno\n- Bun\n\n## Installation\n```\nnpm install sharp\n```\n\n## Usage Examples\n\n**Callback Pattern**:\n```javascript\nconst sharp = require('sharp');\nsharp(inputBuffer)\n .resize(320, 240)\n .toFile('output.webp', (err, info) => { ... });\n```\n\n**Promise-Based**:\n```javascript\nsharp('input.jpg')\n .rotate()\n .resize(200)\n .jpeg({ mozjpeg: true })\n .toBuffer()\n .then(data => { ... });\n```\n\n**Async/Await with Image Creation**:\n```javascript\nconst png = await sharp({\n create: {\n width: 48,\n height: 48,\n channels: 4,\n background: { r: 255, g: 0, b: 0, alpha: 0.5 }\n }\n})\n .png()\n .toBuffer();\n```\n\n**Stream Processing**:\nSupports piping readable streams through transformations to writable streams.\n\n## System Requirements\nMost modern macOS, Windows, and Linux installations require no additional dependencies.\n\n## Project Metadata\n- **License**: Apache 2.0\n- **Repository**: 31.9k stars, 1.4k forks\n- **Active Maintenance**: 107 releases, 223 contributors\n- **Adoption**: Used by 2.2 million projects\n\n## Documentation & Resources\nComplete details available at sharp.pixelplumbing.com, including installation guides, API documentation, performance benchmarks, and changelog.","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-constructor","prompt":"Extract ALL constructor API details: method signatures, every parameter name with type, default value, and description. Include all options object properties, return types, examples, and any notes or constraints. Be exhaustive - I need every single parameter and option documented."},"toolUseId":"toolu_01MTP3hBvkiW5cqB3Ss8YDnA","output":"# Sharp Constructor API - Complete Reference\n\n## Sharp Constructor\n\n**Signature:** `new Sharp([input], [options])`\n\n**Returns:** Sharp instance (implements `stream.Duplex`)\n\n**Emits:** `info` and `warning` events\n\n**Throws:** Error for invalid parameters\n\n---\n\n## Input Parameter\n\n**Type:** `Buffer | ArrayBuffer | Uint8Array | Uint8ClampedArray | Int8Array | Uint16Array | Int16Array | Uint32Array | Int32Array | Float32Array | Float64Array | string | Array`\n\n**Optional.** Can be:\n- Buffer/typed arrays with JPEG, PNG, WebP, AVIF, GIF, SVG, or TIFF data\n- TypedArray with raw pixel data\n- Filesystem path string to image file\n- Array of inputs (joined together)\n- Streamed input when omitted\n\n---\n\n## Options Parameter\n\n**Type:** Object (all properties optional)\n\n### Core Processing Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `failOn` | string | `'warning'` | Abort sensitivity: 'none', 'truncated', 'error', 'warning' (ordered by severity) |\n| `limitInputPixels` | number \\| boolean | 268402689 | Max pixels (width × height); false removes limit, true uses default |\n| `unlimited` | boolean | false | Remove memory-exhaustion safety features for JPEG, PNG, SVG, HEIF |\n| `autoOrient` | boolean | false | Rotate/flip per EXIF Orientation metadata |\n| `sequentialRead` | boolean | true | Use sequential vs. random access for reading |\n\n### Image Metadata Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `density` | number | 72 | DPI for vector images (range: 1100000) |\n| `ignoreIcc` | boolean | false | Ignore embedded ICC profile |\n| `pages` | number | 1 | Pages to extract from multi-page images; -1 for all |\n| `page` | number | 0 | Starting page index (zero-based) |\n| `animated` | boolean | false | Read all frames; equivalent to `pages: -1` |\n\n---\n\n## Raw Pixel Input (options.raw)\n\n**Type:** Object (describes raw pixel data)\n\n| Property | Type | Required | Description |\n|----------|------|----------|-------------|\n| `width` | number | Yes | Integral pixel width |\n| `height` | number | Yes | Integral pixel height |\n| `channels` | number | Yes | 14 channels |\n| `premultiplied` | boolean | No (default false) | Skip premultiplication if already applied |\n| `pageHeight` | number | No | Frame height for animated images |\n\n---\n\n## Create New Image (options.create)\n\n**Type:** Object (describes generated image)\n\n| Property | Type | Required | Description |\n|----------|------|----------|-------------|\n| `width` | number | Yes | Integral pixel width |\n| `height` | number | Yes | Integral pixel height |\n| `channels` | number | Yes | 3 (RGB) or 4 (RGBA) |\n| `background` | string \\| Object | No | Color (parsed by color module) |\n| `pageHeight` | number | No | Frame height for animated images |\n| `noise` | Object | No | Noise generation config |\n\n### Noise Generation (options.create.noise)\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `type` | string | — | Currently only `'gaussian'` supported |\n| `mean` | number | 128 | Mean pixel value |\n| `sigma` | number | 30 | Standard deviation |\n\n---\n\n## Text Rendering (options.text)\n\n**Type:** Object (describes text image creation)\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `text` | string | — | UTF-8 string; supports Pango markup (e.g., `<i>text</i>`) |\n| `font` | string | — | Font name for rendering |\n| `fontfile` | string | — | Absolute path to custom font file |\n| `width` | number | 0 | Word-wrap at pixel boundary; 0 = no wrap |\n| `height` | number | 0 | Max pixel height (auto-fits text when set with width) |\n| `align` | string | `'left'` | 'left', 'centre', 'center', or 'right' |\n| `justify` | boolean | false | Apply text justification |\n| `dpi` | number | 72 | Render resolution (ignored if height specified) |\n| `rgba` | boolean | false | Enable RGBA for color emoji and Pango markup |\n| `spacing` | number | 0 | Line height in points |\n| `wrap` | string | `'word'` | 'word', 'char', 'word-char', or 'none' |\n\n---\n\n## Image Joining (options.join)\n\n**Type:** Object (describes array input composition)\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `across` | number | 1 | Horizontal image count per row |\n| `animated` | boolean | false | Join as animated image |\n| `shim` | number | 0 | Pixels between images |\n| `background` | string \\| Object | — | Color for gaps (parsed by color module) |\n| `halign` | string | `'left'` | Horizontal: 'left', 'centre', 'center', 'right' |\n| `valign` | string | `'top'` | Vertical: 'top', 'centre', 'center', 'bottom' |\n\n---\n\n## Format-Specific Options\n\n### TIFF (options.tiff)\n- `subifd` (number, default -1): OME-TIFF sub-image directory index\n\n### SVG (options.svg)\n- `stylesheet` (string): Custom CSS applied during cascade\n- `highBitdepth` (boolean, default false): 32-bit/channel vs. 8-bit/channel\n\n### PDF (options.pdf)\n- `background` (string | Object): Transparent area fill color\n\n### OpenSlide (options.openSlide)\n- `level` (number, default 0): Multi-level extraction index\n\n### JPEG 2000 (options.jp2)\n- `oneshot` (boolean, default false): Single-operation tiled decoding\n\n---\n\n## clone()\n\n**Signature:** `clone() ⇒ Sharp`\n\nReturns new instance sharing parent's input. Enables multiple independent output pipelines from a single input stream.\n\n**Usage:** Attach different transformations (resize, extract, etc.) to cloned instances for parallel processing.","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-input","prompt":"Extract ALL input API details: every method signature, every parameter name with type, default value, and description. Include all options object properties, return types, examples, and any notes or constraints. Be exhaustive - I need every single method, parameter and option documented."},"toolUseId":"toolu_01DrqbKC8ib5LUQf5ETHii8y","output":"# Sharp Input Metadata API\n\nBased on the documentation provided, here are the input API details:\n\n## metadata() Method\n\n**Signature:** `metadata([callback]) ⇒ Promise.<Object> | Sharp`\n\n**Purpose:** Fast access to uncached image metadata without decompressing pixel data.\n\n**Parameters:**\n- `callback` (optional, function): Called with arguments `(err, metadata)`\n\n**Return Value:** Promise resolving to metadata object (or Sharp instance if callback provided)\n\n**Metadata Object Properties:**\n- `format` (string): Decoder name (jpeg, png, webp, gif, svg)\n- `size` (number): Total image bytes (Stream/Buffer input only)\n- `width`, `height` (number): Pixel dimensions\n- `space` (string): Color space (srgb, rgb, cmyk, lab, b-w, etc.)\n- `channels` (number): Band count (e.g., 3 for sRGB, 4 for CMYK)\n- `depth` (string): Pixel format (uchar, char, ushort, float, etc.)\n- `density` (number): DPI if present\n- `chromaSubsampling` (string): JPEG subsampling (4:2:0 or 4:4:4)\n- `isProgressive`, `isPalette` (boolean): Image encoding properties\n- `bitsPerSample` (number): Bits per channel\n- `pages`, `pageHeight`, `loop`, `delay` (number/array): Animation data\n- `hasAlpha`, `hasProfile`, `isOpaque` (boolean): Image properties\n- `orientation` (number): EXIF orientation value\n- `exif`, `icc`, `iptc`, `xmp`, `xmpAsString` (buffer/string): Metadata buffers\n- `dominant` (object): Dominant sRGB color from histogram\n\n---\n\n## stats() Method\n\n**Signature:** `stats([callback]) ⇒ Promise.<Object>`\n\n**Purpose:** Access pixel-derived statistics for every channel.\n\n**Parameters:**\n- `callback` (optional, function): Called with arguments `(err, stats)`\n\n**Return Value:** Promise resolving to statistics object\n\n**Statistics Object Properties:**\n- `channels` (array): Per-channel stats including min, max, sum, squaresSum, mean, stdev, minX, minY, maxX, maxY\n- `isOpaque` (boolean): True if fully opaque or no alpha channel\n- `entropy` (number): Greyscale entropy estimation\n- `sharpness` (number): Laplacian-based sharpness estimation\n- `dominant` (object): Most dominant sRGB color\n\n**Important Note:** Statistics derive from original input; operations must be written to buffer first.","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-output","prompt":"Extract ALL output API details: every method (toFile, toBuffer, toFormat, jpeg, png, webp, avif, tiff, gif, heif, jxl, raw, tile, timeout, keepExif, withExif, keepIccProfile, withIccProfile, keepMetadata, withMetadata) with their complete signatures, every parameter name with type, default value, and description. Include all options, return types, examples, and constraints. Be exhaustive."},"toolUseId":"toolu_01862oHWpgFywdRg63axkB3Y","output":"# Sharp Output API Documentation\n\n## Core Output Methods\n\n### toFile(fileOut, [callback])\n**Returns:** `Promise.<Object>`\n\nWrites output to a filesystem path. Format inferred from extension (.jpg, .png, .webp, .avif, .tiff, .gif, .dzi, .v supported).\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| fileOut | string | Target file path |\n| [callback] | function | Optional callback(err, info) |\n\n**Info object contains:** format, size (bytes), width, height, channels, premultiplied, cropOffsetLeft, cropOffsetTop (if cropped), attentionX/Y (attention crop), pageHeight/pages (animated), textAutofitDpi (text output)\n\n---\n\n### toBuffer([options], [callback])\n**Returns:** `Promise.<Buffer>`\n\nOutputs to Buffer. Supports JPEG, PNG, WebP, AVIF, TIFF, GIF, raw pixel data.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| [options] | Object | | |\n| [options.resolveWithObject] | boolean | false | Resolve with {data, info} instead of raw data |\n| [callback] | function | | Optional callback(err, data, info) |\n\n---\n\n## Format-Specific Methods\n\n### toFormat(format, options)\n**Returns:** `Sharp`\n\nForces output to specified format.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| format | string \\| Object | Format ID or object with 'id' property |\n| options | Object | Format-specific options |\n\n---\n\n### jpeg([options])\n**Returns:** `Sharp`\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| quality | number | 80 | 1-100 |\n| progressive | boolean | false | Interlaced scan |\n| chromaSubsampling | string | '4:2:0' | '4:4:4' prevents subsampling |\n| optimiseCoding / optimizeCoding | boolean | true | Huffman optimization |\n| mozjpeg | boolean | false | Enables trellis, overshoot, optimised scans, table 3 |\n| trellisQuantisation | boolean | false | |\n| overshootDeringing | boolean | false | |\n| optimiseScans / optimizeScans | boolean | false | Forces progressive |\n| quantisationTable / quantizationTable | number | 0 | 0-8 |\n| force | boolean | true | Force JPEG even if input differs |\n\n---\n\n### png([options])\n**Returns:** `Sharp`\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| progressive | boolean | false | Interlaced |\n| compressionLevel | number | 6 | zlib 0-9 |\n| adaptiveFiltering | boolean | false | Row filtering |\n| palette | boolean | false | Palette-based with alpha |\n| quality | number | 100 | Lowest colors for quality (enables palette) |\n| effort | number | 7 | 1-10 CPU effort (enables palette) |\n| colours / colors | number | 256 | Max palette entries (enables palette) |\n| dither | number | 1.0 | Floyd-Steinberg diffusion (enables palette) |\n| force | boolean | true | |\n\n---\n\n### webp([options])\n**Returns:** `Sharp`\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| quality | number | 80 | 1-100 |\n| alphaQuality | number | 100 | 0-100 alpha layer |\n| lossless | boolean | false | |\n| nearLossless | boolean | false | |\n| smartSubsample | boolean | false | High-quality chroma |\n| smartDeblock | boolean | false | Auto deblock (slow) |\n| preset | string | 'default' | default, photo, picture, drawing, icon, text |\n| effort | number | 4 | 0-6 CPU effort |\n| loop | number | 0 | Animation iterations (0=infinite) |\n| delay | number \\| Array.<number> | | Frame delays (ms) |\n| minSize | boolean | false | Minimize via key frames (slow) |\n| mixed | boolean | false | Lossy/lossless mix (slow) |\n| force | boolean | true | |\n\n---\n\n### gif([options])\n**Returns:** `Sharp` *(Since v0.30.0)*\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| reuse | boolean | true | Reuse input palette |\n| progressive | boolean | false | Interlaced |\n| colours / colors | number | 256 | 2-256 entries |\n| effort | number | 7 | 1-10 |\n| dither | number | 1.0 | 0-1 Floyd-Steinberg |\n| interFrameMaxError | number | 0 | 0-32 transparency error |\n| interPaletteMaxError | number | 3 | 0-256 palette reuse error |\n| keepDuplicateFrames | boolean | false | Keep duplicate frames |\n| loop | number | 0 | Animation (0=infinite) |\n| delay | number \\| Array.<number> | | Frame delays (ms) |\n| force | boolean | true | |\n\n---\n\n### avif([options])\n**Returns:** `Sharp` *(Since v0.27.0)*\n\nImage sequences unsupported. Prebuilt binaries: 8-bit only. Experimental on Windows ARM64 (requires ARM64v8.4+).\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| quality | number | 50 | 1-100 |\n| lossless | boolean | false | |\n| effort | number | 4 | 0-9 |\n| chromaSubsampling | string | '4:4:4' | '4:2:0' option |\n| bitdepth | number | 8 | 8, 10, or 12 bit |\n\n---\n\n### heif(options)\n**Returns:** `Sharp` *(Since v0.23.0)*\n\nRequires global libvips with libheif, libde265, x265 for HEIC (patent-encumbered).\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| compression | string | required | av1 or hevc |\n| quality | number | 50 | 1-100 |\n| lossless | boolean | false | |\n| effort | number | 4 | 0-9 |\n| chromaSubsampling | string | '4:4:4' | '4:2:0' option |\n| bitdepth | number | 8 | 8, 10, or 12 bit |\n\n---\n\n### jp2([options])\n**Returns:** `Sharp` *(Since v0.29.1)*\n\nRequires custom libvips with OpenJPEG; prebuilt binaries exclude this.\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| quality | number | 80 | 1-100 |\n| lossless | boolean | false | |\n| tileWidth | number | 512 | Horizontal tile |\n| tileHeight | number | 512 | Vertical tile |\n| chromaSubsampling | string | '4:4:4' | '4:2:0' option |\n\n---\n\n### tiff([options])\n**Returns:** `Sharp`\n\nDensity via [withMetadata](#withmetadata) instead of xres/yres.\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| quality | number | 80 | 1-100 |\n| force | boolean | true | |\n| compression | string | 'jpeg' | none, jpeg, deflate, packbits, ccittfax4, lzw, webp, zstd, jp2k |\n| bigtiff | boolean | false | BigTIFF variant |\n| predictor | string | 'horizontal' | none, horizontal, float |\n| pyramid | boolean | false | Image pyramid |\n| tile | boolean | false | Tiled TIFF |\n| tileWidth | number | 256 | |\n| tileHeight | number | 256 | |\n| xres | number | 1.0 | pixels/mm |\n| yres | number | 1.0 | pixels/mm |\n| resolutionUnit | string | 'inch' | inch, cm |\n| bitdepth | number | 8 | 1, 2, or 4 bit |\n| miniswhite | boolean | false | 1-bit as miniswhite |\n\n---\n\n### jxl([options])\n**Returns:** `Sharp` *(Since v0.31.3)*\n\n**Experimental—do not use in production.** Requires custom libvips with libjxl; prebuilt binaries exclude this.\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| distance | number | 1.0 | 0-15 max encoding error |\n| quality | number | | 1-100 (overrides distance) |\n| decodingTier | number | 0 | 0-4 decode speed |\n| lossless | boolean | false | |\n| effort | number | 7 | 1-9 |\n| loop | number | 0 | Animation (0=infinite) |\n| delay | number \\| Array.<number> | | Frame delays (ms) |\n\n---\n\n### raw([options])\n**Returns:** `Sharp`\n\nUncompressed pixel data, left-to-right, top-to-bottom, no padding. RGB/RGBA for non-greyscale.\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| [options.depth] | string | 'uchar' | char, uchar, short, ushort, int, uint, float, complex, double, dpcomplex |\n\n---\n\n### tile([options])\n**Returns:** `Sharp`\n\nTile-based deep zoom (pyramid). Set format via toFormat, jpeg, png, or webp. Use .zip/.szi extension with toFile for archive.\n\n| Option | Type | Default | Notes |\n|--------|------|---------|-------|\n| size | number | 256 | 1-8192 pixels |\n| overlap | number | 0 | 0-8192 pixels |\n| angle | number | 0 | Multiple of 90 |\n| background | string \\| Object | \"{r:255, g:255, b:255, alpha:1}\" | Parsed by color module |\n| depth | string | | onepixel, onetile, or one |\n| skipBlanks | number | -1 / 5 | 0-255 (8-bit) or 0-65535 (16-bit); 5 for google layout, -1 default |\n| container | string | 'fs' | fs or zip |\n| layout | string | 'dz' | dz, iiif, iiif3, zoomify, google |\n| centre / center | boolean | false | Centre image |\n| id | string | 'https://example.com/iiif' | IIIF @id/id attribute |\n| basename | string | | Name in zip directory |\n\n---\n\n### timeout(options)\n**Returns:** `Sharp` *(Since v0.29.2)*\n\nSets processing timeout starting when libvips opens input. Thread wait time excluded.\n\n| Option | Type | Description |\n|--------|------|-------------|\n| options.seconds | number | 0 = indefinite (default) |\n\n---\n\n## Metadata Handling Methods\n\n### keepExif()\n**Returns:** `Sharp` *(Since v0.33.0)*\n\nPreserves all EXIF metadata. Unsupported for TIFF output.\n\n---\n\n### withExif(exif)\n**Returns:** `Sharp` *(Since v0.33.0)*\n\nSets EXIF metadata, ignoring input EXIF.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| exif | Object.<string, Object.<string, string>> | Keys: IFD0, IFD1, IFD3, etc.; values are key/value string pairs |\n\n---\n\n### withExifMerge(exif)\n**Returns:** `Sharp` *(Since v0.33.0)*\n\nUpdates/merges EXIF metadata with input image's EXIF.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| exif | Object.<string, Object.<string, string>> | Keys: IFD0, IFD1, etc. |\n\n---\n\n### keepIccProfile()\n**Returns:** `Sharp` *(Since v0.33.0)*\n\nPreserves ICC profile. Use with [toColourspace](/api-colour/#tocolourspace) and optionally [pipelineColourspace](/api-colour/#pipelinecolourspace) when input/output colour spaces differ.\n\n---\n\n### withIccProfile(icc, [options])\n**Returns:** `Sharp` *(Since v0.33.0)*\n\nTransforms using ICC profile and attaches to output.\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| icc | string | | Filesystem path or built-in (srgb, p3, cmyk) |\n| [options] | Object | | |\n| [options.attach] | number | true | Include profile in metadata |\n\n---\n\n### keepXmp()\n**Returns:** `Sharp` *(Since v0.34.3)*\n\nPreserves XMP metadata.\n\n---\n\n### withXmp(xmp)\n**Returns:** `Sharp` *(Since v0.34.3)*\n\nSets XMP metadata. Supported by PNG, JPEG, WebP, TIFF output.\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| xmp | string | XMP XML string to embed |\n\n---\n\n### keepMetadata()\n**Returns:** `Sharp` *(Since v0.33.0)*\n\nPreserves all metadata (EXIF, ICC, XMP, IPTC). Default behavior strips all metadata and converts to sRGB.\n\n---\n\n### withMetadata([options])\n**Returns:** `Sharp`\n\nPreserves most metadata (EXIF, XMP, IPTC) and adds sRGB ICC profile when appropriate.\n\n| Option | Type | Description |\n|--------|------|-------------|\n| [options.orientation] | number | EXIF Orientation tag (1-8) |\n| [options.density] | number | Pixels per inch (DPI) |\n\n---\n\n## Summary Table\n\n| Method | Returns | Key Purpose |\n|--------|---------|-------------|\n| toFile | Promise.<Object> | Write to filesystem |\n| toBuffer | Promise.<Buffer> | Write to memory |\n| toFormat | Sharp | Force format |\n| jpeg, png, webp, gif, avif, heif, jp2, tiff, jxl | Sharp | Format options |\n| raw | Sharp | Uncompressed pixels |\n| tile | Sharp | Deep zoom pyramid |\n| timeout | Sharp | Processing timeout |\n| keepExif, withExif, withExifMerge | Sharp | EXIF control |\n| keepIccProfile, withIccProfile | Sharp | ICC color profile |\n| keepXmp, withXmp | Sharp | XMP metadata |\n| keepMetadata, withMetadata | Sharp | All/most metadata |","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-resize","prompt":"Extract ALL resize API details: every method signature, every parameter name with type, default value, and description. Include all options like width, height, fit, position, kernel, withoutEnlargement, withoutReduction, fastShrinkOnLoad. Include return types, examples, and constraints. Be exhaustive."},"toolUseId":"toolu_0189nieTWiR41FkNxLx9VwFg","output":"# Sharp Resize API: Complete Reference\n\n## resize() Method\n\n**Signature:** `resize([width], [height], [options]) ⇒ Sharp`\n\n**Purpose:** Adjusts image dimensions to specified width, height, or both.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `[width]` | number | — | Target width in pixels; use `null`/`undefined` to auto-scale based on height |\n| `[height]` | number | — | Target height in pixels; use `null`/`undefined` to auto-scale based on width |\n| `[options]` | Object | — | Configuration object for advanced control |\n\n### Options Object\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `width` | number | — | Alternative width specification; takes priority if both methods used |\n| `height` | number | — | Alternative height specification; takes priority if both methods used |\n| `fit` | string | `'cover'` | Scaling strategy: `cover`, `contain`, `fill`, `inside`, `outside` |\n| `position` | string | `'centre'` | Placement for `cover`/`contain`: cardinal/intercardinal directions or gravity terms |\n| `background` | string/Object | `{r:0,g:0,b:0,alpha:1}` | Fill color for `contain` fit; parsed by color module |\n| `kernel` | string | `'lanczos3'` | Reduction kernel: `nearest`, `linear`, `cubic`, `mitchell`, `lanczos2`, `lanczos3`, `mks2013`, `mks2021` |\n| `withoutEnlargement` | boolean | `false` | Prevents upscaling when dimensions already meet targets |\n| `withoutReduction` | boolean | `false` | Prevents downscaling when dimensions exceed targets |\n| `fastShrinkOnLoad` | boolean | `true` | Leverages JPEG/WebP shrink-on-load; may cause minor moiré or rounding |\n\n### Fit Modes\n\n- **cover:** Preserves aspect ratio; crops to fill both dimensions\n- **contain:** Preserves aspect ratio; letterboxes to fit within dimensions\n- **fill:** Ignores aspect ratio; stretches to exact dimensions\n- **inside:** Preserves aspect ratio; maximizes size without exceeding dimensions\n- **outside:** Preserves aspect ratio; minimizes size while meeting minimum dimensions\n\n### Position/Gravity Values\n\nPosition: `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`\n\nGravity: `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `center`/`centre`\n\nStrategy (cover only): `entropy` (Shannon entropy focus) or `attention` (luminance/saturation/skin tone focus)\n\n### Return Type\n`Sharp` (chainable)\n\n### Throws\n`Error` for invalid parameters\n\n### Key Constraints\n\n- Only one resize operation per pipeline; subsequent calls ignored\n- Operations order: resize occurs after extraction/trim, before extend\n- Upsampling kernels map: `nearest`, `linear`, `cubic` direct; others map to `cubic`\n\n---\n\n## extend() Method\n\n**Signature:** `extend(extend) ⇒ Sharp`\n\n**Purpose:** Adds padding/extrusion to image edges with background color or derived pixels.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `extend` | number/Object | — | Uniform edge count or per-edge configuration |\n\n### Options (as Object)\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `top` | number | 0 | Pixels to add above image |\n| `left` | number | 0 | Pixels to add to left |\n| `bottom` | number | 0 | Pixels to add below |\n| `right` | number | 0 | Pixels to add to right |\n| `extendWith` | string | `'background'` | Population method: `background`, `copy`, `repeat`, `mirror` |\n| `background` | string/Object | `{r:0,g:0,b:0,alpha:1}` | Fill color; parsed by color module |\n\n### Return Type\n`Sharp` (chainable)\n\n### Execution Order\nAlways applies after resize and extract operations\n\n---\n\n## extract() Method\n\n**Signature:** `extract(options) ⇒ Sharp`\n\n**Purpose:** Crops a rectangular region from the image.\n\n### Parameters\n\n| Parameter | Type | Description |\n|-----------|------|-------------|\n| `options` | Object | Region definition |\n| `options.left` | number | Zero-indexed horizontal offset |\n| `options.top` | number | Zero-indexed vertical offset |\n| `options.width` | number | Region width |\n| `options.height` | number | Region height |\n\n### Return Type\n`Sharp` (chainable)\n\n### Usage Patterns\n\n- **Pre-resize:** Call before `resize()` for initial cropping\n- **Post-resize:** Call after `resize()` for final cropping\n- **Sandwich:** Call twice around `resize()` for extract-resize-extract workflow\n\n---\n\n## trim() Method\n\n**Signature:** `trim([options]) ⇒ Sharp`\n\n**Purpose:** Removes edge pixels matching background color similarity threshold.\n\n### Parameters\n\n| Parameter | Type | Default | Description |\n|-----------|------|---------|-------------|\n| `[options]` | Object | — | Configuration object |\n| `options.background` | string/Object | `'top-left pixel'` | Reference color; parsed by color module |\n| `options.threshold` | number | 10 | Tolerance for color matching (positive number) |\n| `options.lineArt` | boolean | `false` | Optimizes for vector/line art rather than photography |\n\n### Return Type\n`Sharp` (chainable)\n\n### Behavior\n\n- Alpha channel images use combined bounding box of both channels\n- No trimming occurs if result would eliminate entire image\n- Response `info` includes `trimOffsetLeft` and `trimOffsetTop` properties","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-operation","prompt":"Extract ALL operation API details: every method (rotate, flip, flop, affine, sharpen, median, blur, flatten, unflatten, gamma, negate, normalise, normalize, clahe, convolve, threshold, boolean, linear, recomb, modulate, extend, extract, trim) with complete signatures, every parameter with type, default, description. Include return types, examples, constraints. Be exhaustive."},"toolUseId":"toolu_01Dt5mqoHT7iWgKz4GeCcRAN","output":"# Sharp Image Operations API Reference\n\n## Complete Method Signatures\n\n### rotate\n**Signature:** `rotate([angle], [options]) ⇒ Sharp`\n\n- **angle** (number, default: `auto`): Rotation angle in degrees\n- **options.background** (string|Object, default: `\"#000000\"`): Background color parsed by color module\n- **Returns:** Sharp instance\n- **Constraint:** Only one rotation per pipeline; previous calls ignored\n- **Note:** Converts angles to valid positive rotation (e.g., -450° → 270°)\n\n### autoOrient\n**Signature:** `autoOrient() ⇒ Sharp`\n\n- **Returns:** Sharp instance\n- **Behavior:** \"Auto-orient based on the EXIF `Orientation` tag, then remove the tag\"\n- **Note:** Mirroring inferred from EXIF data\n\n### flip\n**Signature:** `flip([flip]) ⇒ Sharp`\n\n- **flip** (boolean, default: `true`): Enable vertical mirroring\n- **Returns:** Sharp instance\n- **Behavior:** \"Mirror the image vertically (up-down) about the x-axis\"\n- **Constraint:** Does not work correctly with multi-page images\n\n### flop\n**Signature:** `flop([flop]) ⇒ Sharp`\n\n- **flop** (boolean, default: `true`): Enable horizontal mirroring\n- **Returns:** Sharp instance\n- **Behavior:** \"Mirror the image horizontally (left-right) about the y-axis\"\n\n### affine\n**Signature:** `affine(matrix, [options]) ⇒ Sharp`\n\n- **matrix** (Array of numbers|2D array): Transformation matrix (length 4 or 2x2)\n- **options.background** (string|Object, default: `\"#000000\"`): Fill color\n- **options.idx** (number, default: `0`): Input horizontal offset\n- **options.idy** (number, default: `0`): Input vertical offset\n- **options.odx** (number, default: `0`): Output horizontal offset\n- **options.ody** (number, default: `0`): Output vertical offset\n- **options.interpolator** (string, default: `sharp.interpolators.bicubic`): Interpolation method\n- **Returns:** Sharp instance\n- **Constraint:** Occurs after resizing, extraction, rotation\n\n### sharpen\n**Signature:** `sharpen([options], [flat], [jagged]) ⇒ Sharp`\n\n- **options** (object|number): Configuration object\n - **sigma** (number, 0.00000110): Gaussian mask sigma where `sigma = 1 + radius / 2`\n - **m1** (number, default: `1.0`, 01000000): Flat area sharpening level\n - **m2** (number, default: `2.0`, 01000000): Jagged area sharpening level\n - **x1** (number, default: `2.0`, 01000000): Flat/jagged threshold\n - **y2** (number, default: `10.0`, 01000000): Max brightening\n - **y3** (number, default: `20.0`, 01000000): Max darkening\n- **flat** (number, deprecated): Use `options.m1`\n- **jagged** (number, deprecated): Use `options.m2`\n- **Returns:** Sharp instance\n\n### median\n**Signature:** `median([size]) ⇒ Sharp`\n\n- **size** (number, default: `3`): Square mask dimension (size × size)\n- **Returns:** Sharp instance\n- **Behavior:** Applies median filtering with default 3×3 window\n\n### blur\n**Signature:** `blur([options]) ⇒ Sharp`\n\n- **options** (object|number|boolean):\n - **sigma** (number, 0.31000): Gaussian blur sigma\n - **precision** (string, default: `\"integer\"`): One of `integer`, `float`, `approximate`\n - **minAmplitude** (number, default: `0.2`, 0.0011): Mask accuracy control\n- **Returns:** Sharp instance\n- **Behavior:** Without parameters performs 3×3 box blur; with sigma performs Gaussian blur\n\n### dilate\n**Signature:** `dilate([width]) ⇒ Sharp`\n\n- **width** (number, default: `1`): Dilation width in pixels\n- **Returns:** Sharp instance\n- **Behavior:** \"Expand foreground objects using the dilate morphological operator\"\n\n### erode\n**Signature:** `erode([width]) ⇒ Sharp`\n\n- **width** (number, default: `1`): Erosion width in pixels\n- **Returns:** Sharp instance\n- **Behavior:** \"Shrink foreground objects using the erode morphological operator\"\n\n### flatten\n**Signature:** `flatten([options]) ⇒ Sharp`\n\n- **options.background** (string|Object, default: `{r: 0, g: 0, b: 0}`): Background color\n- **Returns:** Sharp instance\n- **Behavior:** \"Merge alpha transparency channel, if any, with a background, then remove the alpha channel\"\n\n### unflatten\n**Signature:** `unflatten() ⇒ Sharp`\n\n- **Returns:** Sharp instance\n- **Behavior:** \"Ensure the image has an alpha channel with all white pixel values made fully transparent\"\n- **Status:** Experimental API\n\n### gamma\n**Signature:** `gamma([gamma], [gammaOut]) ⇒ Sharp`\n\n- **gamma** (number, default: `2.2`, 1.03.0): Gamma correction factor\n- **gammaOut** (number, 1.03.0): Output gamma (defaults to `gamma` if omitted)\n- **Returns:** Sharp instance\n- **Note:** JPEG/WebP inputs lose shrink-on-load optimization\n\n### negate\n**Signature:** `negate([options]) ⇒ Sharp`\n\n- **options.alpha** (boolean, default: `true`): Whether to negate alpha channel\n- **Returns:** Sharp instance\n- **Behavior:** Produces image negative\n\n### normalise\n**Signature:** `normalise([options]) ⇒ Sharp`\n\n- **options.lower** (number, default: `1`): Percentile threshold for underexposure\n- **options.upper** (number, default: `99`): Percentile threshold for overexposure\n- **Returns:** Sharp instance\n- **Behavior:** \"Enhance output image contrast by stretching its luminance to cover a full dynamic range\"\n\n### normalize\n**Signature:** `normalize([options]) ⇒ Sharp`\n\nAlternative American spelling of `normalise` with identical parameters and behavior.\n\n### clahe\n**Signature:** `clahe(options) ⇒ Sharp`\n\n- **options.width** (number, required): Search window integral width in pixels\n- **options.height** (number, required): Search window integral height in pixels\n- **options.maxSlope** (number, default: `3`, 0100): Brightening level (0 disables limiting)\n- **Returns:** Sharp instance\n- **Behavior:** \"Perform contrast limiting adaptive histogram equalization [CLAHE]\"\n\n### convolve\n**Signature:** `convolve(kernel) ⇒ Sharp`\n\n- **kernel.width** (number, required): Kernel width in pixels\n- **kernel.height** (number, required): Kernel height in pixels\n- **kernel.kernel** (array, required): Array of width×height values\n- **kernel.scale** (number, default: `sum`): Kernel scale\n- **kernel.offset** (number, default: `0`): Kernel offset\n- **Returns:** Sharp instance\n\n### threshold\n**Signature:** `threshold([threshold], [options]) ⇒ Sharp`\n\n- **threshold** (number, default: `128`, 0255): Threshold level\n- **options.greyscale** (boolean, default: `true`): Convert to single-channel grayscale\n- **options.grayscale** (boolean, default: `true`): Alternative spelling\n- **Returns:** Sharp instance\n- **Behavior:** Pixels ≥ threshold become 255; others become 0\n\n### boolean\n**Signature:** `boolean(operand, operator, [options]) ⇒ Sharp`\n\n- **operand** (Buffer|string): Image data or file path\n- **operator** (string): One of `and`, `or`, `eor` (bitwise operations)\n- **options.raw** (object): Raw pixel metadata\n - **raw.width** (number): Operand width\n - **raw.height** (number): Operand height\n - **raw.channels** (number): Channel count\n- **Returns:** Sharp instance\n\n### linear\n**Signature:** `linear([a], [b]) ⇒ Sharp`\n\n- **a** (number|array, default: `[]`): Multiplier per channel\n- **b** (number|array, default: `[]`): Offset per channel\n- **Returns:** Sharp instance\n- **Formula:** `a * input + b`\n- **Note:** Array lengths must match channel count\n\n### recomb\n**Signature:** `recomb(inputMatrix) ⇒ Sharp`\n\n- **inputMatrix** (3×3 or 4×4 array): Recombination matrix\n- **Returns:** Sharp instance\n- **Example usage:** Sepia filter via color matrix transformation\n\n### modulate\n**Signature:** `modulate([options]) ⇒ Sharp`\n\n- **options.brightness** (number): Multiplicative brightness factor\n- **options.saturation** (number): Saturation multiplier\n- **options.hue** (number): Hue rotation in degrees\n- **options.lightness** (number): Additive lightness value\n- **Returns:** Sharp instance\n- **Note:** \"Brightness and lightness both operate on luminance, with the difference being that brightness is multiplicative whereas lightness is additive\"\n\n---\n\n**Note:** The provided documentation does not include `extend`, `extract`, or `trim` operations. Only the 22 explicitly documented methods are detailed above.","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-colour","prompt":"Extract ALL colour/color API details: every method (tint, greyscale, grayscale, pipelineColourspace, pipelineColorspace, toColourspace, toColorspace) with complete signatures, every parameter with type, default, description. Include return types, examples, constraints, available colourspace values. Be exhaustive."},"toolUseId":"toolu_01XgLfXm9vKeuiQ7nFRXior7","output":"# Sharp Colour/Color API Reference\n\n## Complete Method Signatures\n\n### tint()\n**Signature:** `tint(tint) ⇒ Sharp`\n\n**Parameter:**\n- `tint` (string | Object): Color specification parsed by the color module\n\n**Behavior:** Applies tint to images while preserving alpha channels\n\n**Example:**\n```javascript\nconst output = await sharp(input)\n .tint({ r: 255, g: 240, b: 16 })\n .toBuffer();\n```\n\n**Throws:** Error on invalid parameters\n\n---\n\n### greyscale() / grayscale()\n**Signature:** `greyscale([greyscale]) ⇒ Sharp`\n\n**Parameter:**\n- `[greyscale]` (Boolean, default: true): Enable/disable conversion\n\n**Behavior:** Converts to \"8-bit greyscale; 256 shades of grey\" using linear operation. Output defaults to web-friendly sRGB with three identical color channels unless overridden. Alpha channels remain unchanged.\n\n**Note:** Documentation advises using `gamma()` with greyscale for non-linear source spaces like sRGB\n\n**Example:**\n```javascript\nconst output = await sharp(input).greyscale().toBuffer();\n```\n\n---\n\n### pipelineColourspace() / pipelineColorspace()\n**Signature:** `pipelineColourspace([colourspace]) ⇒ Sharp`\n\n**Parameter:**\n- `[colourspace]` (string): Pipeline colorspace identifier\n\n**Valid Values:** `rgb16`, `scrgb`, `lab`, `grey16` (see [libvips Interpretation enum](https://www.libvips.org/API/current/enum.Interpretation.html))\n\n**Behavior:** Sets conversion point at pipeline start; all operations execute in specified space before final output conversion\n\n**Since:** v0.29.0\n\n**Example:**\n```javascript\nawait sharp(input)\n .pipelineColourspace('rgb16')\n .toColourspace('srgb')\n .toFile('16bpc-pipeline-to-8bpc-output.png');\n```\n\n**Throws:** Error on invalid parameters\n\n---\n\n### toColourspace() / toColorspace()\n**Signature:** `toColourspace([colourspace]) ⇒ Sharp`\n\n**Parameter:**\n- `[colourspace]` (string): Output colorspace identifier\n\n**Valid Values:** `srgb`, `rgb`, `cmyk`, `lab`, `b-w` (see [libvips Interpretation enum](https://www.libvips.org/API/current/enum.Interpretation.html))\n\n**Default Behavior:** Web-friendly sRGB with additional channels as alpha\n\n**Example:**\n```javascript\nawait sharp(input)\n .toColourspace('rgb16')\n .toFile('16-bpp.png');\n```\n\n**Throws:** Error on invalid parameters","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-channel","prompt":"Extract ALL channel API details: every method (removeAlpha, ensureAlpha, extractChannel, joinChannel, bandbool) with complete signatures, every parameter with type, default, description. Include return types, examples, constraints. Be exhaustive."},"toolUseId":"toolu_012WAjbmb2vFSSDTNmXMcFjX","output":"# Sharp Channel Manipulation API Details\n\n## removeAlpha()\n**Signature:** `removeAlpha() ⇒ Sharp`\n\n**Description:** Eliminates alpha channels from images. Acts as a no-operation if no alpha channel exists.\n\n**Parameters:** None\n\n**Return Type:** Sharp\n\n**Example:**\n```javascript\nsharp('rgba.png').removeAlpha().toFile('rgb.png')\n```\n\n---\n\n## ensureAlpha()\n**Signature:** `ensureAlpha([alpha]) ⇒ Sharp`\n\n**Parameters:**\n- `alpha` (number, optional, default: 1) — \"alpha transparency level (0=fully-transparent, 1=fully-opaque)\"\n\n**Return Type:** Sharp\n\n**Throws:** Error for invalid alpha transparency levels\n\n**Since:** v0.21.2\n\n**Examples:**\n```javascript\nawait sharp('rgb.jpg').ensureAlpha().toFile('rgba.png')\nawait sharp(rgb).ensureAlpha(0).toBuffer()\n```\n\n---\n\n## extractChannel()\n**Signature:** `extractChannel(channel) ⇒ Sharp`\n\n**Parameters:**\n- `channel` (number | string) — \"zero-indexed channel/band number to extract, or `red`, `green`, `blue` or `alpha`\"\n\n**Return Type:** Sharp\n\n**Output Colorspace:** b-w (8-bit) or grey16 (16-bit)\n\n**Throws:** Error for invalid channel selection\n\n**Examples:**\n```javascript\nawait sharp(input).extractChannel('green').toFile('green.jpg')\nconst [red1, red2, ...] = await sharp(input).extractChannel(0).raw().toBuffer()\n```\n\n---\n\n## joinChannel()\n**Signature:** `joinChannel(images, options) ⇒ Sharp`\n\n**Parameters:**\n- `images` (string | Buffer | Array) — one or more image sources\n- `options` (Object) — image options matching sharp() constructor format\n\n**Return Type:** Sharp\n\n**Channel Ordering:**\n- sRGB: Red (0), Green (1), Blue (2), Alpha (3)\n- CMYK: Magenta (0), Cyan (1), Yellow (2), Black (3), Alpha (4)\n\n**Throws:** Error for invalid parameters\n\n---\n\n## bandbool()\n**Signature:** `bandbool(boolOp) ⇒ Sharp`\n\n**Parameters:**\n- `boolOp` (string) — \"one of `and`, `or` or `eor` to perform that bitwise operation\"\n\n**Return Type:** Sharp\n\n**Output:** Single-channel image from bitwise operations across all input bands\n\n**Throws:** Error for invalid parameters\n\n**Example:**\n```javascript\nsharp('3-channel-rgb-input.png').bandbool(sharp.bool.and).toFile('1-channel-output.png')\n```","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-composite","prompt":"Extract ALL composite API details: the composite method signature, every parameter and option (input, blend, gravity, top, left, tile, premultiplied, density, raw, animated, failOn, limitInputPixels, create), all blend mode values, return types, examples, constraints. Be exhaustive."},"toolUseId":"toolu_01L2R8u1245kZGV8csxnxgkA","output":"# Sharp Compositing API Reference\n\n## Method Signature\n```\ncomposite(images) ⇒ Sharp\n```\n\n## Core Description\n\"Composite image(s) over the processed (resized, extracted etc.) image.\" Images must be same size or smaller than the processed image.\n\n## Parameter Structure\n\n**images**: Array of composite objects\n\n### Input Options\n- **input**: Buffer, file path string, or Create object\n - **create**: Blank overlay specification\n - width (Number)\n - height (Number)\n - channels (Number, 3-4)\n - background (String/Object) - parsed by color module\n - **text**: Text image creation\n - text (string) - UTF-8 with Pango markup support\n - font (string) - font name\n - fontfile (string) - absolute filesystem path\n - width (number, default: 0) - word-wrap pixels\n - height (number, default: 0) - pixel height\n - align (string, default: 'left') - 'left'/'centre'/'center'/'right'\n - justify (boolean, default: false)\n - dpi (number, default: 72) - render resolution\n - rgba (boolean, default: false) - RGBA output\n - spacing (number, default: 0) - line height in points\n\n### Positioning Options\n- **gravity** (String, default: 'centre') - overlay placement point\n- **top** (Number) - pixel offset from top\n- **left** (Number) - pixel offset from left\n*(top/left take precedence over gravity)*\n\n### Blending Options\n- **blend** (String, default: 'over') - compositing mode\n- **premultiplied** (Boolean, default: false) - avoid premultiplication\n\n### Rendering Options\n- **tile** (Boolean, default: false) - repeat across entire image\n- **density** (Number, default: 72) - DPI for vector overlays\n- **autoOrient** (Boolean, default: false) - apply EXIF orientation\n- **animated** (boolean, default: false) - read all frames\n- **raw** (Object) - raw pixel data specification\n - width, height, channels\n- **failOn** (string, default: 'warning')\n- **limitInputPixels** (number/boolean, default: 268402689)\n\n## Blend Modes (24 total)\n`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`\n\n## Constraints\n- \"Other operations in the same processing pipeline will always be applied to the input image before composition\"\n- Overlay images cannot exceed base image dimensions\n- Returns Sharp object for chaining\n\n## Available Since\nv0.22.0","isError":false},{"role":"tool","toolName":"WebFetch","toolInput":{"url":"https://sharp.pixelplumbing.com/api-utility","prompt":"Extract ALL utility API details: every method (metadata, stats, toBuffer, toFile) and static/module-level utilities (sharp.format, sharp.interpolators, sharp.versions, sharp.queue, sharp.cache, sharp.concurrency, sharp.counters, sharp.simd, sharp.block) with complete signatures, parameters, return types, output object shapes. Be exhaustive."},"toolUseId":"toolu_011oonVC49Ge9DwPPeW84Sfd","output":"# Sharp Utility API Reference\n\n## Static/Module-Level Properties\n\n### `sharp.versions`\nReturns an Object containing version numbers of sharp, libvips, and dependencies.\n\n### `sharp.interpolators`\nRead-only enum Object with interpolation methods:\n- `nearest` (string): \"nearest\" - Nearest neighbour, enlargement only\n- `bilinear` (string): \"bilinear\" - Bilinear interpolation\n- `bicubic` (string): \"bicubic\" - Bicubic (default)\n- `locallyBoundedBicubic` (string): \"lbb\" - Prevents acutance\n- `nohalo` (string): \"nohalo\" - Prevents acutance, 3x slower\n- `vertexSplitQuadraticBasisSpline` (string): \"vsqbs\" - Prevents staircasing\n\n### `sharp.format`\nReturns Object with nested booleans representing available input/output formats.\n\n### `sharp.queue`\nEventEmitter emitting `change` events when tasks are queued or complete.\n\n## Static Methods\n\n### `sharp.cache([options])` → Object\nGets/sets libvips operation cache limits. Returns cache statistics.\n\n**Parameters:**\n- `[options]` (Object|boolean, default: true)\n - `[memory]` (number, default: 50) - Max MB for cache\n - `[files]` (number, default: 20) - Max open files\n - `[items]` (number, default: 100) - Max cached operations\n\n### `sharp.concurrency([concurrency])` → number\nGets/sets max threads per image. Default: CPU core count.\n\n**Parameters:**\n- `[concurrency]` (number) - Pass 0 to reset to core count\n\n### `sharp.counters()` → Object\nReturns internal task counters: `{queue: number, process: number}`\n\n### `sharp.simd([simd])` → boolean\nGets/sets SIMD vector unit usage (requires highway support).\n\n**Parameters:**\n- `[simd]` (boolean, default: true)\n\n### `sharp.block(options)`\nBlocks libvips operations at runtime (v0.32.4+).\n\n**Parameters:**\n- `options.operation` (Array<string>) - Operation names to block\n\n### `sharp.unblock(options)`\nUnblocks libvips operations at runtime (v0.32.4+).\n\n**Parameters:**\n- `options.operation` (Array<string>) - Operation names to unblock","isError":false},{"role":"assistant","text":"Now I have all the information needed. Let me write the SKILL.md file."},{"role":"tool","toolName":"Read","toolInput":{"file_path":"/home/pastilhas/projects/officer.dev/data/skills/sharp/SKILL.md"},"toolUseId":"toolu_01Rh3BKiE4hxRRVgULfUbTuR","output":" 1→---\n 2→name: sharp\n 3→description: \n 4→---\n 5→","isError":false},{"role":"tool","toolName":"Write","toolInput":{"file_path":"/home/pastilhas/projects/officer.dev/data/skills/sharp/SKILL.md","content":"---\nname: sharp\ndescription: Process images using the sharp Node.js library. Use when the user wants to resize, convert, crop, composite, transform, or optimize images programmatically.\n---\n\n# Sharp\n\nAPI reference for sharp — a high-performance Node.js image processing library built on libvips.\n\nTypically 4-5x faster than ImageMagick/GraphicsMagick. Supports JPEG, PNG, WebP, GIF, AVIF, TIFF, SVG, HEIF, JP2, and JXL.\n\nOfficial docs: https://sharp.pixelplumbing.com\nRepository: https://github.com/lovell/sharp\n\n## Installation\n\n```bash\nnpm install sharp\n```\n\nRequires Node.js ^18.17.0 or >= 20.3.0 (or Deno/Bun with Node-API v9).\n\n## Usage\n\nSharp uses a fluent, chainable API. Every call returns a Sharp instance.\n\n```js\nimport sharp from 'sharp';\n\nawait sharp('input.jpg')\n .resize(800, 600)\n .jpeg({ quality: 80 })\n .toFile('output.jpg');\n```\n\nSharp implements `stream.Duplex` — it can be piped to/from.\n\n---\n\n## Constructor\n\n```js\nsharp([input], [options])\n```\n\n- `input` (Buffer | string | Array): Image buffer, file path, array of inputs, or omit for stream input.\n\n### Options\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `failOn` | string | `'warning'` | `'none'`, `'truncated'`, `'error'`, `'warning'` |\n| `limitInputPixels` | number \\| boolean | `268402689` | Max pixels; `false` to disable |\n| `unlimited` | boolean | `false` | Remove memory safety for JPEG/PNG/SVG/HEIF |\n| `autoOrient` | boolean | `false` | Auto-rotate per EXIF Orientation |\n| `sequentialRead` | boolean | `true` | Sequential vs random access |\n| `density` | number | `72` | DPI for vector images (1-100000) |\n| `ignoreIcc` | boolean | `false` | Ignore embedded ICC profile |\n| `pages` | number | `1` | Pages to extract; `-1` for all |\n| `page` | number | `0` | Starting page (zero-based) |\n| `animated` | boolean | `false` | Read all frames (equiv. `pages: -1`) |\n\n### Raw Input\n\n```js\nsharp(buffer, { raw: { width: 100, height: 100, channels: 4 } })\n```\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `width` | number | Pixel width |\n| `height` | number | Pixel height |\n| `channels` | number | 1-4 |\n| `premultiplied` | boolean | Skip premultiplication (default `false`) |\n\n### Create New Image\n\n```js\nsharp({ create: { width: 300, height: 200, channels: 4, background: '#ff0000' } })\n```\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `width` | number | Pixel width |\n| `height` | number | Pixel height |\n| `channels` | number | 3 (RGB) or 4 (RGBA) |\n| `background` | string \\| Object | Color (parsed by color module) |\n| `noise` | Object | `{ type: 'gaussian', mean: 128, sigma: 30 }` |\n\n### Render Text\n\n```js\nsharp({ text: { text: 'Hello', font: 'Arial', dpi: 150 } })\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `text` | string | -- | UTF-8; supports Pango markup |\n| `font` | string | -- | Font name |\n| `fontfile` | string | -- | Absolute path to font file |\n| `width` | number | `0` | Word-wrap boundary; 0 = no wrap |\n| `height` | number | `0` | Max height |\n| `align` | string | `'left'` | `'left'`, `'centre'`, `'center'`, `'right'` |\n| `justify` | boolean | `false` | Text justification |\n| `dpi` | number | `72` | Render resolution |\n| `rgba` | boolean | `false` | RGBA for color emoji/Pango markup |\n| `spacing` | number | `0` | Line height in points |\n| `wrap` | string | `'word'` | `'word'`, `'char'`, `'word-char'`, `'none'` |\n\n### Join Array\n\n```js\nsharp([img1, img2, img3], { join: { across: 3, shim: 10 } })\n```\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `across` | number | `1` | Images per row |\n| `animated` | boolean | `false` | Join as animated image |\n| `shim` | number | `0` | Pixel gap between images |\n| `background` | string \\| Object | -- | Gap fill color |\n| `halign` | string | `'left'` | `'left'`, `'centre'`, `'right'` |\n| `valign` | string | `'top'` | `'top'`, `'centre'`, `'bottom'` |\n\n### Clone\n\n```js\nconst pipeline = sharp('input.jpg');\nconst clone1 = pipeline.clone().resize(200).toFile('thumb.jpg');\nconst clone2 = pipeline.clone().resize(800).toFile('large.jpg');\n```\n\n---\n\n## Resize\n\n```js\n.resize([width], [height], [options])\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `width` | number | -- | Target width (null to auto-scale) |\n| `height` | number | -- | Target height (null to auto-scale) |\n| `fit` | string | `'cover'` | `'cover'`, `'contain'`, `'fill'`, `'inside'`, `'outside'` |\n| `position` | string | `'centre'` | Gravity/position for cover/contain |\n| `background` | string \\| Object | `{r:0,g:0,b:0,alpha:1}` | Fill color for `contain` |\n| `kernel` | string | `'lanczos3'` | `'nearest'`, `'linear'`, `'cubic'`, `'mitchell'`, `'lanczos2'`, `'lanczos3'` |\n| `withoutEnlargement` | boolean | `false` | Don't upscale |\n| `withoutReduction` | boolean | `false` | Don't downscale |\n| `fastShrinkOnLoad` | boolean | `true` | JPEG/WebP shrink-on-load |\n\n**Fit modes:**\n- `cover` — crop to fill both dimensions\n- `contain` — letterbox within dimensions\n- `fill` — stretch to exact dimensions (ignores aspect ratio)\n- `inside` — fit within, no exceeding\n- `outside` — minimum size meeting both dimensions\n\n**Position values:** `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`, `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `centre`/`center`\n\n**Strategy (cover only):** `entropy`, `attention`\n\nOnly one resize per pipeline.\n\n---\n\n## Operations\n\n### Rotation & Orientation\n\n| Method | Description |\n|--------|-------------|\n| `.rotate([angle], [options])` | Rotate by degrees; omit angle for EXIF auto-rotate. `options.background` for fill color |\n| `.autoOrient()` | Auto-orient from EXIF, then remove Orientation tag |\n| `.flip([flip])` | Vertical mirror (default `true`) |\n| `.flop([flop])` | Horizontal mirror (default `true`) |\n\n### Transform\n\n| Method | Description |\n|--------|-------------|\n| `.affine(matrix, [options])` | 2x2 affine transform. Options: `background`, `idx`, `idy`, `odx`, `ody`, `interpolator` |\n| `.extend(extend)` | Add padding. Number for uniform, or `{ top, right, bottom, left, extendWith, background }`. `extendWith`: `'background'`, `'copy'`, `'repeat'`, `'mirror'` |\n| `.extract({ left, top, width, height })` | Crop region. Can be called before and/or after resize |\n| `.trim([options])` | Auto-crop to content. Options: `background` (default top-left pixel), `threshold` (default `10`), `lineArt` |\n\n### Enhancement\n\n| Method | Description |\n|--------|-------------|\n| `.sharpen([options])` | Sharpen. `options.sigma` (0.000001-10), `.m1` (flat), `.m2` (jagged), `.x1`, `.y2`, `.y3` |\n| `.blur([options])` | No args: 3x3 box blur. `options.sigma` (0.3-1000) for Gaussian. Options: `precision`, `minAmplitude` |\n| `.median([size])` | Median filter, default 3x3 |\n| `.gamma([gamma], [gammaOut])` | Gamma correction (1.0-3.0, default 2.2) |\n| `.normalise([options])` | Stretch luminance. `options.lower` (default `1`), `.upper` (default `99`) percentiles |\n| `.clahe({ width, height, [maxSlope] })` | Contrast Limited Adaptive Histogram Equalization |\n\n### Morphology\n\n| Method | Description |\n|--------|-------------|\n| `.dilate([width])` | Dilation, default 1px |\n| `.erode([width])` | Erosion, default 1px |\n\n### Pixel Operations\n\n| Method | Description |\n|--------|-------------|\n| `.negate([options])` | Invert colors. `options.alpha` (default `true`) |\n| `.threshold([value], [options])` | Binarize at threshold (0-255, default 128). `options.greyscale` (default `true`) |\n| `.boolean(operand, operator)` | Bitwise op with another image: `'and'`, `'or'`, `'eor'` |\n| `.linear([a], [b])` | Per-channel linear transform: `a * pixel + b` |\n| `.recomb(matrix)` | 3x3 or 4x4 color recombination matrix |\n| `.modulate([options])` | Adjust `brightness` (multiply), `saturation` (multiply), `hue` (degrees), `lightness` (add) |\n| `.convolve(kernel)` | Custom convolution: `{ width, height, kernel, scale, offset }` |\n| `.flatten([options])` | Merge alpha with `options.background`, remove alpha |\n| `.unflatten()` | Add alpha; white becomes transparent (experimental) |\n\n---\n\n## Colour\n\n| Method | Description |\n|--------|-------------|\n| `.tint(color)` | Apply tint, preserving alpha |\n| `.greyscale([bool])` | Convert to 8-bit greyscale (alias: `.grayscale()`) |\n| `.pipelineColourspace(space)` | Set pipeline colorspace (e.g. `'rgb16'`, `'lab'`, `'grey16'`) |\n| `.toColourspace(space)` | Set output colorspace (e.g. `'srgb'`, `'cmyk'`, `'b-w'`) |\n\n---\n\n## Channel\n\n| Method | Description |\n|--------|-------------|\n| `.removeAlpha()` | Remove alpha channel |\n| `.ensureAlpha([alpha])` | Add alpha if missing. `alpha`: 0 (transparent) to 1 (opaque, default) |\n| `.extractChannel(channel)` | Extract single channel: `0`-`3` or `'red'`, `'green'`, `'blue'`, `'alpha'` |\n| `.joinChannel(images, [options])` | Add channel(s) from other image(s) |\n| `.bandbool(op)` | Bitwise across all bands: `'and'`, `'or'`, `'eor'` |\n\n---\n\n## Composite\n\n```js\n.composite(images)\n```\n\nOverlay images onto the pipeline image. `images` is an array of objects:\n\n| Property | Type | Default | Description |\n|----------|------|---------|-------------|\n| `input` | Buffer \\| string | -- | Image data, file path, or `create`/`text` object |\n| `blend` | string | `'over'` | Blend mode |\n| `gravity` | string | `'centre'` | Placement gravity |\n| `top` | number | -- | Pixel offset from top (overrides gravity) |\n| `left` | number | -- | Pixel offset from left (overrides gravity) |\n| `tile` | boolean | `false` | Repeat overlay across image |\n| `premultiplied` | boolean | `false` | Skip premultiplication |\n| `density` | number | `72` | DPI for vector overlays |\n\n**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`\n\n```js\nawait sharp('base.png')\n .composite([{ input: 'overlay.png', gravity: 'southeast' }])\n .toFile('output.png');\n```\n\n---\n\n## Output\n\n### Write to File\n\n```js\nawait sharp('input.jpg').resize(800).toFile('output.jpg');\n```\n\nFormat inferred from extension. Returns `{ format, size, width, height, channels, premultiplied }`.\n\n### Write to Buffer\n\n```js\nconst buffer = await sharp('input.jpg').resize(800).toBuffer();\n// or with info:\nconst { data, info } = await sharp('input.jpg').resize(800).toBuffer({ resolveWithObject: true });\n```\n\n### Format Methods\n\n#### JPEG\n\n```js\n.jpeg([options])\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `quality` | number | `80` | 1-100 |\n| `progressive` | boolean | `false` | Progressive JPEG |\n| `chromaSubsampling` | string | `'4:2:0'` | `'4:2:0'` or `'4:4:4'` |\n| `mozjpeg` | boolean | `false` | MozJPEG optimizations |\n| `force` | boolean | `true` | Force JPEG output |\n\n#### PNG\n\n```js\n.png([options])\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `progressive` | boolean | `false` | Progressive (interlace) |\n| `compressionLevel` | number | `6` | 0-9 |\n| `adaptiveFiltering` | boolean | `false` | Adaptive row filtering |\n| `palette` | boolean | `false` | Quantise to palette |\n| `quality` | number | `100` | Palette quality (1-100) |\n| `effort` | number | `7` | CPU effort (1-10, palette mode) |\n| `colours`/`colors` | number | `256` | Max palette colors (2-256) |\n| `dither` | number | `1.0` | Floyd-Steinberg dithering level |\n| `force` | boolean | `true` | Force PNG output |\n\n#### WebP\n\n```js\n.webp([options])\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `quality` | number | `80` | 1-100 |\n| `alphaQuality` | number | `100` | 0-100 |\n| `lossless` | boolean | `false` | Lossless compression |\n| `nearLossless` | boolean | `false` | Near-lossless mode |\n| `smartSubsample` | boolean | `false` | Smart chroma subsampling |\n| `preset` | string | `'default'` | `'default'`, `'photo'`, `'picture'`, `'drawing'`, `'icon'`, `'text'` |\n| `effort` | number | `4` | 0-6 |\n| `loop` | number | `0` | Animation loops (0 = infinite) |\n| `delay` | number \\| Array | -- | Frame delay(s) in ms |\n| `force` | boolean | `true` | Force WebP output |\n\n#### AVIF\n\n```js\n.avif([options])\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `quality` | number | `50` | 1-100 |\n| `lossless` | boolean | `false` | Lossless mode |\n| `effort` | number | `4` | 0-9 |\n| `chromaSubsampling` | string | `'4:4:4'` | Chroma subsampling |\n| `bitdepth` | number | `8` | 8, 10, or 12 |\n\n#### GIF\n\n```js\n.gif([options])\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `reuse` | boolean | `true` | Reuse palette |\n| `progressive` | boolean | `false` | Progressive (interlace) |\n| `colours`/`colors` | number | `256` | 2-256 |\n| `effort` | number | `7` | 1-10 |\n| `dither` | number | `1.0` | 0-1 |\n| `loop` | number | `0` | 0 = infinite |\n| `delay` | number \\| Array | -- | Frame delay(s) in ms |\n| `force` | boolean | `true` | Force GIF output |\n\n#### TIFF\n\n```js\n.tiff([options])\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `quality` | number | `80` | 1-100 |\n| `compression` | string | `'jpeg'` | `'none'`, `'jpeg'`, `'deflate'`, `'packbits'`, `'lzw'`, `'webp'`, `'zstd'`, `'jp2k'`, `'ccittfax4'` |\n| `predictor` | string | `'horizontal'` | `'none'`, `'horizontal'`, `'float'` |\n| `pyramid` | boolean | `false` | Write image pyramid |\n| `tile` | boolean | `false` | Tiled TIFF |\n| `tileWidth` | number | `256` | Tile width |\n| `tileHeight` | number | `256` | Tile height |\n| `bitdepth` | number | `8` | 1, 2, 4, or 8 |\n| `force` | boolean | `true` | Force TIFF output |\n\n#### HEIF\n\n```js\n.heif({ compression: 'hevc' })\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `compression` | string | required | `'av1'` or `'hevc'` |\n| `quality` | number | `50` | 1-100 |\n| `lossless` | boolean | `false` | Lossless mode |\n| `effort` | number | `4` | 0-9 |\n| `bitdepth` | number | `8` | 8, 10, or 12 |\n\n#### Raw\n\n```js\n.raw([options])\n```\n\n- `options.depth` (string, default `'uchar'`): `'char'`, `'uchar'`, `'short'`, `'ushort'`, `'int'`, `'uint'`, `'float'`, `'double'`\n\n#### Tile (DZI / Zoomify / IIIF)\n\n```js\n.tile([options])\n```\n\n| Option | Type | Default | Description |\n|--------|------|---------|-------------|\n| `size` | number | `256` | Tile size (1-8192) |\n| `overlap` | number | `0` | Tile overlap (0-8192) |\n| `layout` | string | `'dz'` | `'dz'`, `'iiif'`, `'iiif3'`, `'zoomify'`, `'google'` |\n| `container` | string | `'fs'` | `'fs'` or `'zip'` |\n| `angle` | number | `0` | Rotation (multiple of 90) |\n| `background` | string \\| Object | white | Fill color |\n\n---\n\n## Metadata & Stats\n\n### metadata()\n\n```js\nconst meta = await sharp('input.jpg').metadata();\n```\n\nReturns without decoding pixels:\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `format` | string | `'jpeg'`, `'png'`, `'webp'`, `'gif'`, `'svg'`, etc. |\n| `width` | number | Pixel width |\n| `height` | number | Pixel height |\n| `space` | string | Color space (`'srgb'`, `'rgb'`, `'cmyk'`, `'b-w'`, etc.) |\n| `channels` | number | Band count |\n| `depth` | string | Pixel depth (`'uchar'`, `'ushort'`, `'float'`, etc.) |\n| `density` | number | DPI |\n| `chromaSubsampling` | string | e.g. `'4:2:0'` |\n| `isProgressive` | boolean | Progressive/interlaced |\n| `hasAlpha` | boolean | Has alpha channel |\n| `hasProfile` | boolean | Has ICC profile |\n| `orientation` | number | EXIF orientation (1-8) |\n| `pages` | number | Page count |\n| `size` | number | Total bytes (Buffer/Stream input) |\n| `exif` | Buffer | Raw EXIF |\n| `icc` | Buffer | ICC profile |\n| `xmp` | Buffer | XMP data |\n\n### stats()\n\n```js\nconst stats = await sharp('input.jpg').stats();\n```\n\nReturns pixel-derived statistics:\n\n| Property | Type | Description |\n|----------|------|-------------|\n| `channels` | Array | Per-channel: `min`, `max`, `sum`, `mean`, `stdev`, `minX`, `minY`, `maxX`, `maxY` |\n| `isOpaque` | boolean | Fully opaque |\n| `entropy` | number | Greyscale entropy |\n| `sharpness` | number | Laplacian sharpness |\n| `dominant` | Object | Dominant sRGB color |\n\n---\n\n## Metadata Preservation\n\nBy default, sharp strips all metadata and converts to sRGB.\n\n| Method | Description |\n|--------|-------------|\n| `.keepMetadata()` | Preserve all metadata (EXIF, ICC, XMP, IPTC) |\n| `.keepExif()` | Preserve EXIF only |\n| `.withExif(exif)` | Set EXIF (replaces input). Object keyed by IFD |\n| `.withExifMerge(exif)` | Merge with existing EXIF |\n| `.keepIccProfile()` | Preserve ICC profile |\n| `.withIccProfile(icc, [options])` | Set ICC: path or `'srgb'`, `'p3'`, `'cmyk'` |\n| `.keepXmp()` | Preserve XMP |\n| `.withXmp(xmp)` | Set XMP (XML string) |\n| `.withMetadata([options])` | Preserve most metadata. Options: `orientation`, `density` |\n\n---\n\n## Timeout\n\n```js\n.timeout({ seconds: 30 })\n```\n\nAbort processing after N seconds. `0` = no timeout (default).\n\n---\n\n## Utility (Static)\n\n| Property/Method | Description |\n|-----------------|-------------|\n| `sharp.format` | Object with available input/output format booleans |\n| `sharp.versions` | Version info for sharp, libvips, dependencies |\n| `sharp.interpolators` | Enum: `nearest`, `bilinear`, `bicubic`, `lbb`, `nohalo`, `vsqbs` |\n| `sharp.cache([options])` | Get/set cache: `{ memory: 50, files: 20, items: 100 }` |\n| `sharp.concurrency([n])` | Get/set thread count (default: CPU cores) |\n| `sharp.counters()` | Returns `{ queue, process }` |\n| `sharp.simd([bool])` | Enable/disable SIMD (default `true`) |\n| `sharp.block({ operation })` | Block specific operations |\n| `sharp.unblock({ operation })` | Unblock operations |\n\n---\n\n## Common Recipes\n\n### Resize and convert format\n\n```js\nawait sharp('input.png')\n .resize(800, 600)\n .webp({ quality: 80 })\n .toFile('output.webp');\n```\n\n### Resize to fit within bounds (no upscale)\n\n```js\nawait sharp('input.jpg')\n .resize(1200, 800, { fit: 'inside', withoutEnlargement: true })\n .toFile('output.jpg');\n```\n\n### Create thumbnail (cover crop)\n\n```js\nawait sharp('input.jpg')\n .resize(250, 250, { fit: 'cover', position: 'attention' })\n .toFile('thumb.jpg');\n```\n\n### Crop region\n\n```js\nawait sharp('input.jpg')\n .extract({ left: 100, top: 50, width: 400, height: 300 })\n .toFile('cropped.jpg');\n```\n\n### Add watermark overlay\n\n```js\nawait sharp('photo.jpg')\n .composite([{ input: 'watermark.png', gravity: 'southeast' }])\n .toFile('watermarked.jpg');\n```\n\n### Composite text overlay\n\n```js\nawait sharp('photo.jpg')\n .composite([{\n input: { text: { text: 'Hello World', font: 'sans', dpi: 200, rgba: true } },\n gravity: 'south'\n }])\n .toFile('annotated.jpg');\n```\n\n### Convert to greyscale\n\n```js\nawait sharp('input.jpg')\n .greyscale()\n .toFile('grey.jpg');\n```\n\n### Blur\n\n```js\nawait sharp('input.jpg')\n .blur({ sigma: 5 })\n .toFile('blurred.jpg');\n```\n\n### Rotate\n\n```js\nawait sharp('input.jpg')\n .rotate(90)\n .toFile('rotated.jpg');\n```\n\n### Auto-orient from EXIF\n\n```js\nawait sharp('input.jpg')\n .autoOrient()\n .toFile('oriented.jpg');\n```\n\n### Extend with padding\n\n```js\nawait sharp('input.png')\n .extend({ top: 20, bottom: 20, left: 20, right: 20, background: '#ffffff' })\n .toFile('padded.png');\n```\n\n### Auto-trim whitespace\n\n```js\nawait sharp('input.png')\n .trim({ threshold: 10 })\n .toFile('trimmed.png');\n```\n\n### Optimize JPEG for web\n\n```js\nawait sharp('input.jpg')\n .resize(1920, null, { withoutEnlargement: true })\n .jpeg({ quality: 75, mozjpeg: true, progressive: true })\n .toFile('optimized.jpg');\n```\n\n### Generate AVIF from JPEG\n\n```js\nawait sharp('input.jpg')\n .avif({ quality: 50, effort: 4 })\n .toFile('output.avif');\n```\n\n### Extract channel\n\n```js\nawait sharp('input.png')\n .extractChannel('red')\n .toFile('red-channel.png');\n```\n\n### Get image metadata\n\n```js\nconst { width, height, format, space } = await sharp('input.jpg').metadata();\n```\n\n### Buffer round-trip\n\n```js\nconst buffer = await sharp('input.jpg')\n .resize(300)\n .png()\n .toBuffer();\n```\n\n### Create solid color image\n\n```js\nawait sharp({ create: { width: 100, height: 100, channels: 4, background: '#ff6600' } })\n .png()\n .toFile('orange.png');\n```\n\n### Join images into grid\n\n```js\nawait sharp(['a.png', 'b.png', 'c.png', 'd.png'], { join: { across: 2 } })\n .toFile('grid.png');\n```\n\n### Preserve metadata\n\n```js\nawait sharp('input.jpg')\n .resize(800)\n .keepMetadata()\n .toFile('output.jpg');\n```\n\n### Animated GIF resize\n\n```js\nawait sharp('input.gif', { animated: true })\n .resize(200)\n .gif()\n .toFile('small.gif');\n```\n\n### Multiple outputs from one input\n\n```js\nconst pipeline = sharp('input.jpg');\nawait Promise.all([\n pipeline.clone().resize(200).toFile('thumb.jpg'),\n pipeline.clone().resize(800).toFile('medium.jpg'),\n pipeline.clone().resize(1600).toFile('large.jpg'),\n]);\n```\n\n---\n\n## Source\n\n- Repository: https://github.com/lovell/sharp\n- Documentation: https://sharp.pixelplumbing.com\n- API — Constructor: https://sharp.pixelplumbing.com/api-constructor\n- API — Input: https://sharp.pixelplumbing.com/api-input\n- API — Resize: https://sharp.pixelplumbing.com/api-resize\n- API — Operations: https://sharp.pixelplumbing.com/api-operation\n- API — Colour: https://sharp.pixelplumbing.com/api-colour\n- API — Channel: https://sharp.pixelplumbing.com/api-channel\n- API — Composite: https://sharp.pixelplumbing.com/api-composite\n- API — Output: https://sharp.pixelplumbing.com/api-output\n- API — Utility: https://sharp.pixelplumbing.com/api-utility\n"},"toolUseId":"toolu_01RV3MitgwCQWi7JtfxogBb8","output":"The file /home/pastilhas/projects/officer.dev/data/skills/sharp/SKILL.md has been updated. Here's the result of running `cat -n` on a snippet of the edited file:\n 1→---\n 2→name: sharp\n 3→description: Process images using the sharp Node.js library. Use when the user wants to resize, convert, crop, composite, transform, or optimize images programmatically.\n 4→---\n 5→\n 6→# Sharp\n 7→\n 8→API reference for sharp — a high-performance Node.js image processing library built on libvips.\n 9→\n 10→Typically 4-5x faster than ImageMagick/GraphicsMagick. Supports JPEG, PNG, WebP, GIF, AVIF, TIFF, SVG, HEIF, JP2, and JXL.\n 11→\n 12→Official docs: https://sharp.pixelplumbing.com\n 13→Repository: https://github.com/lovell/sharp\n 14→\n 15→## Installation\n 16→\n 17→```bash\n 18→npm install sharp\n 19→```\n 20→\n 21→Requires Node.js ^18.17.0 or >= 20.3.0 (or Deno/Bun with Node-API v9).\n 22→\n 23→## Usage\n 24→\n 25→Sharp uses a fluent, chainable API. Every call returns a Sharp instance.\n 26→\n 27→```js\n 28→import sharp from 'sharp';\n 29→\n 30→await sharp('input.jpg')\n 31→ .resize(800, 600)\n 32→ .jpeg({ quality: 80 })\n 33→ .toFile('output.jpg');\n 34→```\n 35→\n 36→Sharp implements `stream.Duplex` — it can be piped to/from.\n 37→\n 38→---\n 39→\n 40→## Constructor\n 41→\n 42→```js\n 43→sharp([input], [options])\n 44→```\n 45→\n 46→- `input` (Buffer | string | Array): Image buffer, file path, array of inputs, or omit for stream input.\n 47→\n 48→### Options\n 49→\n 50→| Option | Type | Default | Description |\n 51→|--------|------|---------|-------------|\n 52→| `failOn` | string | `'warning'` | `'none'`, `'truncated'`, `'error'`, `'warning'` |\n 53→| `limitInputPixels` | number \\| boolean | `268402689` | Max pixels; `false` to disable |\n 54→| `unlimited` | boolean | `false` | Remove memory safety for JPEG/PNG/SVG/HEIF |\n 55→| `autoOrient` | boolean | `false` | Auto-rotate per EXIF Orientation |\n 56→| `sequentialRead` | boolean | `true` | Sequential vs random access |\n 57→| `density` | number | `72` | DPI for vector images (1-100000) |\n 58→| `ignoreIcc` | boolean | `false` | Ignore embedded ICC profile |\n 59→| `pages` | number | `1` | Pages to extract; `-1` for all |\n 60→| `page` | number | `0` | Starting page (zero-based) |\n 61→| `animated` | boolean | `false` | Read all frames (equiv. `pages: -1`) |\n 62→\n 63→### Raw Input\n 64→\n 65→```js\n 66→sharp(buffer, { raw: { width: 100, height: 100, channels: 4 } })\n 67→```\n 68→\n 69→| Property | Type | Description |\n 70→|----------|------|-------------|\n 71→| `width` | number | Pixel width |\n 72→| `height` | number | Pixel height |\n 73→| `channels` | number | 1-4 |\n 74→| `premultiplied` | boolean | Skip premultiplication (default `false`) |\n 75→\n 76→### Create New Image\n 77→\n 78→```js\n 79→sharp({ create: { width: 300, height: 200, channels: 4, background: '#ff0000' } })\n 80→```\n 81→\n 82→| Property | Type | Description |\n 83→|----------|------|-------------|\n 84→| `width` | number | Pixel width |\n 85→| `height` | number | Pixel height |\n 86→| `channels` | number | 3 (RGB) or 4 (RGBA) |\n 87→| `background` | string \\| Object | Color (parsed by color module) |\n 88→| `noise` | Object | `{ type: 'gaussian', mean: 128, sigma: 30 }` |\n 89→\n 90→### Render Text\n 91→\n 92→```js\n 93→sharp({ text: { text: 'Hello', font: 'Arial', dpi: 150 } })\n 94→```\n 95→\n 96→| Property | Type | Default | Description |\n 97→|----------|------|---------|-------------|\n 98→| `text` | string | -- | UTF-8; supports Pango markup |\n 99→| `font` | string | -- | Font name |\n 100→| `fontfile` | string | -- | Absolute path to font file |\n 101→| `width` | number | `0` | Word-wrap boundary; 0 = no wrap |\n 102→| `height` | number | `0` | Max height |\n 103→| `align` | string | `'left'` | `'left'`, `'centre'`, `'center'`, `'right'` |\n 104→| `justify` | boolean | `false` | Text justification |\n 105→| `dpi` | number | `72` | Render resolution |\n 106→| `rgba` | boolean | `false` | RGBA for color emoji/Pango markup |\n 107→| `spacing` | number | `0` | Line height in points |\n 108→| `wrap` | string | `'word'` | `'word'`, `'char'`, `'word-char'`, `'none'` |\n 109→\n 110→### Join Array\n 111→\n 112→```js\n 113→sharp([img1, img2, img3], { join: { across: 3, shim: 10 } })\n 114→```\n 115→\n 116→| Property | Type | Default | Description |\n 117→|----------|------|---------|-------------|\n 118→| `across` | number | `1` | Images per row |\n 119→| `animated` | boolean | `false` | Join as animated image |\n 120→| `shim` | number | `0` | Pixel gap between images |\n 121→| `background` | string \\| Object | -- | Gap fill color |\n 122→| `halign` | string | `'left'` | `'left'`, `'centre'`, `'right'` |\n 123→| `valign` | string | `'top'` | `'top'`, `'centre'`, `'bottom'` |\n 124→\n 125→### Clone\n 126→\n 127→```js\n 128→const pipeline = sharp('input.jpg');\n 129→const clone1 = pipeline.clone().resize(200).toFile('thumb.jpg');\n 130→const clone2 = pipeline.clone().resize(800).toFile('large.jpg');\n 131→```\n 132→\n 133→---\n 134→\n 135→## Resize\n 136→\n 137→```js\n 138→.resize([width], [height], [options])\n 139→```\n 140→\n 141→| Option | Type | Default | Description |\n 142→|--------|------|---------|-------------|\n 143→| `width` | number | -- | Target width (null to auto-scale) |\n 144→| `height` | number | -- | Target height (null to auto-scale) |\n 145→| `fit` | string | `'cover'` | `'cover'`, `'contain'`, `'fill'`, `'inside'`, `'outside'` |\n 146→| `position` | string | `'centre'` | Gravity/position for cover/contain |\n 147→| `background` | string \\| Object | `{r:0,g:0,b:0,alpha:1}` | Fill color for `contain` |\n 148→| `kernel` | string | `'lanczos3'` | `'nearest'`, `'linear'`, `'cubic'`, `'mitchell'`, `'lanczos2'`, `'lanczos3'` |\n 149→| `withoutEnlargement` | boolean | `false` | Don't upscale |\n 150→| `withoutReduction` | boolean | `false` | Don't downscale |\n 151→| `fastShrinkOnLoad` | boolean | `true` | JPEG/WebP shrink-on-load |\n 152→\n 153→**Fit modes:**\n 154→- `cover` — crop to fill both dimensions\n 155→- `contain` — letterbox within dimensions\n 156→- `fill` — stretch to exact dimensions (ignores aspect ratio)\n 157→- `inside` — fit within, no exceeding\n 158→- `outside` — minimum size meeting both dimensions\n 159→\n 160→**Position values:** `top`, `right top`, `right`, `right bottom`, `bottom`, `left bottom`, `left`, `left top`, `north`, `northeast`, `east`, `southeast`, `south`, `southwest`, `west`, `northwest`, `centre`/`center`\n 161→\n 162→**Strategy (cover only):** `entropy`, `attention`\n 163→\n 164→Only one resize per pipeline.\n 165→\n 166→---\n 167→\n 168→## Operations\n 169→\n 170→### Rotation & Orientation\n 171→\n 172→| Method | Description |\n 173→|--------|-------------|\n 174→| `.rotate([angle], [options])` | Rotate by degrees; omit angle for EXIF auto-rotate. `options.background` for fill color |\n 175→| `.autoOrient()` | Auto-orient from EXIF, then remove Orientation tag |\n 176→| `.flip([flip])` | Vertical mirror (default `true`) |\n 177→| `.flop([flop])` | Horizontal mirror (default `true`) |\n 178→\n 179→### Transform\n 180→\n 181→| Method | Description |\n 182→|--------|-------------|\n 183→| `.affine(matrix, [options])` | 2x2 affine transform. Options: `background`, `idx`, `idy`, `odx`, `ody`, `interpolator` |\n 184→| `.extend(extend)` | Add padding. Number for uniform, or `{ top, right, bottom, left, extendWith, background }`. `extendWith`: `'background'`, `'copy'`, `'repeat'`, `'mirror'` |\n 185→| `.extract({ left, top, width, height })` | Crop region. Can be called before and/or after resize |\n 186→| `.trim([options])` | Auto-crop to content. Options: `background` (default top-left pixel), `threshold` (default `10`), `lineArt` |\n 187→\n 188→### Enhancement\n 189→\n 190→| Method | Description |\n 191→|--------|-------------|\n 192→| `.sharpen([options])` | Sharpen. `options.sigma` (0.000001-10), `.m1` (flat), `.m2` (jagged), `.x1`, `.y2`, `.y3` |\n 193→| `.blur([options])` | No args: 3x3 box blur. `options.sigma` (0.3-1000) for Gaussian. Options: `precision`, `minAmplitude` |\n 194→| `.median([size])` | Median filter, default 3x3 |\n 195→| `.gamma([gamma], [gammaOut])` | Gamma correction (1.0-3.0, default 2.2) |\n 196→| `.normalise([options])` | Stretch luminance. `options.lower` (default `1`), `.upper` (default `99`) percentiles |\n 197→| `.clahe({ width, height, [maxSlope] })` | Contrast Limited Adaptive Histogram Equalization |\n 198→\n 199→### Morphology\n 200→\n 201→| Method | Description |\n 202→|--------|-------------|\n 203→| `.dilate([width])` | Dilation, default 1px |\n 204→| `.erode([width])` | Erosion, default 1px |\n 205→\n 206→### Pixel Operations\n 207→\n 208→| Method | Description |\n 209→|--------|-------------|\n 210→| `.negate([options])` | Invert colors. `options.alpha` (default `true`) |\n 211→| `.threshold([value], [options])` | Binarize at threshold (0-255, default 128). `options.greyscale` (default `true`) |\n 212→| `.boolean(operand, operator)` | Bitwise op with another image: `'and'`, `'or'`, `'eor'` |\n 213→| `.linear([a], [b])` | Per-channel linear transform: `a * pixel + b` |\n 214→| `.recomb(matrix)` | 3x3 or 4x4 color recombination matrix |\n 215→| `.modulate([options])` | Adjust `brightness` (multiply), `saturation` (multiply), `hue` (degrees), `lightness` (add) |\n 216→| `.convolve(kernel)` | Custom convolution: `{ width, height, kernel, scale, offset }` |\n 217→| `.flatten([options])` | Merge alpha with `options.background`, remove alpha |\n 218→| `.unflatten()` | Add alpha; white becomes transparent (experimental) |\n 219→\n 220→---\n 221→\n 222→## Colour\n 223→\n 224→| Method | Description |\n 225→|--------|-------------|\n 226→| `.tint(color)` | Apply tint, preserving alpha |\n 227→| `.greyscale([bool])` | Convert to 8-bit greyscale (alias: `.grayscale()`) |\n 228→| `.pipelineColourspace(space)` | Set pipeline colorspace (e.g. `'rgb16'`, `'lab'`, `'grey16'`) |\n 229→| `.toColourspace(space)` | Set output colorspace (e.g. `'srgb'`, `'cmyk'`, `'b-w'`) |\n 230→\n 231→---\n 232→\n 233→## Channel\n 234→\n 235→| Method | Description |\n 236→|--------|-------------|\n 237→| `.removeAlpha()` | Remove alpha channel |\n 238→| `.ensureAlpha([alpha])` | Add alpha if missing. `alpha`: 0 (transparent) to 1 (opaque, default) |\n 239→| `.extractChannel(channel)` | Extract single channel: `0`-`3` or `'red'`, `'green'`, `'blue'`, `'alpha'` |\n 240→| `.joinChannel(images, [options])` | Add channel(s) from other image(s) |\n 241→| `.bandbool(op)` | Bitwise across all bands: `'and'`, `'or'`, `'eor'` |\n 242→\n 243→---\n 244→\n 245→## Composite\n 246→\n 247→```js\n 248→.composite(images)\n 249→```\n 250→\n 251→Overlay images onto the pipeline image. `images` is an array of objects:\n 252→\n 253→| Property | Type | Default | Description |\n 254→|----------|------|---------|-------------|\n 255→| `input` | Buffer \\| string | -- | Image data, file path, or `create`/`text` object |\n 256→| `blend` | string | `'over'` | Blend mode |\n 257→| `gravity` | string | `'centre'` | Placement gravity |\n 258→| `top` | number | -- | Pixel offset from top (overrides gravity) |\n 259→| `left` | number | -- | Pixel offset from left (overrides gravity) |\n 260→| `tile` | boolean | `false` | Repeat overlay across image |\n 261→| `premultiplied` | boolean | `false` | Skip premultiplication |\n 262→| `density` | number | `72` | DPI for vector overlays |\n 263→\n 264→**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`\n 265→\n 266→```js\n 267→await sharp('base.png')\n 268→ .composite([{ input: 'overlay.png', gravity: 'southeast' }])\n 269→ .toFile('output.png');\n 270→```\n 271→\n 272→---\n 273→\n 274→## Output\n 275→\n 276→### Write to File\n 277→\n 278→```js\n 279→await sharp('input.jpg').resize(800).toFile('output.jpg');\n 280→```\n 281→\n 282→Format inferred from extension. Returns `{ format, size, width, height, channels, premultiplied }`.\n 283→\n 284→### Write to Buffer\n 285→\n 286→```js\n 287→const buffer = await sharp('input.jpg').resize(800).toBuffer();\n 288→// or with info:\n 289→const { data, info } = await sharp('input.jpg').resize(800).toBuffer({ resolveWithObject: true });\n 290→```\n 291→\n 292→### Format Methods\n 293→\n 294→#### JPEG\n 295→\n 296→```js\n 297→.jpeg([options])\n 298→```\n 299→\n 300→| Option | Type | Default | Description |\n 301→|--------|------|---------|-------------|\n 302→| `quality` | number | `80` | 1-100 |\n 303→| `progressive` | boolean | `false` | Progressive JPEG |\n 304→| `chromaSubsampling` | string | `'4:2:0'` | `'4:2:0'` or `'4:4:4'` |\n 305→| `mozjpeg` | boolean | `false` | MozJPEG optimizations |\n 306→| `force` | boolean | `true` | Force JPEG output |\n 307→\n 308→#### PNG\n 309→\n 310→```js\n 311→.png([options])\n 312→```\n 313→\n 314→| Option | Type | Default | Description |\n 315→|--------|------|---------|-------------|\n 316→| `progressive` | boolean | `false` | Progressive (interlace) |\n 317→| `compressionLevel` | number | `6` | 0-9 |\n 318→| `adaptiveFiltering` | boolean | `false` | Adaptive row filtering |\n 319→| `palette` | boolean | `false` | Quantise to palette |\n 320→| `quality` | number | `100` | Palette quality (1-100) |\n 321→| `effort` | number | `7` | CPU effort (1-10, palette mode) |\n 322→| `colours`/`colors` | number | `256` | Max palette colors (2-256) |\n 323→| `dither` | number | `1.0` | Floyd-Steinberg dithering level |\n 324→| `force` | boolean | `true` | Force PNG output |\n 325→\n 326→#### WebP\n 327→\n 328→```js\n 329→.webp([options])\n 330→```\n 331→\n 332→| Option | Type | Default | Description |\n 333→|--------|------|---------|-------------|\n 334→| `quality` | number | `80` | 1-100 |\n 335→| `alphaQuality` | number | `100` | 0-100 |\n 336→| `lossless` | boolean | `false` | Lossless compression |\n 337→| `nearLossless` | boolean | `false` | Near-lossless mode |\n 338→| `smartSubsample` | boolean | `false` | Smart chroma subsampling |\n 339→| `preset` | string | `'default'` | `'default'`, `'photo'`, `'picture'`, `'drawing'`, `'icon'`, `'text'` |\n 340→| `effort` | number | `4` | 0-6 |\n 341→| `loop` | number | `0` | Animation loops (0 = infinite) |\n 342→| `delay` | number \\| Array | -- | Frame delay(s) in ms |\n 343→| `force` | boolean | `true` | Force WebP output |\n 344→\n 345→#### AVIF\n 346→\n 347→```js\n 348→.avif([options])\n 349→```\n 350→\n 351→| Option | Type | Default | Description |\n 352→|--------|------|---------|-------------|\n 353→| `quality` | number | `50` | 1-100 |\n 354→| `lossless` | boolean | `false` | Lossless mode |\n 355→| `effort` | number | `4` | 0-9 |\n 356→| `chromaSubsampling` | string | `'4:4:4'` | Chroma subsampling |\n 357→| `bitdepth` | number | `8` | 8, 10, or 12 |\n 358→\n 359→#### GIF\n 360→\n 361→```js\n 362→.gif([options])\n 363→```\n 364→\n 365→| Option | Type | Default | Description |\n 366→|--------|------|---------|-------------|\n 367→| `reuse` | boolean | `true` | Reuse palette |\n 368→| `progressive` | boolean | `false` | Progressive (interlace) |\n 369→| `colours`/`colors` | number | `256` | 2-256 |\n 370→| `effort` | number | `7` | 1-10 |\n 371→| `dither` | number | `1.0` | 0-1 |\n 372→| `loop` | number | `0` | 0 = infinite |\n 373→| `delay` | number \\| Array | -- | Frame delay(s) in ms |\n 374→| `force` | boolean | `true` | Force GIF output |\n 375→\n 376→#### TIFF\n 377→\n 378→```js\n 379→.tiff([options])\n 380→```\n 381→\n 382→| Option | Type | Default | Description |\n 383→|--------|------|---------|-------------|\n 384→| `quality` | number | `80` | 1-100 |\n 385→| `compression` | string | `'jpeg'` | `'none'`, `'jpeg'`, `'deflate'`, `'packbits'`, `'lzw'`, `'webp'`, `'zstd'`, `'jp2k'`, `'ccittfax4'` |\n 386→| `predictor` | string | `'horizontal'` | `'none'`, `'horizontal'`, `'float'` |\n 387→| `pyramid` | boolean | `false` | Write image pyramid |\n 388→| `tile` | boolean | `false` | Tiled TIFF |\n 389→| `tileWidth` | number | `256` | Tile width |\n 390→| `tileHeight` | number | `256` | Tile height |\n 391→| `bitdepth` | number | `8` | 1, 2, 4, or 8 |\n 392→| `force` | boolean | `true` | Force TIFF output |\n 393→\n 394→#### HEIF\n 395→\n 396→```js\n 397→.heif({ compression: 'hevc' })\n 398→```\n 399→\n 400→| Option | Type | Default | Description |\n 401→|--------|------|---------|-------------|\n 402→| `compression` | string | required | `'av1'` or `'hevc'` |\n 403→| `quality` | number | `50` | 1-100 |\n 404→| `lossless` | boolean | `false` | Lossless mode |\n 405→| `effort` | number | `4` | 0-9 |\n 406→| `bitdepth` | number | `8` | 8, 10, or 12 |\n 407→\n 408→#### Raw\n 409→\n 410→```js\n 411→.raw([options])\n 412→```\n 413→\n 414→- `options.depth` (string, default `'uchar'`): `'char'`, `'uchar'`, `'short'`, `'ushort'`, `'int'`, `'uint'`, `'float'`, `'double'`\n 415→\n 416→#### Tile (DZI / Zoomify / IIIF)\n 417→\n 418→```js\n 419→.tile([options])\n 420→```\n 421→\n 422→| Option | Type | Default | Description |\n 423→|--------|------|---------|-------------|\n 424→| `size` | number | `256` | Tile size (1-8192) |\n 425→| `overlap` | number | `0` | Tile overlap (0-8192) |\n 426→| `layout` | string | `'dz'` | `'dz'`, `'iiif'`, `'iiif3'`, `'zoomify'`, `'google'` |\n 427→| `container` | string | `'fs'` | `'fs'` or `'zip'` |\n 428→| `angle` | number | `0` | Rotation (multiple of 90) |\n 429→| `background` | string \\| Object | white | Fill color |\n 430→\n 431→---\n 432→\n 433→## Metadata & Stats\n 434→\n 435→### metadata()\n 436→\n 437→```js\n 438→const meta = await sharp('input.jpg').metadata();\n 439→```\n 440→\n 441→Returns without decoding pixels:\n 442→\n 443→| Property | Type | Description |\n 444→|----------|------|-------------|\n 445→| `format` | string | `'jpeg'`, `'png'`, `'webp'`, `'gif'`, `'svg'`, etc. |\n 446→| `width` | number | Pixel width |\n 447→| `height` | number | Pixel height |\n 448→| `space` | string | Color space (`'srgb'`, `'rgb'`, `'cmyk'`, `'b-w'`, etc.) |\n 449→| `channels` | number | Band count |\n 450→| `depth` | string | Pixel depth (`'uchar'`, `'ushort'`, `'float'`, etc.) |\n 451→| `density` | number | DPI |\n 452→| `chromaSubsampling` | string | e.g. `'4:2:0'` |\n 453→| `isProgressive` | boolean | Progressive/interlaced |\n 454→| `hasAlpha` | boolean | Has alpha channel |\n 455→| `hasProfile` | boolean | Has ICC profile |\n 456→| `orientation` | number | EXIF orientation (1-8) |\n 457→| `pages` | number | Page count |\n 458→| `size` | number | Total bytes (Buffer/Stream input) |\n 459→| `exif` | Buffer | Raw EXIF |\n 460→| `icc` | Buffer | ICC profile |\n 461→| `xmp` | Buffer | XMP data |\n 462→\n 463→### stats()\n 464→\n 465→```js\n 466→const stats = await sharp('input.jpg').stats();\n 467→```\n 468→\n 469→Returns pixel-derived statistics:\n 470→\n 471→| Property | Type | Description |\n 472→|----------|------|-------------|\n 473→| `channels` | Array | Per-channel: `min`, `max`, `sum`, `mean`, `stdev`, `minX`, `minY`, `maxX`, `maxY` |\n 474→| `isOpaque` | boolean | Fully opaque |\n 475→| `entropy` | number | Greyscale entropy |\n 476→| `sharpness` | number | Laplacian sharpness |\n 477→| `dominant` | Object | Dominant sRGB color |\n 478→\n 479→---\n 480→\n 481→## Metadata Preservation\n 482→\n 483→By default, sharp strips all metadata and converts to sRGB.\n 484→\n 485→| Method | Description |\n 486→|--------|-------------|\n 487→| `.keepMetadata()` | Preserve all metadata (EXIF, ICC, XMP, IPTC) |\n 488→| `.keepExif()` | Preserve EXIF only |\n 489→| `.withExif(exif)` | Set EXIF (replaces input). Object keyed by IFD |\n 490→| `.withExifMerge(exif)` | Merge with existing EXIF |\n 491→| `.keepIccProfile()` | Preserve ICC profile |\n 492→| `.withIccProfile(icc, [options])` | Set ICC: path or `'srgb'`, `'p3'`, `'cmyk'` |\n 493→| `.keepXmp()` | Preserve XMP |\n 494→| `.withXmp(xmp)` | Set XMP (XML string) |\n 495→| `.withMetadata([options])` | Preserve most metadata. Options: `orientation`, `density` |\n 496→\n 497→---\n 498→\n 499→## Timeout\n 500→\n 501→```js\n 502→.timeout({ seconds: 30 })\n 503→```\n 504→\n 505→Abort processing after N seconds. `0` = no timeout (default).\n 506→\n 507→---\n 508→\n 509→## Utility (Static)\n 510→\n 511→| Property/Method | Description |\n 512→|-----------------|-------------|\n 513→| `sharp.format` | Object with available input/output format booleans |\n 514→| `sharp.versions` | Version info for sharp, libvips, dependencies |\n 515→| `sharp.interpolators` | Enum: `nearest`, `bilinear`, `bicubic`, `lbb`, `nohalo`, `vsqbs` |\n 516→| `sharp.cache([options])` | Get/set cache: `{ memory: 50, files: 20, items: 100 }` |\n 517→| `sharp.concurrency([n])` | Get/set thread count (default: CPU cores) |\n 518→| `sharp.counters()` | Returns `{ queue, process }` |\n 519→| `sharp.simd([bool])` | Enable/disable SIMD (default `true`) |\n 520→| `sharp.block({ operation })` | Block specific operations |\n 521→| `sharp.unblock({ operation })` | Unblock operations |\n 522→\n 523→---\n 524→\n 525→## Common Recipes\n 526→\n 527→### Resize and convert format\n 528→\n 529→```js\n 530→await sharp('input.png')\n 531→ .resize(800, 600)\n 532→ .webp({ quality: 80 })\n 533→ .toFile('output.webp');\n 534→```\n 535→\n 536→### Resize to fit within bounds (no upscale)\n 537→\n 538→```js\n 539→await sharp('input.jpg')\n 540→ .resize(1200, 800, { fit: 'inside', withoutEnlargement: true })\n 541→ .toFile('output.jpg');\n 542→```\n 543→\n 544→### Create thumbnail (cover crop)\n 545→\n 546→```js\n 547→await sharp('input.jpg')\n 548→ .resize(250, 250, { fit: 'cover', position: 'attention' })\n 549→ .toFile('thumb.jpg');\n 550→```\n 551→\n 552→### Crop region\n 553→\n 554→```js\n 555→await sharp('input.jpg')\n 556→ .extract({ left: 100, top: 50, width: 400, height: 300 })\n 557→ .toFile('cropped.jpg');\n 558→```\n 559→\n 560→### Add watermark overlay\n 561→\n 562→```js\n 563→await sharp('photo.jpg')\n 564→ .composite([{ input: 'watermark.png', gravity: 'southeast' }])\n 565→ .toFile('watermarked.jpg');\n 566→```\n 567→\n 568→### Composite text overlay\n 569→\n 570→```js\n 571→await sharp('photo.jpg')\n 572→ .composite([{\n 573→ input: { text: { text: 'Hello World', font: 'sans', dpi: 200, rgba: true } },\n 574→ gravity: 'south'\n 575→ }])\n 576→ .toFile('annotated.jpg');\n 577→```\n 578→\n 579→### Convert to greyscale\n 580→\n 581→```js\n 582→await sharp('input.jpg')\n 583→ .greyscale()\n 584→ .toFile('grey.jpg');\n 585→```\n 586→\n 587→### Blur\n 588→\n 589→```js\n 590→await sharp('input.jpg')\n 591→ .blur({ sigma: 5 })\n 592→ .toFile('blurred.jpg');\n 593→```\n 594→\n 595→### Rotate\n 596→\n 597→```js\n 598→await sharp('input.jpg')\n 599→ .rotate(90)\n 600→ .toFile('rotated.jpg');\n 601→```\n 602→\n 603→### Auto-orient from EXIF\n 604→\n 605→```js\n 606→await sharp('input.jpg')\n 607→ .autoOrient()\n 608→ .toFile('oriented.jpg');\n 609→```\n 610→\n 611→### Extend with padding\n 612→\n 613→```js\n 614→await sharp('input.png')\n 615→ .extend({ top: 20, bottom: 20, left: 20, right: 20, background: '#ffffff' })\n 616→ .toFile('padded.png');\n 617→```\n 618→\n 619→### Auto-trim whitespace\n 620→\n 621→```js\n 622→await sharp('input.png')\n 623→ .trim({ threshold: 10 })\n 624→ .toFile('trimmed.png');\n 625→```\n 626→\n 627→### Optimize JPEG for web\n 628→\n 629→```js\n 630→await sharp('input.jpg')\n 631→ .resize(1920, null, { withoutEnlargement: true })\n 632→ .jpeg({ quality: 75, mozjpeg: true, progressive: true })\n 633→ .toFile('optimized.jpg');\n 634→```\n 635→\n 636→### Generate AVIF from JPEG\n 637→\n 638→```js\n 639→await sharp('input.jpg')\n 640→ .avif({ quality: 50, effort: 4 })\n 641→ .toFile('output.avif');\n 642→```\n 643→\n 644→### Extract channel\n 645→\n 646→```js\n 647→await sharp('input.png')\n 648→ .extractChannel('red')\n 649→ .toFile('red-channel.png');\n 650→```\n 651→\n 652→### Get image metadata\n 653→\n 654→```js\n 655→const { width, height, format, space } = await sharp('input.jpg').metadata();\n 656→```\n 657→\n 658→### Buffer round-trip\n 659→\n 660→```js\n 661→const buffer = await sharp('input.jpg')\n 662→ .resize(300)\n 663→ .png()\n 664→ .toBuffer();\n 665→```\n 666→\n 667→### Create solid color image\n 668→\n 669→```js\n 670→await sharp({ create: { width: 100, height: 100, channels: 4, background: '#ff6600' } })\n 671→ .png()\n 672→ .toFile('orange.png');\n 673→```\n 674→\n 675→### Join images into grid\n 676→\n 677→```js\n 678→await sharp(['a.png', 'b.png', 'c.png', 'd.png'], { join: { across: 2 } })\n 679→ .toFile('grid.png');\n 680→```\n 681→\n 682→### Preserve metadata\n 683→\n 684→```js\n 685→await sharp('input.jpg')\n 686→ .resize(800)\n 687→ .keepMetadata()\n 688→ .toFile('output.jpg');\n 689→```\n 690→\n 691→### Animated GIF resize\n 692→\n 693→```js\n 694→await sharp('input.gif', { animated: true })\n 695→ .resize(200)\n 696→ .gif()\n 697→ .toFile('small.gif');\n 698→```\n 699→\n 700→### Multiple outputs from one input\n 701→\n 702→```js\n 703→const pipeline = sharp('input.jpg');\n 704→await Promise.all([\n 705→ pipeline.clone().resize(200).toFile('thumb.jpg'),\n 706→ pipeline.clone().resize(800).toFile('medium.jpg'),\n 707→ pipeline.clone().resize(1600).toFile('large.jpg'),\n 708→]);\n 709→```\n 710→\n 711→---\n 712→\n 713→## Source\n 714→\n 715→- Repository: https://github.com/lovell/sharp\n 716→- Documentation: https://sharp.pixelplumbing.com\n 717→- API — Constructor: https://sharp.pixelplumbing.com/api-constructor\n 718→- API — Input: https://sharp.pixelplumbing.com/api-input\n 719→- API — Resize: https://sharp.pixelplumbing.com/api-resize\n 720→- API — Operations: https://sharp.pixelplumbing.com/api-operation\n 721→- API — Colour: https://sharp.pixelplumbing.com/api-colour\n 722→- API — Channel: https://sharp.pixelplumbing.com/api-channel\n 723→- API — Composite: https://sharp.pixelplumbing.com/api-composite\n 724→- API — Output: https://sharp.pixelplumbing.com/api-output\n 725→- API — Utility: https://sharp.pixelplumbing.com/api-utility\n 726→","isError":false}]