ipx 4.0.0-beta.1 → 4.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +222 -209
- package/dist/THIRD-PARTY-LICENSES.md.gz +0 -0
- package/dist/_chunks/libs/@fastify/accept-negotiator.mjs +22 -23
- package/dist/_chunks/libs/css-select.mjs +1077 -937
- package/dist/_chunks/libs/css-tree.mjs +107 -191
- package/dist/_chunks/libs/csso.mjs +50 -82
- package/dist/_chunks/libs/h3.mjs +107 -106
- package/dist/_chunks/libs/image-meta.d.mts +2 -2
- package/dist/_chunks/libs/image-meta.mjs +464 -305
- package/dist/_chunks/libs/sax.mjs +61 -60
- package/dist/_chunks/libs/svgo.mjs +933 -1008
- package/dist/_chunks/node-fs.mjs +125 -49
- package/dist/_chunks/rolldown-runtime.mjs +2 -11
- package/dist/cli.mjs +4 -3
- package/dist/index.d.mts +64 -11
- package/package.json +30 -29
- package/dist/THIRD-PARTY-LICENSES.md +0 -593
package/README.md
CHANGED
|
@@ -15,10 +15,8 @@ Point IPX at a directory or a list of allowed domains, and every image is availa
|
|
|
15
15
|
/w_512,f_webp/photos/buffalo.png
|
|
16
16
|
```
|
|
17
17
|
|
|
18
|
-
Used by [Nuxt Image](https://image.nuxt.com/) and [Netlify](https://www.npmjs.com/package/@netlify/ipx) and open to everyone!
|
|
19
|
-
|
|
20
18
|
> [!NOTE]
|
|
21
|
-
> This is the active development branch for IPX v4. Check out [v3](https://github.com/unjs/ipx/tree/v3) for v3 docs, and
|
|
19
|
+
> This is the active development branch for IPX v4. Check out [v3](https://github.com/unjs/ipx/tree/v3) for v3 docs, and release notes ([alpha](https://github.com/unjs/ipx/releases/tag/v4.0.0-alpha.1), [beta](https://github.com/unjs/ipx/releases/tag/v4.0.0-beta.1)) if you are upgrading.
|
|
22
20
|
|
|
23
21
|
## Quick Start
|
|
24
22
|
|
|
@@ -68,318 +66,318 @@ Colours (`background`, `tint`) accept any colour sharp understands: hex (`f00`,
|
|
|
68
66
|
|
|
69
67
|
<table>
|
|
70
68
|
<tr>
|
|
71
|
-
<td valign="top" width="50%">
|
|
72
|
-
<div align="center"><img src="./assets/operations/width.jpg" alt="/w_160/
|
|
73
|
-
<div
|
|
74
|
-
<code>/w_160/
|
|
69
|
+
<td valign="top" align="left" width="50%">
|
|
70
|
+
<div align="center"><img src="./assets/operations/width.jpg?v=db01a531" width="160" alt="/w_160/scene.jpg"></div>
|
|
71
|
+
<div><b><code>width</code> / <code>w</code></b></div>
|
|
72
|
+
<code>/w_160/scene.jpg</code>
|
|
75
73
|
<br>
|
|
76
|
-
|
|
74
|
+
Resize to a width in pixels, a positive integer. The height follows the aspect ratio. (<a href="https://sharp.pixelplumbing.com/api-resize#resize">docs</a>)
|
|
77
75
|
</td>
|
|
78
|
-
<td valign="top" width="50%">
|
|
79
|
-
<div align="center"><img src="./assets/operations/height.jpg" alt="/h_120/
|
|
80
|
-
<div
|
|
81
|
-
<code>/h_120/
|
|
76
|
+
<td valign="top" align="left" width="50%">
|
|
77
|
+
<div align="center"><img src="./assets/operations/height.jpg?v=ee67aac0" width="180" alt="/h_120/scene.jpg"></div>
|
|
78
|
+
<div><b><code>height</code> / <code>h</code></b></div>
|
|
79
|
+
<code>/h_120/scene.jpg</code>
|
|
82
80
|
<br>
|
|
83
|
-
|
|
81
|
+
Resize to a height in pixels, a positive integer. The width follows the aspect ratio. (<a href="https://sharp.pixelplumbing.com/api-resize#resize">docs</a>)
|
|
84
82
|
</td>
|
|
85
83
|
</tr>
|
|
86
84
|
<tr>
|
|
87
|
-
<td valign="top" width="50%">
|
|
88
|
-
<div align="center"><img src="./assets/operations/resize.jpg" alt="/s_200x200/
|
|
89
|
-
<div
|
|
90
|
-
<code>/s_200x200/
|
|
85
|
+
<td valign="top" align="left" width="50%">
|
|
86
|
+
<div align="center"><img src="./assets/operations/resize.jpg?v=99dda472" width="200" alt="/s_200x200/scene.jpg"></div>
|
|
87
|
+
<div><b><code>resize</code> / <code>s</code></b></div>
|
|
88
|
+
<code>/s_200x200/scene.jpg</code>
|
|
91
89
|
<br>
|
|
92
|
-
<code>{width}x{height}</code
|
|
90
|
+
Resize to <code>{width}x{height}</code>, both positive integers. A single value (<code>s_200</code>) is a square. (<a href="https://sharp.pixelplumbing.com/api-resize#resize">docs</a>)
|
|
93
91
|
</td>
|
|
94
|
-
<td valign="top" width="50%">
|
|
95
|
-
<div align="center"><img src="./assets/operations/kernel.jpg" alt="/s_80x80,kernel_nearest/
|
|
96
|
-
<div
|
|
97
|
-
<code>/s_80x80,kernel_nearest/
|
|
92
|
+
<td valign="top" align="left" width="50%">
|
|
93
|
+
<div align="center"><img src="./assets/operations/kernel.jpg?v=96e57f6e" width="80" alt="/s_80x80,kernel_nearest/photo.jpg"></div>
|
|
94
|
+
<div><b><code>kernel</code></b></div>
|
|
95
|
+
<code>/s_80x80,kernel_nearest/photo.jpg</code>
|
|
98
96
|
<br>
|
|
99
97
|
Sets <code>kernel</code> option for <code>resize</code>. One of <code>nearest</code>, <code>linear</code>, <code>cubic</code>, <code>mitchell</code>, <code>lanczos2</code>, <code>lanczos3</code> (default), <code>mks2013</code> or <code>mks2021</code>. (<a href="https://sharp.pixelplumbing.com/api-resize#resize">docs</a>)
|
|
100
98
|
</td>
|
|
101
99
|
</tr>
|
|
102
100
|
<tr>
|
|
103
|
-
<td valign="top" width="50%">
|
|
104
|
-
<div align="center"><img src="./assets/operations/fit.jpg" alt="/
|
|
105
|
-
<div
|
|
106
|
-
<code>/
|
|
101
|
+
<td valign="top" align="left" width="50%">
|
|
102
|
+
<div align="center"><img src="./assets/operations/fit.jpg?v=08b8660c" width="300" alt="/s_300x150,fit_contain,b_00ff00/scene.jpg"></div>
|
|
103
|
+
<div><b><code>fit</code></b></div>
|
|
104
|
+
<code>/s_300x150,fit_contain,b_00ff00/scene.jpg</code>
|
|
107
105
|
<br>
|
|
108
106
|
Sets <code>fit</code> option for <code>resize</code>. One of <code>contain</code>, <code>cover</code> (default), <code>fill</code>, <code>inside</code> or <code>outside</code>. (<a href="https://sharp.pixelplumbing.com/api-resize#resize">docs</a>)
|
|
109
107
|
</td>
|
|
110
|
-
<td valign="top" width="50%">
|
|
111
|
-
<div align="center"><img src="./assets/operations/position.jpg" alt="/
|
|
112
|
-
<div
|
|
113
|
-
<code>/
|
|
108
|
+
<td valign="top" align="left" width="50%">
|
|
109
|
+
<div align="center"><img src="./assets/operations/position.jpg?v=187fe5e7" width="107" alt="/s_150x300,pos_top/scene.jpg"></div>
|
|
110
|
+
<div><b><code>position</code> / <code>pos</code></b></div>
|
|
111
|
+
<code>/s_150x300,pos_top/scene.jpg</code>
|
|
114
112
|
<br>
|
|
115
|
-
Sets <code>position</code> option for <code>resize</code>. A position (<code>top</code>, <code>right top</code>,
|
|
113
|
+
Sets <code>position</code> option for <code>resize</code>. A position (<code>top</code>, <code>right top</code>, ..., <code>left top</code>), gravity (<code>north</code>, <code>northeast</code>, ..., <code>center</code>) or strategy (<code>entropy</code>, <code>attention</code>), also accepted as their numeric constants. Since <code>_</code> separates arguments, multi-word values use <code>-</code> (<code>pos_right-top</code>). (<a href="https://sharp.pixelplumbing.com/api-resize#resize">docs</a>)
|
|
116
114
|
</td>
|
|
117
115
|
</tr>
|
|
118
116
|
<tr>
|
|
119
|
-
<td valign="top" width="50%">
|
|
120
|
-
<div align="center"><img src="./assets/operations/extend.jpg" alt="/extend_20_40_20_40_mirror/
|
|
121
|
-
<div
|
|
122
|
-
<code>/extend_20_40_20_40_mirror/
|
|
117
|
+
<td valign="top" align="left" width="50%">
|
|
118
|
+
<div align="center"><img src="./assets/operations/extend.jpg?v=0dfb2098" width="320" alt="/extend_20_40_20_40_mirror/scene.jpg"></div>
|
|
119
|
+
<div><b><code>extend</code></b></div>
|
|
120
|
+
<code>/extend_20_40_20_40_mirror/scene.jpg</code>
|
|
123
121
|
<br>
|
|
124
|
-
|
|
122
|
+
Pad or extrude the edges, as <code>extend_{top}_{right}_{bottom}_{left}</code> with an optional <code>{extendWith}</code>. Edges are integers between <code>0</code> and <code>10000</code>. <code>extendWith</code> is <code>background</code> (default), <code>copy</code>, <code>repeat</code> or <code>mirror</code>; <code>background</code> takes its colour from the <code>background</code> / <code>b</code> modifier. (<a href="https://sharp.pixelplumbing.com/api-resize#extend">docs</a>)
|
|
125
123
|
</td>
|
|
126
|
-
<td valign="top" width="50%">
|
|
127
|
-
<div align="center"><img src="./assets/operations/background.jpg" alt="/rotate_45,b_00ff00/
|
|
128
|
-
<div
|
|
129
|
-
<code>/rotate_45,b_00ff00/
|
|
124
|
+
<td valign="top" align="left" width="50%">
|
|
125
|
+
<div align="center"><img src="./assets/operations/background.jpg?v=6b197635" width="320" alt="/rotate_45,b_00ff00/scene.jpg"></div>
|
|
126
|
+
<div><b><code>background</code> / <code>b</code></b></div>
|
|
127
|
+
<code>/rotate_45,b_00ff00/scene.jpg</code>
|
|
130
128
|
<br>
|
|
131
|
-
Background colour
|
|
129
|
+
Background colour, a hex (<code>f00</code>, <code>ff0000</code>) or named (<code>red</code>) colour. Used by <code>extend</code>, <code>rotate</code>, <code>flatten</code>, <code>opacity</code> and <code>resize</code> (with <code>fit_contain</code>).
|
|
132
130
|
</td>
|
|
133
131
|
</tr>
|
|
134
132
|
<tr>
|
|
135
|
-
<td valign="top" width="50%">
|
|
136
|
-
<div align="center"><img src="./assets/operations/extract.jpg" alt="/
|
|
137
|
-
<div
|
|
138
|
-
<code>/
|
|
133
|
+
<td valign="top" align="left" width="50%">
|
|
134
|
+
<div align="center"><img src="./assets/operations/extract.jpg?v=ac75bdaa" width="160" alt="/extract_150_10_160_120/scene.jpg"></div>
|
|
135
|
+
<div><b><code>extract</code> / <code>crop</code></b></div>
|
|
136
|
+
<code>/extract_150_10_160_120/scene.jpg</code>
|
|
139
137
|
<br>
|
|
140
|
-
|
|
138
|
+
Crop a region, as <code>extract_{left}_{top}_{width}_{height}</code>. All four arguments are required; <code>width</code> and <code>height</code> must be positive. (<a href="https://sharp.pixelplumbing.com/api-resize#extract">docs</a>)
|
|
141
139
|
</td>
|
|
142
|
-
<td valign="top" width="50%">
|
|
143
|
-
<div align="center"><img src="./assets/operations/format.webp" alt="/f_webp/
|
|
144
|
-
<div
|
|
145
|
-
<code>/f_webp/
|
|
140
|
+
<td valign="top" align="left" width="50%">
|
|
141
|
+
<div align="center"><img src="./assets/operations/format.webp?v=90841432" width="320" alt="/f_webp/photo.jpg"></div>
|
|
142
|
+
<div><b><code>format</code> / <code>f</code></b></div>
|
|
143
|
+
<code>/f_webp/photo.jpg</code>
|
|
146
144
|
<br>
|
|
147
|
-
|
|
145
|
+
Output format. One of <code>jpg</code>, <code>jpeg</code>, <code>png</code>, <code>webp</code>, <code>avif</code>, <code>gif</code>, <code>heif</code>, <code>tiff</code> or <code>auto</code> (experimental, only with middleware). (<a href="https://sharp.pixelplumbing.com/api-output#toformat">docs</a>)
|
|
148
146
|
</td>
|
|
149
147
|
</tr>
|
|
150
148
|
<tr>
|
|
151
|
-
<td valign="top" width="50%">
|
|
152
|
-
<div align="center"><img src="./assets/operations/quality.jpg" alt="/q_10/
|
|
153
|
-
<div
|
|
154
|
-
<code>/q_10/
|
|
149
|
+
<td valign="top" align="left" width="50%">
|
|
150
|
+
<div align="center"><img src="./assets/operations/quality.jpg?v=865c529f" width="320" alt="/q_10/photo.jpg"></div>
|
|
151
|
+
<div><b><code>quality</code> / <code>q</code></b></div>
|
|
152
|
+
<code>/q_10/photo.jpg</code>
|
|
155
153
|
<br>
|
|
156
|
-
|
|
154
|
+
Encoding quality, an integer between <code>1</code> and <code>100</code>. A lower value means a smaller file.
|
|
157
155
|
</td>
|
|
158
|
-
<td valign="top" width="50%">
|
|
159
|
-
<div align="center"><img src="./assets/operations/rotate.jpg" alt="/rotate_45/
|
|
160
|
-
<div
|
|
161
|
-
<code>/rotate_45/
|
|
156
|
+
<td valign="top" align="left" width="50%">
|
|
157
|
+
<div align="center"><img src="./assets/operations/rotate.jpg?v=4bc4f0b2" width="320" alt="/rotate_45/scene.jpg"></div>
|
|
158
|
+
<div><b><code>rotate</code></b></div>
|
|
159
|
+
<code>/rotate_45/scene.jpg</code>
|
|
162
160
|
<br>
|
|
163
|
-
Angle in degrees, between <code>-3600</code> and <code>3600</code>. Angles that are not a multiple of <code>90</code>
|
|
161
|
+
Angle in degrees, between <code>-3600</code> and <code>3600</code>. Angles that are not a multiple of <code>90</code> fill the corners with the <code>background</code> / <code>b</code> colour. Without an angle (<code>rotate</code>) the image is auto-oriented from its EXIF tag. (<a href="https://sharp.pixelplumbing.com/api-operation#rotate">docs</a>)
|
|
164
162
|
</td>
|
|
165
163
|
</tr>
|
|
166
164
|
<tr>
|
|
167
|
-
<td valign="top" width="50%">
|
|
168
|
-
<div align="center"><img src="./assets/operations/enlarge.jpg" alt="/enlarge,s_400x400/
|
|
169
|
-
<div
|
|
170
|
-
<code>/enlarge,s_400x400/
|
|
165
|
+
<td valign="top" align="left" width="50%">
|
|
166
|
+
<div align="center"><img src="./assets/operations/enlarge.jpg?v=9c6fb296" width="320" alt="/enlarge,s_400x400/photo.jpg"></div>
|
|
167
|
+
<div><b><code>enlarge</code></b></div>
|
|
168
|
+
<code>/enlarge,s_400x400/photo.jpg</code>
|
|
171
169
|
<br>
|
|
172
|
-
Allow the image to be upscaled.
|
|
170
|
+
Allow the image to be upscaled (<code>enlarge_false</code> turns it back off). Without it, the source is never upscaled: a requested box that is too large is shrunk, preserving its aspect ratio, so the output is never larger than the source, except along the padded axis of <code>fit_contain</code>.
|
|
173
171
|
</td>
|
|
174
|
-
<td valign="top" width="50%">
|
|
175
|
-
<div align="center"><img src="./assets/operations/flip.jpg" alt="/flip/
|
|
176
|
-
<div
|
|
177
|
-
<code>/flip/
|
|
172
|
+
<td valign="top" align="left" width="50%">
|
|
173
|
+
<div align="center"><img src="./assets/operations/flip.jpg?v=40a31bca" width="320" alt="/flip/scene.jpg"></div>
|
|
174
|
+
<div><b><code>flip</code></b></div>
|
|
175
|
+
<code>/flip/scene.jpg</code>
|
|
178
176
|
<br>
|
|
179
|
-
Mirror the image vertically. (<a href="https://sharp.pixelplumbing.com/api-operation#flip">docs</a>)
|
|
177
|
+
Mirror the image vertically, about the horizontal axis. Combine with <code>flop</code> to turn it upside down. (<a href="https://sharp.pixelplumbing.com/api-operation#flip">docs</a>)
|
|
180
178
|
</td>
|
|
181
179
|
</tr>
|
|
182
180
|
<tr>
|
|
183
|
-
<td valign="top" width="50%">
|
|
184
|
-
<div align="center"><img src="./assets/operations/flop.jpg" alt="/flop/
|
|
185
|
-
<div
|
|
186
|
-
<code>/flop/
|
|
181
|
+
<td valign="top" align="left" width="50%">
|
|
182
|
+
<div align="center"><img src="./assets/operations/flop.jpg?v=747fa554" width="320" alt="/flop/scene.jpg"></div>
|
|
183
|
+
<div><b><code>flop</code></b></div>
|
|
184
|
+
<code>/flop/scene.jpg</code>
|
|
187
185
|
<br>
|
|
188
|
-
Mirror the image horizontally. (<a href="https://sharp.pixelplumbing.com/api-operation#flop">docs</a>)
|
|
186
|
+
Mirror the image horizontally, about the vertical axis. Combine with <code>flip</code> to turn it upside down. (<a href="https://sharp.pixelplumbing.com/api-operation#flop">docs</a>)
|
|
189
187
|
</td>
|
|
190
|
-
<td valign="top" width="50%">
|
|
191
|
-
<div align="center"><img src="./assets/operations/sharpen.jpg" alt="/sharpen_5/
|
|
192
|
-
<div
|
|
193
|
-
<code>/sharpen_5/
|
|
188
|
+
<td valign="top" align="left" width="50%">
|
|
189
|
+
<div align="center"><img src="./assets/operations/sharpen.jpg?v=eafda8ec" width="320" alt="/sharpen_5/photo.jpg"></div>
|
|
190
|
+
<div><b><code>sharpen</code></b></div>
|
|
191
|
+
<code>/sharpen_5/photo.jpg</code>
|
|
194
192
|
<br>
|
|
195
|
-
<code>{sigma}_{flat}_{jagged}_{x1}_{y2}_{y3}</code>. <code>sigma</code> is between <code>0.000001</code> and <code>10</code>, the rest between <code>0</code> and <code>1000000</code>. Without arguments (<code>sharpen</code>) a mild sharpen is applied. (<a href="https://sharp.pixelplumbing.com/api-operation#sharpen">docs</a>)
|
|
193
|
+
Sharpen the image, as <code>{sigma}_{flat}_{jagged}_{x1}_{y2}_{y3}</code>. <code>sigma</code> is a number between <code>0.000001</code> and <code>10</code>, the rest between <code>0</code> and <code>1000000</code>. Without arguments (<code>sharpen</code>) a mild sharpen is applied. (<a href="https://sharp.pixelplumbing.com/api-operation#sharpen">docs</a>)
|
|
196
194
|
</td>
|
|
197
195
|
</tr>
|
|
198
196
|
<tr>
|
|
199
|
-
<td valign="top" width="50%">
|
|
200
|
-
<div align="center"><img src="./assets/operations/median.jpg" alt="/median_10/
|
|
201
|
-
<div
|
|
202
|
-
<code>/median_10/
|
|
197
|
+
<td valign="top" align="left" width="50%">
|
|
198
|
+
<div align="center"><img src="./assets/operations/median.jpg?v=2317e13b" width="320" alt="/median_10/photo.jpg"></div>
|
|
199
|
+
<div><b><code>median</code></b></div>
|
|
200
|
+
<code>/median_10/photo.jpg</code>
|
|
203
201
|
<br>
|
|
204
|
-
Square mask size, an integer between <code>1</code> and <code>1000</code> (defaults to <code>3</code>). (<a href="https://sharp.pixelplumbing.com/api-operation#median">docs</a>)
|
|
202
|
+
Apply a median filter, removing noise while keeping edges. Square mask size, an integer between <code>1</code> and <code>1000</code> (defaults to <code>3</code>). (<a href="https://sharp.pixelplumbing.com/api-operation#median">docs</a>)
|
|
205
203
|
</td>
|
|
206
|
-
<td valign="top" width="50%">
|
|
207
|
-
<div align="center"><img src="./assets/operations/blur.jpg" alt="/blur_5/
|
|
208
|
-
<div
|
|
209
|
-
<code>/blur_5/
|
|
204
|
+
<td valign="top" align="left" width="50%">
|
|
205
|
+
<div align="center"><img src="./assets/operations/blur.jpg?v=565d775a" width="320" alt="/blur_5/edges.jpg"></div>
|
|
206
|
+
<div><b><code>blur</code></b></div>
|
|
207
|
+
<code>/blur_5/edges.jpg</code>
|
|
210
208
|
<br>
|
|
211
|
-
<code>{sigma}_{precision}_{minAmplitude}</code>. <code>sigma</code> is a number between <code>0.3</code> and <code>1000</code>, <code>precision</code> one of <code>integer</code> (default), <code>float</code> or <code>approximate</code>, <code>minAmplitude</code>
|
|
209
|
+
Gaussian blur, as <code>{sigma}_{precision}_{minAmplitude}</code>. <code>sigma</code> is a number between <code>0.3</code> and <code>1000</code>, <code>precision</code> one of <code>integer</code> (default), <code>float</code> or <code>approximate</code>, <code>minAmplitude</code> between <code>0.001</code> and <code>1</code>. Without arguments (<code>blur</code>) a mild blur is applied. (<a href="https://sharp.pixelplumbing.com/api-operation#blur">docs</a>)
|
|
212
210
|
</td>
|
|
213
211
|
</tr>
|
|
214
212
|
<tr>
|
|
215
|
-
<td valign="top" width="50%">
|
|
216
|
-
<div align="center"><img src="./assets/operations/dilate.png" alt="/
|
|
217
|
-
<div
|
|
218
|
-
<code>/
|
|
213
|
+
<td valign="top" align="left" width="50%">
|
|
214
|
+
<div align="center"><img src="./assets/operations/dilate.png?v=17bf0c5d" width="320" alt="/dilate_4/graphic.png"></div>
|
|
215
|
+
<div><b><code>dilate</code></b></div>
|
|
216
|
+
<code>/dilate_4/graphic.png</code>
|
|
219
217
|
<br>
|
|
220
|
-
Expand foreground objects. Width in pixels, an integer between <code>1</code> and <code>100</code> (defaults to <code>1</code>)
|
|
218
|
+
Expand foreground objects. Width in pixels, an integer between <code>1</code> and <code>100</code> (defaults to <code>1</code>), capped below the sharp maximum since the cost grows with the width. (<a href="https://sharp.pixelplumbing.com/api-operation#dilate">docs</a>)
|
|
221
219
|
</td>
|
|
222
|
-
<td valign="top" width="50%">
|
|
223
|
-
<div align="center"><img src="./assets/operations/erode.png" alt="/
|
|
224
|
-
<div
|
|
225
|
-
<code>/
|
|
220
|
+
<td valign="top" align="left" width="50%">
|
|
221
|
+
<div align="center"><img src="./assets/operations/erode.png?v=b5c7e49a" width="320" alt="/erode_4/graphic.png"></div>
|
|
222
|
+
<div><b><code>erode</code></b></div>
|
|
223
|
+
<code>/erode_4/graphic.png</code>
|
|
226
224
|
<br>
|
|
227
|
-
Shrink foreground objects. Width in pixels, an integer between <code>1</code> and <code>100</code> (defaults to <code>1</code>)
|
|
225
|
+
Shrink foreground objects. Width in pixels, an integer between <code>1</code> and <code>100</code> (defaults to <code>1</code>), capped below the sharp maximum since the cost grows with the width. (<a href="https://sharp.pixelplumbing.com/api-operation#erode">docs</a>)
|
|
228
226
|
</td>
|
|
229
227
|
</tr>
|
|
230
228
|
<tr>
|
|
231
|
-
<td valign="top" width="50%">
|
|
232
|
-
<div align="center"><img src="./assets/operations/clahe.jpg" alt="/clahe_20_20_5/
|
|
233
|
-
<div
|
|
234
|
-
<code>/clahe_20_20_5/
|
|
229
|
+
<td valign="top" align="left" width="50%">
|
|
230
|
+
<div align="center"><img src="./assets/operations/clahe.jpg?v=0aa709f5" width="320" alt="/clahe_20_20_5/edges.jpg"></div>
|
|
231
|
+
<div><b><code>clahe</code></b></div>
|
|
232
|
+
<code>/clahe_20_20_5/edges.jpg</code>
|
|
235
233
|
<br>
|
|
236
|
-
Contrast limiting adaptive histogram equalization, as <code>{width}_{height}_{maxSlope}</code>. <code>width</code> is required and <code>height</code> defaults to it (a square window); both are integers between <code>1</code> and <code>100</code>,
|
|
234
|
+
Contrast limiting adaptive histogram equalization, as <code>{width}_{height}_{maxSlope}</code>. <code>width</code> is required and <code>height</code> defaults to it (a square window); both are integers between <code>1</code> and <code>100</code>, clamped to the source dimensions. <code>maxSlope</code> is an integer between <code>0</code> and <code>100</code> (defaults to <code>3</code>). (<a href="https://sharp.pixelplumbing.com/api-operation#clahe">docs</a>)
|
|
237
235
|
</td>
|
|
238
|
-
<td valign="top" width="50%">
|
|
239
|
-
<div align="center"><img src="./assets/operations/flatten.jpg" alt="/flatten,b_00ff00,f_jpeg/
|
|
240
|
-
<div
|
|
241
|
-
<code>/flatten,b_00ff00,f_jpeg/
|
|
236
|
+
<td valign="top" align="left" width="50%">
|
|
237
|
+
<div align="center"><img src="./assets/operations/flatten.jpg?v=02455cd1" width="320" alt="/flatten,b_00ff00,f_jpeg/alpha.png"></div>
|
|
238
|
+
<div><b><code>flatten</code></b></div>
|
|
239
|
+
<code>/flatten,b_00ff00,f_jpeg/alpha.png</code>
|
|
242
240
|
<br>
|
|
243
|
-
Remove alpha channel, if any, and replace with the <code>background</code> / <code>b</code> colour. (<a href="https://sharp.pixelplumbing.com/api-operation#flatten">docs</a>)
|
|
241
|
+
Remove the alpha channel, if any, and replace transparency with the <code>background</code> / <code>b</code> colour. (<a href="https://sharp.pixelplumbing.com/api-operation#flatten">docs</a>)
|
|
244
242
|
</td>
|
|
245
243
|
</tr>
|
|
246
244
|
<tr>
|
|
247
|
-
<td valign="top" width="50%">
|
|
248
|
-
<div align="center"><img src="./assets/operations/unflatten.webp" alt="/unflatten,f_webp/
|
|
249
|
-
<div
|
|
250
|
-
<code>/unflatten,f_webp/
|
|
245
|
+
<td valign="top" align="left" width="50%">
|
|
246
|
+
<div align="center"><img src="./assets/operations/unflatten.webp?v=db6b8455" width="320" alt="/unflatten,f_webp/graphic.png"></div>
|
|
247
|
+
<div><b><code>unflatten</code></b></div>
|
|
248
|
+
<code>/unflatten,f_webp/graphic.png</code>
|
|
251
249
|
<br>
|
|
252
250
|
Make every fully white pixel transparent, so the output format needs an alpha channel (<code>png</code>, <code>webp</code>, <code>avif</code>). (<a href="https://sharp.pixelplumbing.com/api-operation#unflatten">docs</a>)
|
|
253
251
|
</td>
|
|
254
|
-
<td valign="top" width="50%">
|
|
255
|
-
<div align="center"><img src="./assets/operations/gamma.jpg" alt="/gamma_3/
|
|
256
|
-
<div
|
|
257
|
-
<code>/gamma_3/
|
|
252
|
+
<td valign="top" align="left" width="50%">
|
|
253
|
+
<div align="center"><img src="./assets/operations/gamma.jpg?v=ec2a179b" width="320" alt="/gamma_3/colour.jpg"></div>
|
|
254
|
+
<div><b><code>gamma</code></b></div>
|
|
255
|
+
<code>/gamma_3/colour.jpg</code>
|
|
258
256
|
<br>
|
|
259
|
-
<code>{gamma}_{gammaOut}</code>, each a number between <code>1.0</code> and <code>3.0</code> (defaults to <code>2.2</code>). (<a href="https://sharp.pixelplumbing.com/api-operation#gamma">docs</a>)
|
|
257
|
+
Gamma correction, as <code>{gamma}_{gammaOut}</code>, each a number between <code>1.0</code> and <code>3.0</code> (defaults to <code>2.2</code>). (<a href="https://sharp.pixelplumbing.com/api-operation#gamma">docs</a>)
|
|
260
258
|
</td>
|
|
261
259
|
</tr>
|
|
262
260
|
<tr>
|
|
263
|
-
<td valign="top" width="50%">
|
|
264
|
-
<div align="center"><img src="./assets/operations/negate.jpg" alt="/negate/
|
|
265
|
-
<div
|
|
266
|
-
<code>/negate/
|
|
261
|
+
<td valign="top" align="left" width="50%">
|
|
262
|
+
<div align="center"><img src="./assets/operations/negate.jpg?v=6dcd6c51" width="320" alt="/negate/colour.jpg"></div>
|
|
263
|
+
<div><b><code>negate</code></b></div>
|
|
264
|
+
<code>/negate/colour.jpg</code>
|
|
267
265
|
<br>
|
|
268
|
-
Optional <code>{alpha}</code> (<code>true</code> by default) controls whether the alpha channel is negated too, e.g. <code>negate_false</code>. (<a href="https://sharp.pixelplumbing.com/api-operation#negate">docs</a>)
|
|
266
|
+
Produce the negative of the image. Optional <code>{alpha}</code> (<code>true</code> by default) controls whether the alpha channel is negated too, e.g. <code>negate_false</code>. (<a href="https://sharp.pixelplumbing.com/api-operation#negate">docs</a>)
|
|
269
267
|
</td>
|
|
270
|
-
<td valign="top" width="50%">
|
|
271
|
-
<div align="center"><img src="./assets/operations/normalize.jpg" alt="/normalize_10_90/
|
|
272
|
-
<div
|
|
273
|
-
<code>/normalize_10_90/
|
|
268
|
+
<td valign="top" align="left" width="50%">
|
|
269
|
+
<div align="center"><img src="./assets/operations/normalize.jpg?v=7ab13cca" width="320" alt="/normalize_10_90/edges.jpg"></div>
|
|
270
|
+
<div><b><code>normalize</code></b></div>
|
|
271
|
+
<code>/normalize_10_90/edges.jpg</code>
|
|
274
272
|
<br>
|
|
275
|
-
Stretch the luminance to the full dynamic range, as <code>{lower}_{upper}</code> percentiles. <code>lower</code> is a number between <code>0</code> and <code>99</code> (defaults to <code>1</code>), <code>upper</code> between <code>1</code> and <code>100</code> (defaults to <code>99</code>) and
|
|
273
|
+
Stretch the luminance to the full dynamic range, as <code>{lower}_{upper}</code> percentiles. <code>lower</code> is a number between <code>0</code> and <code>99</code> (defaults to <code>1</code>), <code>upper</code> between <code>1</code> and <code>100</code> (defaults to <code>99</code>) and greater than <code>lower</code>. (<a href="https://sharp.pixelplumbing.com/api-operation#normalize">docs</a>)
|
|
276
274
|
</td>
|
|
277
275
|
</tr>
|
|
278
276
|
<tr>
|
|
279
|
-
<td valign="top" width="50%">
|
|
280
|
-
<div align="center"><img src="./assets/operations/threshold.jpg" alt="/threshold_128/
|
|
281
|
-
<div
|
|
282
|
-
<code>/threshold_128/
|
|
277
|
+
<td valign="top" align="left" width="50%">
|
|
278
|
+
<div align="center"><img src="./assets/operations/threshold.jpg?v=e870d914" width="320" alt="/threshold_128/colour.jpg"></div>
|
|
279
|
+
<div><b><code>threshold</code></b></div>
|
|
280
|
+
<code>/threshold_128/colour.jpg</code>
|
|
283
281
|
<br>
|
|
284
|
-
<code>{threshold}_{grayscale}</code>. <code>threshold</code> is an integer between <code>0</code> and <code>255</code> (defaults to <code>128</code>). Optional <code>grayscale</code> (<code>true</code> by default) converts to single channel
|
|
282
|
+
Map every pixel to black or white, as <code>{threshold}_{grayscale}</code>. <code>threshold</code> is an integer between <code>0</code> and <code>255</code> (defaults to <code>128</code>). Optional <code>grayscale</code> (<code>true</code> by default) converts to single channel first, e.g. <code>threshold_128_false</code>. (<a href="https://sharp.pixelplumbing.com/api-operation#threshold">docs</a>)
|
|
285
283
|
</td>
|
|
286
|
-
<td valign="top" width="50%">
|
|
287
|
-
<div align="center"><img src="./assets/operations/linear.jpg" alt="/linear_1.5_-30/
|
|
288
|
-
<div
|
|
289
|
-
<code>/linear_1.5_-30/
|
|
284
|
+
<td valign="top" align="left" width="50%">
|
|
285
|
+
<div align="center"><img src="./assets/operations/linear.jpg?v=04090af0" width="320" alt="/linear_1.5_-30/colour.jpg"></div>
|
|
286
|
+
<div><b><code>linear</code></b></div>
|
|
287
|
+
<code>/linear_1.5_-30/colour.jpg</code>
|
|
290
288
|
<br>
|
|
291
|
-
Levels adjustment applying <code>a * input + b</code>, as <code>{a}_{b}</code>. <code>a</code> is the multiplier (defaults to <code>1</code>)
|
|
289
|
+
Levels adjustment applying <code>a * input + b</code>, as <code>{a}_{b}</code>. <code>a</code> is the multiplier (defaults to <code>1</code>) and <code>b</code> the offset (defaults to <code>0</code>), both numbers. (<a href="https://sharp.pixelplumbing.com/api-operation#linear">docs</a>)
|
|
292
290
|
</td>
|
|
293
291
|
</tr>
|
|
294
292
|
<tr>
|
|
295
|
-
<td valign="top" width="50%">
|
|
296
|
-
<div align="center"><img src="./assets/operations/tint.jpg" alt="/tint_00ff00/
|
|
297
|
-
<div
|
|
298
|
-
<code>/tint_00ff00/
|
|
293
|
+
<td valign="top" align="left" width="50%">
|
|
294
|
+
<div align="center"><img src="./assets/operations/tint.jpg?v=7a727e4a" width="320" alt="/tint_00ff00/colour.jpg"></div>
|
|
295
|
+
<div><b><code>tint</code></b></div>
|
|
296
|
+
<code>/tint_00ff00/colour.jpg</code>
|
|
299
297
|
<br>
|
|
300
|
-
Tint colour. (<a href="https://sharp.pixelplumbing.com/api-colour#tint">docs</a>)
|
|
298
|
+
Tint the image, keeping its luminance. A hex (<code>f00</code>, <code>ff0000</code>) or named (<code>red</code>) colour. (<a href="https://sharp.pixelplumbing.com/api-colour#tint">docs</a>)
|
|
301
299
|
</td>
|
|
302
|
-
<td valign="top" width="50%">
|
|
303
|
-
<div align="center"><img src="./assets/operations/grayscale.jpg" alt="/grayscale/
|
|
304
|
-
<div
|
|
305
|
-
<code>/grayscale/
|
|
300
|
+
<td valign="top" align="left" width="50%">
|
|
301
|
+
<div align="center"><img src="./assets/operations/grayscale.jpg?v=8e4a38ec" width="320" alt="/grayscale/colour.jpg"></div>
|
|
302
|
+
<div><b><code>grayscale</code></b></div>
|
|
303
|
+
<code>/grayscale/colour.jpg</code>
|
|
306
304
|
<br>
|
|
307
|
-
Convert to 8-bit greyscale. (<a href="https://sharp.pixelplumbing.com/api-colour#grayscale">docs</a>)
|
|
305
|
+
Convert the image to 8-bit greyscale, mapping every pixel to its luminance. (<a href="https://sharp.pixelplumbing.com/api-colour#grayscale">docs</a>)
|
|
308
306
|
</td>
|
|
309
307
|
</tr>
|
|
310
308
|
<tr>
|
|
311
|
-
<td valign="top" width="50%">
|
|
312
|
-
<div align="center"><img src="./assets/operations/modulate.jpg" alt="/modulate_1.5_2_90_10/
|
|
313
|
-
<div
|
|
314
|
-
<code>/modulate_1.5_2_90_10/
|
|
309
|
+
<td valign="top" align="left" width="50%">
|
|
310
|
+
<div align="center"><img src="./assets/operations/modulate.jpg?v=f1cce46c" width="320" alt="/modulate_1.5_2_90_10/colour.jpg"></div>
|
|
311
|
+
<div><b><code>modulate</code></b></div>
|
|
312
|
+
<code>/modulate_1.5_2_90_10/colour.jpg</code>
|
|
315
313
|
<br>
|
|
316
|
-
|
|
314
|
+
Transform the image, as <code>{brightness}_{saturation}_{hue}_{lightness}</code>. <code>brightness</code> and <code>saturation</code> are numbers <code>>= 0</code>, <code>hue</code> an integer in degrees. Each is also available on its own (below). (<a href="https://sharp.pixelplumbing.com/api-operation#modulate">docs</a>)
|
|
317
315
|
</td>
|
|
318
|
-
<td valign="top" width="50%">
|
|
319
|
-
<div align="center"><img src="./assets/operations/brightness.jpg" alt="/brightness_1.5/
|
|
320
|
-
<div
|
|
321
|
-
<code>/brightness_1.5/
|
|
316
|
+
<td valign="top" align="left" width="50%">
|
|
317
|
+
<div align="center"><img src="./assets/operations/brightness.jpg?v=c79f82bb" width="320" alt="/brightness_1.5/colour.jpg"></div>
|
|
318
|
+
<div><b><code>brightness</code></b></div>
|
|
319
|
+
<code>/brightness_1.5/colour.jpg</code>
|
|
322
320
|
<br>
|
|
323
|
-
Brightness multiplier, a number <code>>= 0</code
|
|
321
|
+
Brightness multiplier, a number <code>>= 0</code> (<code>1</code> leaves the image unchanged). Required. (<a href="https://sharp.pixelplumbing.com/api-operation#modulate">docs</a>)
|
|
324
322
|
</td>
|
|
325
323
|
</tr>
|
|
326
324
|
<tr>
|
|
327
|
-
<td valign="top" width="50%">
|
|
328
|
-
<div align="center"><img src="./assets/operations/saturation.jpg" alt="/saturation_0.3/
|
|
329
|
-
<div
|
|
330
|
-
<code>/saturation_0.3/
|
|
325
|
+
<td valign="top" align="left" width="50%">
|
|
326
|
+
<div align="center"><img src="./assets/operations/saturation.jpg?v=9a395c34" width="320" alt="/saturation_0.3/colour.jpg"></div>
|
|
327
|
+
<div><b><code>saturation</code></b></div>
|
|
328
|
+
<code>/saturation_0.3/colour.jpg</code>
|
|
331
329
|
<br>
|
|
332
|
-
Saturation multiplier, a number <code>>= 0</code
|
|
330
|
+
Saturation multiplier, a number <code>>= 0</code> (<code>0</code> is greyscale). Required. (<a href="https://sharp.pixelplumbing.com/api-operation#modulate">docs</a>)
|
|
333
331
|
</td>
|
|
334
|
-
<td valign="top" width="50%">
|
|
335
|
-
<div align="center"><img src="./assets/operations/hue.jpg" alt="/hue_90/
|
|
336
|
-
<div
|
|
337
|
-
<code>/hue_90/
|
|
332
|
+
<td valign="top" align="left" width="50%">
|
|
333
|
+
<div align="center"><img src="./assets/operations/hue.jpg?v=8dff0588" width="320" alt="/hue_90/colour.jpg"></div>
|
|
334
|
+
<div><b><code>hue</code></b></div>
|
|
335
|
+
<code>/hue_90/colour.jpg</code>
|
|
338
336
|
<br>
|
|
339
|
-
Hue rotation, an integer in degrees
|
|
337
|
+
Hue rotation, an integer in degrees that wraps around at <code>360</code>. Required. (<a href="https://sharp.pixelplumbing.com/api-operation#modulate">docs</a>)
|
|
340
338
|
</td>
|
|
341
339
|
</tr>
|
|
342
340
|
<tr>
|
|
343
|
-
<td valign="top" width="50%">
|
|
344
|
-
<div align="center"><img src="./assets/operations/lightness.jpg" alt="/lightness_30/
|
|
345
|
-
<div
|
|
346
|
-
<code>/lightness_30/
|
|
341
|
+
<td valign="top" align="left" width="50%">
|
|
342
|
+
<div align="center"><img src="./assets/operations/lightness.jpg?v=fe72d3a8" width="320" alt="/lightness_30/colour.jpg"></div>
|
|
343
|
+
<div><b><code>lightness</code></b></div>
|
|
344
|
+
<code>/lightness_30/colour.jpg</code>
|
|
347
345
|
<br>
|
|
348
|
-
Lightness addend, a number. Required. (<a href="https://sharp.pixelplumbing.com/api-operation#modulate">docs</a>)
|
|
346
|
+
Lightness addend, a number added to the lightness of every pixel. Required. (<a href="https://sharp.pixelplumbing.com/api-operation#modulate">docs</a>)
|
|
349
347
|
</td>
|
|
350
|
-
<td valign="top" width="50%">
|
|
351
|
-
<div align="center"><img src="./assets/operations/opacity.webp" alt="/opacity_0.5,f_webp/
|
|
352
|
-
<div
|
|
353
|
-
<code>/opacity_0.5,f_webp/
|
|
348
|
+
<td valign="top" align="left" width="50%">
|
|
349
|
+
<div align="center"><img src="./assets/operations/opacity.webp?v=75d9647c" width="320" alt="/opacity_0.5,f_webp/alpha.png"></div>
|
|
350
|
+
<div><b><code>opacity</code></b></div>
|
|
351
|
+
<code>/opacity_0.5,f_webp/alpha.png</code>
|
|
354
352
|
<br>
|
|
355
|
-
Opacity, a number between <code>0</code> and <code>1</code>. Required. The image is made transparent, so the output format needs an alpha channel (<code>png</code>, <code>webp</code>, <code>avif</code>)
|
|
353
|
+
Opacity, a number between <code>0</code> and <code>1</code>. Required. The image is made transparent, so the output format needs an alpha channel (<code>png</code>, <code>webp</code>, <code>avif</code>), or set the <code>background</code> / <code>b</code> colour to blend into it instead, e.g. <code>opacity_0.5,b_fff,f_jpeg</code>.
|
|
356
354
|
</td>
|
|
357
355
|
</tr>
|
|
358
356
|
<tr>
|
|
359
|
-
<td valign="top" width="50%">
|
|
360
|
-
<div align="center"><img src="./assets/operations/animated.gif" alt="/a,w_160/
|
|
361
|
-
<div
|
|
362
|
-
<code>/a,w_160/
|
|
357
|
+
<td valign="top" align="left" width="50%">
|
|
358
|
+
<div align="center"><img src="./assets/operations/animated.gif?v=e51060bb" width="160" alt="/a,w_160/animated.gif"></div>
|
|
359
|
+
<div><b><code>animated</code> / <code>a</code></b></div>
|
|
360
|
+
<code>/a,w_160/animated.gif</code>
|
|
363
361
|
<br>
|
|
364
|
-
Process every frame of an animated image. Experimental.
|
|
362
|
+
Process every frame of an animated image instead of the first one. Experimental.
|
|
365
363
|
</td>
|
|
366
|
-
<td valign="top" width="50%">
|
|
364
|
+
<td valign="top" align="left" width="50%">
|
|
367
365
|
<div align="center"><em>No sample: the sample source has no uniform border to trim.</em></div>
|
|
368
|
-
<div
|
|
369
|
-
<code>/trim_30/
|
|
366
|
+
<div><b><code>trim</code></b></div>
|
|
367
|
+
<code>/trim_30/photo.jpg</code>
|
|
370
368
|
<br>
|
|
371
|
-
Trim pixels
|
|
369
|
+
Trim edge pixels that are within the threshold of the top-left pixel colour. Threshold is a number <code>>= 0</code> (defaults to <code>10</code>). (<a href="https://sharp.pixelplumbing.com/api-resize#trim">docs</a>)
|
|
372
370
|
</td>
|
|
373
371
|
</tr>
|
|
374
372
|
<tr>
|
|
375
|
-
<td valign="top" width="50%">
|
|
373
|
+
<td valign="top" align="left" width="50%">
|
|
376
374
|
<div align="center"><em>No sample: the sample source carries no EXIF <code>Orientation</code> tag.</em></div>
|
|
377
|
-
<div
|
|
378
|
-
<code>/autoorient/
|
|
375
|
+
<div><b><code>autoorient</code></b></div>
|
|
376
|
+
<code>/autoorient/photo.jpg</code>
|
|
379
377
|
<br>
|
|
380
|
-
Rotate and flip the image
|
|
378
|
+
Rotate and flip the image according to its EXIF <code>Orientation</code> tag, then remove the tag. Also applied by <code>rotate</code> without an angle. (<a href="https://sharp.pixelplumbing.com/api-operation#autoorient">docs</a>)
|
|
381
379
|
</td>
|
|
382
|
-
<td valign="top" width="50%"></td>
|
|
380
|
+
<td valign="top" align="left" width="50%"></td>
|
|
383
381
|
</tr>
|
|
384
382
|
</table>
|
|
385
383
|
|
|
@@ -482,9 +480,28 @@ Every option can also be set universally with an `IPX_*` environment variable, w
|
|
|
482
480
|
| -------------------- | -------------------------- | ------- | --------------------------------------------------------- |
|
|
483
481
|
| `alias` | `IPX_ALIAS` | `{}` | Map URL prefixes to other prefixes or remote origins. |
|
|
484
482
|
| `maxOutputDimension` | `IPX_MAX_OUTPUT_DIMENSION` | `8192` | Maximum width and height (in pixels) of the output image. |
|
|
483
|
+
| `allowedModifiers` | `IPX_ALLOWED_MODIFIERS` | (all) | Modifiers that requests are allowed to use. |
|
|
485
484
|
|
|
486
485
|
Requested `width`, `height` and `resize` dimensions are clamped to `maxOutputDimension`, preserving the requested aspect ratio, and `extend` edges are clamped so the extended canvas stays within it. This bounds how much memory a single request can allocate: sharp only limits the _input_ size, so without it `/enlarge,s_20000x20000/image.jpg` (or `/extend_10000_10000_10000_10000/image.jpg`) allocates gigabytes from a small source image. Set to `false` to disable, which is only safe when modifiers come from a trusted source.
|
|
487
486
|
|
|
487
|
+
`allowedModifiers` restricts a public endpoint to the modifiers a site actually uses, for example `allowedModifiers: ["width", "height", "format", "quality"]` or `IPX_ALLOWED_MODIFIERS=width,height,format,quality`. Aliases follow their modifier (allowing `width` also allows `w`). Any other modifier, including an unknown one, is rejected with a `400` before the source is fetched, so expensive operations (`blur`, `median`, ...) cannot be triggered. Only modifier names are checked, not their values: allowing `format` allows every supported output format, including the slow-to-encode `avif`. The same image also stays reachable under many URLs (`?cb=1`, `w_10` vs `w_1e1`, ...), so this does not prevent busting a CDN cache.
|
|
488
|
+
|
|
489
|
+
### Server (`createIPXFetchHandler`, `createIPXNodeHandler`, `serveIPX`)
|
|
490
|
+
|
|
491
|
+
| Option | Environment variable | Default | Description |
|
|
492
|
+
| ------------- | -------------------- | ---------------------------------------------------- | ------------------------------------------------------- |
|
|
493
|
+
| `autoFormats` | `IPX_AUTO_FORMATS` | `avif`, `webp`, `jpeg`, `png`, `tiff`, `heif`, `gif` | Formats `f_auto` can pick from, in order of preference. |
|
|
494
|
+
|
|
495
|
+
`f_auto` serves the format that the client's `accept` header lists with the highest q-value, and equal q-values go to the earlier entry in `autoFormats`. Wildcards such as `image/*` and `*/*` do not match a format, so browsers only negotiate the formats they list explicitly (in practice `avif`, `webp` and `png`). When nothing matches, `jpeg` is served, even if it is not in the list. Animated images only consider `webp` and `gif`, and fall back to `gif`.
|
|
496
|
+
|
|
497
|
+
AVIF compresses best but is much slower to encode, so leave it out when encoding time matters more than size:
|
|
498
|
+
|
|
499
|
+
```ts
|
|
500
|
+
createIPXFetchHandler(ipx, { autoFormats: ["webp", "jpeg"] });
|
|
501
|
+
```
|
|
502
|
+
|
|
503
|
+
With the CLI: `IPX_AUTO_FORMATS=webp,jpeg ipx serve`. Unknown formats throw when the handler is created.
|
|
504
|
+
|
|
488
505
|
### Filesystem source (`ipxFSStorage`)
|
|
489
506
|
|
|
490
507
|
Enabled by default with the CLI only.
|
|
@@ -499,13 +516,13 @@ Enabled by default with the CLI only.
|
|
|
499
516
|
|
|
500
517
|
Enabled by default with the CLI only.
|
|
501
518
|
|
|
502
|
-
| Option | Environment variable | Default | Description
|
|
503
|
-
| ----------------- | ---------------------------- | ------- |
|
|
504
|
-
| `domains` | `IPX_HTTP_DOMAINS` | `[]` | Allowlist of hostnames images can be fetched from.
|
|
505
|
-
| `maxAge` | `IPX_HTTP_MAX_AGE` | `300` |
|
|
506
|
-
| `fetchOptions` | `IPX_HTTP_FETCH_OPTIONS` | `{}` | Passed to `fetch()`.
|
|
507
|
-
| `allowAllDomains` | `IPX_HTTP_ALLOW_ALL_DOMAINS` | `false` | Disables the allowlist. Unsafe on a public server.
|
|
508
|
-
| `blockPrivateIPs` | `IPX_HTTP_BLOCK_PRIVATE_IPS` | `false` | Rejects hosts that are, or resolve to, a non-public IP address. |
|
|
519
|
+
| Option | Environment variable | Default | Description |
|
|
520
|
+
| ----------------- | ---------------------------- | ------- | --------------------------------------------------------------------------------------------- |
|
|
521
|
+
| `domains` | `IPX_HTTP_DOMAINS` | `[]` | Allowlist of hostnames images can be fetched from. |
|
|
522
|
+
| `maxAge` | `IPX_HTTP_MAX_AGE` | `300` | `cache-control` max-age, in seconds, when upstream sends none. |
|
|
523
|
+
| `fetchOptions` | `IPX_HTTP_FETCH_OPTIONS` | `{}` | Passed to `fetch()`. |
|
|
524
|
+
| `allowAllDomains` | `IPX_HTTP_ALLOW_ALL_DOMAINS` | `false` | Disables the allowlist. Unsafe on a public server. |
|
|
525
|
+
| `blockPrivateIPs` | `IPX_HTTP_BLOCK_PRIVATE_IPS` | `false` | Rejects hosts that are, or resolve to, a non-public IP address (best effort, see note below). |
|
|
509
526
|
|
|
510
527
|
Only `http:` and `https:` URLs are allowed (anything else is rejected with `403 IPX_FORBIDDEN_PROTOCOL`), and redirects are followed **only within the allowlist**, up to 3 hops: each redirect target is re-validated and a redirect to a host that is not listed is rejected with `403 IPX_FORBIDDEN_HOST` (`502 IPX_TOO_MANY_REDIRECTS` beyond 3 hops). Previously redirects were followed blindly, which let an allowlisted host with an open redirect bounce IPX to internal addresses such as the cloud metadata service (SSRF). If an allowlisted host redirects to a CDN, add the CDN hostname to the allowlist as well. Redirect re-validation is skipped when `allowAllDomains` is enabled without `blockPrivateIPs` (nothing to validate) or when `redirect` is explicitly set in `fetchOptions`.
|
|
511
528
|
|
|
@@ -521,7 +538,10 @@ The host of the requested URL **and of every redirect hop** must be a public add
|
|
|
521
538
|
|
|
522
539
|
It is **off by default**: many deployments legitimately fetch from in-cluster origins (internal object storage, a sidecar, `localhost` in development), and enabling it by default would break them.
|
|
523
540
|
|
|
524
|
-
|
|
541
|
+
> [!WARNING]
|
|
542
|
+
> `blockPrivateIPs` is best effort and does **not** protect against DNS rebinding. The hostname is resolved once to validate it and again when `fetch` opens the socket, so a DNS record the attacker controls (with a very short TTL) can answer with a public address during validation and a private one during the fetch. This matters when the attacker can choose the hostname: with `allowAllDomains`, or an allowlisted domain whose DNS you do not control. If IPX must not reach internal services, enforce it at the network level: run it behind an egress proxy, or a firewall / network policy that blocks private ranges and the cloud metadata service (on AWS, also require IMDSv2).
|
|
543
|
+
|
|
544
|
+
It is also not a substitute for the allowlist — a public address that happens to be reachable is still fetched.
|
|
525
545
|
|
|
526
546
|
## SVG Images
|
|
527
547
|
|
|
@@ -628,13 +648,6 @@ The parser may be async, and can throw an `HTTPError` (re-exported from `ipx`) t
|
|
|
628
648
|
|
|
629
649
|
Returned values are escaped by IPX, so custom parsers don't need to do it themselves. Note this is not an access check — exactly as with the default URL style, what the resulting id is allowed to resolve to is enforced by the storage layer (`ipxFSStorage`'s directory boundary, `ipxHttpStorage`'s domain allowlist).
|
|
630
650
|
|
|
631
|
-
## Migration from v3 to v4
|
|
632
|
-
|
|
633
|
-
- The server creation APIs have changed. See the [Programmatic API](#programmatic-api) section for examples.
|
|
634
|
-
- The JSON error format has changed from `{ error: string }` to `{ status, statusText, message }`.
|
|
635
|
-
- The `svgo` option is now `svg.optimize`. SVG images are always sanitized, even when optimization is disabled.
|
|
636
|
-
- SVG optimization now applies SVGO's `preset-default` unless custom `plugins` are configured (previously only the configured plugins ran), so SVG output is restructured more than before. See the [SVG Images](#svg-images) section.
|
|
637
|
-
|
|
638
651
|
## License
|
|
639
652
|
|
|
640
653
|
[MIT](./LICENSE)
|