Skip to content

Commit 1e85765

Browse files
Fix Images docs code examples (7 files) (#28396)
* Fix Images docs code examples (7 files) Co-authored-by: elithrar <elithrar@users.noreply.github.com> * [Images] Fix type error: use file.stream() instead of file.arrayBuffer() for Images binding input env.IMAGES.input() expects ReadableStream<Uint8Array>, not ArrayBuffer. Changed all 4 code blocks to use file.stream() consistently. * Wrap TS blocks in TypeScriptExample Co-authored-by: elithrar <elithrar@users.noreply.github.com> * [Images] Convert optimize-user-uploaded-image examples to TypeScript-first with TypeScriptExample --------- Co-authored-by: ask-bonk[bot] <ask-bonk[bot]@users.noreply.github.com> Co-authored-by: elithrar <elithrar@users.noreply.github.com>
1 parent 52c7273 commit 1e85765

7 files changed

Lines changed: 381 additions & 304 deletions

File tree

Lines changed: 30 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
---
2-
32
summary: Draw a watermark from KV on an image from R2
43
pcx_content_type: example
54
title: Watermarks
@@ -9,41 +8,47 @@ description: Draw a watermark from KV on an image from R2
98
reviewed: 2025-04-03
109
---
1110

11+
import { TypeScriptExample } from "~/components";
12+
13+
<TypeScriptExample>
14+
1215
```ts
1316
interface Env {
14-
BUCKET: R2Bucket,
15-
NAMESPACE: KVNamespace,
16-
IMAGES: ImagesBinding,
17+
BUCKET: R2Bucket;
18+
NAMESPACE: KVNamespace;
19+
IMAGES: ImagesBinding;
1720
}
1821
export default {
19-
async fetch(request, env, ctx): Promise<Response> {
20-
const watermarkKey = "my-watermark";
21-
const sourceKey = "my-source-image";
22+
async fetch(request, env, ctx): Promise<Response> {
23+
const watermarkKey = "my-watermark";
24+
const sourceKey = "my-source-image";
2225

23-
const cache = await caches.open("transformed-images");
24-
const cacheKey = new URL(sourceKey + "/" + watermarkKey, request.url);
25-
const cacheResponse = await cache.match(cacheKey);
26+
const cache = await caches.open("transformed-images");
27+
const cacheKey = new URL(sourceKey + "/" + watermarkKey, request.url);
28+
const cacheResponse = await cache.match(cacheKey);
2629

27-
if (cacheResponse) {
28-
return cacheResponse;
29-
}
30+
if (cacheResponse) {
31+
return cacheResponse;
32+
}
3033

31-
let watermark = await env.NAMESPACE.get(watermarkKey, "stream");
32-
let source = await env.BUCKET.get(sourceKey);
34+
let watermark = await env.NAMESPACE.get(watermarkKey, "stream");
35+
let source = await env.BUCKET.get(sourceKey);
3336

34-
if (!watermark || !source) {
35-
return new Response("Not found", { status: 404 });
36-
}
37+
if (!watermark || !source) {
38+
return new Response("Not found", { status: 404 });
39+
}
3740

38-
const result = await env.IMAGES.input(source.body)
39-
.draw(watermark)
40-
.output({ format: "image/jpeg" });
41+
const result = await env.IMAGES.input(source.body)
42+
.draw(watermark)
43+
.output({ format: "image/jpeg" });
4144

42-
const response = result.response();
45+
const response = result.response();
4346

44-
ctx.waitUntil(cache.put(cacheKey, response.clone()));
47+
ctx.waitUntil(cache.put(cacheKey, response.clone()));
4548

46-
return result.response();
47-
},
49+
return response;
50+
},
4851
} satisfies ExportedHandler<Env>;
4952
```
53+
54+
</TypeScriptExample>

src/content/docs/images/transform-images/bindings.mdx

Lines changed: 18 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ sidebar:
55
order: 4
66
---
77

8-
import { WranglerConfig } from "~/components";
8+
import { WranglerConfig, TypeScriptExample } from "~/components";
99

1010
A [binding](/workers/runtime-apis/bindings/) connects your [Worker](/workers/) to external resources on the Developer Platform, like [Images](/images/transform-images/transform-via-workers/), [R2 buckets](/r2/buckets/), or [KV Namespaces](/kv/concepts/kv-namespaces/).
1111

@@ -61,26 +61,29 @@ Within your Worker code, you can interact with this binding by using `env.IMAGES
6161

6262
For example, to draw a resized watermark on an image:
6363

64+
<TypeScriptExample>
65+
6466
```ts
6567
// Fetch the watermark from Workers Assets, R2, KV etc
66-
const watermark: ReadableStream = ...
68+
const watermark: ReadableStream = getWatermarkStream();
6769

6870
// Fetch the main image
69-
const image: ReadableStream = ...
71+
const image: ReadableStream = getImageStream();
7072

7173
const response = (
72-
await env.IMAGES.input(image)
73-
.draw(
74-
env.IMAGES.input(watermark)
75-
.transform({ width: 32, height: 32}),
76-
{ bottom: 32, right: 32 }
77-
)
78-
.output({ format: "image/avif" })
79-
).response()
74+
await env.IMAGES.input(image)
75+
.draw(env.IMAGES.input(watermark).transform({ width: 32, height: 32 }), {
76+
bottom: 32,
77+
right: 32,
78+
})
79+
.output({ format: "image/avif" })
80+
).response();
8081

