@@ -8,9 +8,15 @@ import LocalDevelopment from "/snippets/local-development-extensions.mdx";
8
8
9
9
## Overview
10
10
11
- This task optimizes and watermarks an image using the Sharp library, and then uploads the processed image to R2 storage.
11
+ This task processes and watermarks an image using the Sharp library, and then uploads it to R2 storage.
12
12
13
- ## Adding build configurations
13
+ ## Prerequisites
14
+
15
+ - A project with [ Trigger.dev initialized] ( /quick-start )
16
+ - The [ Sharp] ( https://sharp.pixelplumbing.com/install ) library installed on your machine
17
+ - An R2-compatible object storage service, such as [ Cloudflare R2] ( https://developers.cloudflare.com/r2 )
18
+
19
+ ## Adding the build configuration
14
20
15
21
To use this example, you'll first need to add these build settings to your ` trigger.config.ts ` file:
16
22
@@ -34,22 +40,22 @@ export default defineConfig({
34
40
35
41
## Key features
36
42
37
- - Resizes and rotates an image
38
- - Adds a watermark to the image
39
- - Uploads the processed image to R2 storage
43
+ - Resizes a JPEG image to 800x800 pixels
44
+ - Adds a watermark to the image, positioned in the bottom-right corner, using a PNG image
45
+ - Uploads the processed image to R2 storage
40
46
41
47
## Task code
42
48
43
49
``` ts trigger/sharp-image-processing.ts
44
- import { PutObjectCommand , S3Client } from " @aws-sdk/client-s3" ;
50
+ import { S3Client } from " @aws-sdk/client-s3" ;
51
+ import { Upload } from " @aws-sdk/lib-storage" ;
45
52
import { logger , task } from " @trigger.dev/sdk/v3" ;
46
53
import fs from " fs/promises" ;
47
- import fetch from " node-fetch" ;
48
54
import os from " os" ;
49
55
import path from " path" ;
50
56
import sharp from " sharp" ;
51
57
52
- // Initialize R2 client
58
+ // Initialize R2 client using your R2 account details
53
59
const r2Client = new S3Client ({
54
60
region: " auto" ,
55
61
endpoint: process .env .R2_ENDPOINT ,
@@ -61,63 +67,51 @@ const r2Client = new S3Client({
61
67
62
68
export const sharpProcessImage = task ({
63
69
id: " sharp-process-image" ,
70
+ retry: { maxAttempts: 1 },
64
71
run : async (payload : { imageUrl: string ; watermarkUrl: string }) => {
65
72
const { imageUrl, watermarkUrl } = payload ;
73
+ const outputPath = path .join (os .tmpdir (), ` output_${Date .now ()}.jpg ` );
66
74
67
- // Generate temporary and output file names
68
- const tempDirectory = os .tmpdir ();
69
- const outputPath = path .join (tempDirectory , ` output_${Date .now ()}.jpg ` );
70
-
71
- // Fetch the image and watermark
72
75
const [imageResponse, watermarkResponse] = await Promise .all ([
73
76
fetch (imageUrl ),
74
77
fetch (watermarkUrl ),
75
78
]);
76
79
const imageBuffer = await imageResponse .arrayBuffer ();
77
80
const watermarkBuffer = await watermarkResponse .arrayBuffer ();
78
81
79
- // Optimize the image using Sharp
80
82
await sharp (Buffer .from (imageBuffer ))
81
- .rotate (90 ) // Rotate the image by 90 degrees
82
- .resize (800 , 600 ) // Resize the image to 800x600
83
+ .resize (800 , 800 ) // Resize the image to 800x800px
83
84
.composite ([
84
85
{
85
86
input: Buffer .from (watermarkBuffer ),
86
87
gravity: " southeast" , // Position the watermark in the bottom-right corner
87
88
},
88
89
])
89
- .toFormat (" jpeg" )
90
- .toFile (outputPath );
91
-
92
- // Log the output file path
93
- logger .log (` Optimized image saved at: ${outputPath } ` );
94
-
95
- // Read the optimized image file
96
- const optimizedImageBuffer = await fs .readFile (outputPath );
97
-
98
- // Upload the optimized image to R2, replacing slashes with underscores
99
- const r2Key = ` processed-images/${path .basename (outputPath )} ` ;
100
-
101
- const uploadParams = {
102
- Bucket: process .env .R2_BUCKET ,
103
- Key: r2Key ,
104
- Body: optimizedImageBuffer ,
105
- };
106
-
107
- // Upload the image to R2 and get the URL
108
- await r2Client .send (new PutObjectCommand (uploadParams ));
109
- const r2Url = ` https://${process .env .R2_ACCOUNT_ID }.r2.cloudflarestorage.com/${process .env .R2_BUCKET }/${r2Key } ` ;
110
- logger .log (" Optimized image uploaded to R2" , { url: r2Url });
111
-
112
- // Delete the temporary file
113
- await fs .unlink (outputPath );
114
-
115
- // Return the optimized image buffer, file path, and R2 URL
116
- return {
117
- optimizedImageBuffer ,
118
- optimizedImagePath: outputPath ,
119
- r2Url ,
120
- };
90
+ .jpeg () // Convert to jpeg
91
+ .toBuffer () // Convert to buffer
92
+ .then (async (outputBuffer ) => {
93
+ await fs .writeFile (outputPath , outputBuffer ); // Write the buffer to file
94
+
95
+ const r2Key = ` processed-images/${path .basename (outputPath )} ` ;
96
+ const uploadParams = {
97
+ Bucket: process .env .R2_BUCKET ,
98
+ Key: r2Key ,
99
+ Body: await fs .readFile (outputPath ),
100
+ };
101
+
102
+ const upload = new Upload ({
103
+ client: r2Client ,
104
+ params: uploadParams ,
105
+ });
106
+
107
+ await upload .done ();
108
+ logger .log (" Image uploaded to R2 storage." , {
109
+ path: ` /${process .env .R2_BUCKET }/${r2Key } ` ,
110
+ });
111
+
112
+ await fs .unlink (outputPath ); // Clean up the temporary file
113
+ return { r2Key };
114
+ });
121
115
},
122
116
});
123
117
```
@@ -133,4 +127,4 @@ To test this task in the dashboard, you can use the following payload:
133
127
}
134
128
```
135
129
136
- <LocalDevelopment packages = { " the Sharp image processing library" } />
130
+ <LocalDevelopment packages = { " the Sharp image processing library" } />
0 commit comments