8182
return response;
8283
```
8384

85+
</TypeScriptExample>
86+
8487
### `.output()`
8588

8689
- You must define [a supported format](/images/transform-images/#supported-output-formats) such as AVIF, WebP, or JPEG for the [transformed image](/images/transform-images/).
@@ -90,6 +93,8 @@ return response;
9093

9194
For example, to rotate, resize, and blur an image, then output the image as AVIF:
9295

96+
<TypeScriptExample>
97+
9398
```ts
9499
const info = await env.IMAGES.info(stream);
95100
// Stream contains a valid image, and width/height is available on the info object
@@ -108,6 +113,8 @@ const response = (
108113
return response;
109114
```
110115

116+
</TypeScriptExample>
117+
111118
### `.info()`
112119

113120
- Outputs information about the image, such as `format`, `fileSize`, `width`, and `height`.

src/content/docs/images/transform-images/control-origin-access.mdx

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ export default {
4242
const requestURL = new URL(request.url);
4343
// Append the request path such as "/assets/image1.jpg" to the hiddenImageOrigin.
4444
// You could also process the path to add or remove directories, modify filenames, etc.
45-
const imageURL = hiddenImageOrigin + requestURL.path;
45+
const imageURL = hiddenImageOrigin + requestURL.pathname;
4646
// This will fetch image from the given URL, but to the website's visitors this
4747
// will appear as a response to the original request. Visitor’s browser will
4848
// not see this URL.
@@ -61,13 +61,12 @@ export default {
6161
const imageURL =// detail omitted in this example, see the previous example
6262

6363
const requestURL = new URL(request.url)
64-
const resizingOptions = {
65-
width: requestURL.searchParams.get("width"),
66-
}
64+
const width = parseInt(requestURL.searchParams.get("width"), 10);
65+
const resizingOptions = { width }
6766
// If someone tries to manipulate your image URLs to reveal higher-resolution images,
6867
// you can catch that and refuse to serve the request (or enforce a smaller size, etc.)
6968
if (resizingOptions.width > 1000) {
70-
throw Error("We dont allow viewing images larger than 1000 pixels wide")
69+
return new Response("We don't allow viewing images larger than 1000 pixels wide", { status: 400 })
7170
}
7271
return fetch(imageURL, {cf:{image:resizingOptions}})
7372
},};
@@ -85,7 +84,7 @@ export default {
8584

8685
// The regex selects the first path component after the "images"
8786
// prefix, and the rest of the path (e.g. "/images/first/rest")
88-
const match = requestURL.path.match(/images\/([^/]+)\/(.+)/);
87+
const match = requestURL.pathname.match(/images\/([^/]+)\/(.+)/);
8988

9089
// You can require the first path component to be one of the
9190
// predefined sizes only, and set actual dimensions accordingly.
@@ -121,14 +120,14 @@ Cloudflare image transformations cache resized images to aid performance. Images
121120
const signedHeaders = generatedSignedHeaders();
122121

123122
fetch(private_url, {
124-
headers: signedHeaders
125-
cf: {
126-
image: {
127-
format: "auto",
128-
"origin-auth": "share-publicly"
129-
}
130-
}
131-
})
123+
headers: signedHeaders,
124+
cf: {
125+
image: {
126+
format: "auto",
127+
"origin-auth": "share-publicly",
128+
},
129+
},
130+
});
132131
```
133132

134133
When using this code, the following headers are passed through to the origin, and allow your request to be successful:

src/content/docs/images/transform-images/draw-overlays.mdx

Lines changed: 51 additions & 53 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ pcx_content_type: reference
33
title: Draw overlays and watermarks
44
sidebar:
55
order: 5
6-
76
---
87

98
You can draw additional images on top of a resized image, with transparency and blending effects. This enables adding of watermarks, logos, signatures, vignettes, and other effects to resized images.
@@ -12,61 +11,59 @@ This feature is available only in [Workers](/images/transform-images/transform-v
1211

1312
```js
1413
fetch(imageURL, {
15-
cf: {
16-
image: {
17-
width: 800,
18-
height: 600,
19-
draw: [
20-
{
21-
url: 'https://example.com/branding/logo.png', // draw this image
22-
bottom: 5, // 5 pixels from the bottom edge
23-
right: 5, // 5 pixels from the right edge
24-
fit: 'contain', // make it fit within 100x50 area
25-
width: 100,
26-
height: 50,
27-
opacity: 0.8, // 20% transparent
28-
},
29-
],
30-
},
31-
},
14+
cf: {
15+
image: {
16+
width: 800,
17+
height: 600,
18+
draw: [
19+
{
20+
url: "https://example.com/branding/logo.png", // draw this image
21+
bottom: 5, // 5 pixels from the bottom edge
22+
right: 5, // 5 pixels from the right edge
23+
fit: "contain", // make it fit within 100x50 area
24+
width: 100,
25+
height: 50,
26+
opacity: 0.8, // 20% transparent
27+
},
28+
],
29+
},
30+
},
3231
});
3332
```
3433

3534
## Draw options
3635

3736
The `draw` property is an array. Overlays are drawn in the order they appear in the array (the last array entry is the topmost layer). Each item in the `draw` array is an object, which can have the following properties:
3837

38+
- `url`
39+
- Absolute URL of the image file to use for the drawing. It can be any of the supported file formats. For drawing watermarks or non-rectangular overlays, Cloudflare recommends that you use PNG or WebP images.
3940

41+
- `width` and `height`
42+
- Maximum size of the overlay image, in pixels. It must be an integer.
4043

41-
* `url`
42-
* Absolute URL of the image file to use for the drawing. It can be any of the supported file formats. For drawing watermarks or non-rectangular overlays, Cloudflare recommends that you use PNG or WebP images.
43-
44-
* `width` and `height`
45-
* Maximum size of the overlay image, in pixels. It must be an integer.
44+
- `fit` and `gravity`
45+
- Affects interpretation of `width` and `height`. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options).
4646

47-
* `fit` and `gravity`
48-
* Affects interpretation of `width` and `height`. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options).
47+
- `opacity`
48+
- Floating-point number between `0` (transparent) and `1` (opaque). For example, `opacity: 0.5` makes overlay semitransparent.
4949

50-
* `opacity`
51-
* Floating-point number between `0` (transparent) and `1` (opaque). For example, `opacity: 0.5` makes overlay semitransparent.
50+
- `repeat`
51+
- If set to `true`, the overlay image will be tiled to cover the entire area. This is useful for stock-photo-like watermarks.
52+
- If set to `"x"`, the overlay image will be tiled horizontally only (form a line).
53+
- If set to `"y"`, the overlay image will be tiled vertically only (form a line).
5254

53-
* `repeat`
54-
* If set to `true`, the overlay image will be tiled to cover the entire area. This is useful for stock-photo-like watermarks.
55-
* If set to `"x"`, the overlay image will be tiled horizontally only (form a line).
56-
* If set to `"y"`, the overlay image will be tiled vertically only (form a line).
57-
58-
* `top`, `left`, `bottom`, `right`
59-
* Position of the overlay image relative to a given edge. Each property is an offset in pixels. `0` aligns exactly to the edge. For example, `left: 10` positions left side of the overlay 10 pixels from the left edge of the image it is drawn over. `bottom: 0` aligns bottom of the overlay with bottom of the background image.
55+
- `top`, `left`, `bottom`, `right`
56+
- Position of the overlay image relative to a given edge. Each property is an offset in pixels. `0` aligns exactly to the edge. For example, `left: 10` positions left side of the overlay 10 pixels from the left edge of the image it is drawn over. `bottom: 0` aligns bottom of the overlay with bottom of the background image.
6057

6158
Setting both `left` and `right`, or both `top` and `bottom` is an error.
6259

6360
If no position is specified, the image will be centered.
6461

65-
* `background`
66-
* Background color to add underneath the overlay image. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options).
62+
- `background`
63+
- Background color to add underneath the overlay image. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options).
6764

68-
* `rotate`
69-
* Number of degrees to rotate the overlay image by. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options).
65+
- `rotate`
66+
- Number of degrees to rotate the overlay image by. Same as [for the main image](/images/transform-images/transform-via-workers/#fetch-options).
7067

7168
## Draw using the Images binding
7269

@@ -76,14 +73,15 @@ The accepted options for the overlaid image are `opacity`, `repeat`, `top`, `lef
7673

7774
```js
7875
// Fetch image and watermark
79-
const img = await fetch('https://example.com/image.png');
80-
const watermark = await fetch('https://example.com/watermark.png');
76+
const img = await fetch("https://example.com/image.png");
77+
const watermark = await fetch("https://example.com/watermark.png");
8178

82-
const response = await env.IMAGES.input(img.body)
83-
.transform({ width: 1024 })
84-
.draw(watermark.body, { "opacity": 0.25, "repeat": true })
85-
.output({ format: "image/avif" })
86-
.response();
79+
const response = (
80+
await env.IMAGES.input(img.body)
81+
.transform({ width: 1024 })
82+
.draw(watermark.body, { opacity: 0.25, repeat: true })
83+
.output({ format: "image/avif" })
84+
).response();
8785

8886
return response;
8987
```
@@ -95,10 +93,10 @@ In the example below, the watermark is manipulated with `rotate` and `width` bef
9593
```js
9694
// Fetch image and watermark
9795
const response = (
98-
await env.IMAGES.input(img.body)
99-
.transform({ width: 1024 })
100-
.draw(watermark.body, { "opacity": 0.25, "repeat": true })
101-
.output({ format: "image/avif" })
96+
await env.IMAGES.input(img.body)
97+
.transform({ width: 1024 })
98+
.draw(watermark.body, { opacity: 0.25, repeat: true })
99+
.output({ format: "image/avif" })
102100
).response();
103101
```
104102

@@ -114,7 +112,7 @@ image: {
114112
repeat: true, // Tiled over entire image
115113
opacity: 0.2, // and subtly blended
116114
},
117-
];
115+
],
118116
}
119117
```
120118

@@ -128,7 +126,7 @@ image: {
128126
bottom: 5, // Positioned near bottom right corner
129127
right: 5,
130128
},
131-
];
129+
],
132130
}
133131
```
134132

@@ -141,7 +139,7 @@ image: {
141139
url: 'https://example.com/play-button.png',
142140
// Center position is the default
143141
},
144-
];
142+
],
145143
}
146144
```
147145

@@ -155,6 +153,6 @@ image: {
155153
{ url: 'https://example.com/watermark.png', repeat: true, opacity: 0.2 },
156154
{ url: 'https://example.com/play-button.png' },
157155
{ url: 'https://example.com/by-me.png', bottom: 5, right: 5 },
158-
];
156+
],
159157
}
160158
```

0 commit comments

Comments
 (0)