Files
James Ritchie fade22015f Docs – v4 GA updates (#2298)
* Adds new features table to top of v4 upgrade guide

* Adds wait idempotency to wait-until, wait-for, and wait-for-token pages

* Adds new priority docs page and updates the v4 upgrade guide

* Adds new task lifecycle hooks

* Removes the message about requiring tasks to be exported

* Adds new global lifecycle hooks section

* Moves sections from upgrade guide into the table

* Adds hidden task page

* Improves the global lifecycle hooks section

* Updates middleware and locals section

* Adds new useWaitToken page to the react hooks section

* Adds a new ai.tool section

* Moves Docker (legacy) page into self-hosting section

* Removes known issues from v4 upgrade guide

* Replace “toolTask” with “ai.tool” in the Streams page example

* Renames guide to “Migrating from v3” and adds redirect

* Remove references to v4

* Removes changelog from migration guide

* The installation guide now references `@latest update`

* Changes all references from `/sdk/v3` to `/sdk`

* Updates @v4-beta to @latest

* Fixed broken link

* Fixes broken link

* Adds an upgrade to v4 using AI section

* Fixes 2 broken links

* Adds an entry for targetting preview branches

* Updates the run statuses

* Adds boolean helpers section to the runs and realtime pages

* Updates the concurrency page

* Updates the test page to include the new options

* Adds SDK and curl options for the preview branch targeting

* Updates new bulk actions page

* Remove the releasing concurrency section

* Got rid of some more @v4-beta mentions

* Improved rate limit docs

* Improved migrating docs

* Removed commented sections of the docs

* useWaitToken hook

* Fixed the description

* Fix for missing test image

---------

Co-authored-by: Matt Aitken <matt@mattaitken.com>
Co-authored-by: Dan <8297864+D-K-P@users.noreply.github.com>
2025-08-18 12:34:55 +01:00

131 lines
3.8 KiB
Plaintext

---
title: "Process images using Sharp"
sidebarTitle: "Sharp image processing"
description: "This example demonstrates how to process images using the Sharp library with Trigger.dev."
---
import LocalDevelopment from "/snippets/local-development-extensions.mdx";
## Overview
This task processes and watermarks an image using the Sharp library, and then uploads it to R2 storage.
## Prerequisites
- A project with [Trigger.dev initialized](/quick-start)
- The [Sharp](https://sharp.pixelplumbing.com/install) library installed on your machine
- An R2-compatible object storage service, such as [Cloudflare R2](https://developers.cloudflare.com/r2)
## Adding the build configuration
To use this example, you'll first need to add these build settings to your `trigger.config.ts` file:
```ts trigger.config.ts
import { defineConfig } from "@trigger.dev/sdk";
export default defineConfig({
project: "<project ref>",
// Your other config settings...
build: {
// This is required to use the Sharp library
external: ["sharp"],
},
});
```
<Note>
Any packages that install or build a native binary should be added to external, as native binaries
cannot be bundled.
</Note>
## Key features
- Resizes a JPEG image to 800x800 pixels
- Adds a watermark to the image, positioned in the bottom-right corner, using a PNG image
- Uploads the processed image to R2 storage
## Task code
```ts trigger/sharp-image-processing.ts
import { S3Client } from "@aws-sdk/client-s3";
import { Upload } from "@aws-sdk/lib-storage";
import { logger, task } from "@trigger.dev/sdk";
import fs from "fs/promises";
import os from "os";
import path from "path";
import sharp from "sharp";
// Initialize R2 client using your R2 account details
const r2Client = new S3Client({
region: "auto",
endpoint: process.env.R2_ENDPOINT,
credentials: {
accessKeyId: process.env.R2_ACCESS_KEY_ID ?? "",
secretAccessKey: process.env.R2_SECRET_ACCESS_KEY ?? "",
},
});
export const sharpProcessImage = task({
id: "sharp-process-image",
retry: { maxAttempts: 1 },
run: async (payload: { imageUrl: string; watermarkUrl: string }) => {
const { imageUrl, watermarkUrl } = payload;
const outputPath = path.join(os.tmpdir(), `output_${Date.now()}.jpg`);
const [imageResponse, watermarkResponse] = await Promise.all([
fetch(imageUrl),
fetch(watermarkUrl),
]);
const imageBuffer = await imageResponse.arrayBuffer();
const watermarkBuffer = await watermarkResponse.arrayBuffer();
await sharp(Buffer.from(imageBuffer))
.resize(800, 800) // Resize the image to 800x800px
.composite([
{
input: Buffer.from(watermarkBuffer),
gravity: "southeast", // Position the watermark in the bottom-right corner
},
])
.jpeg() // Convert to jpeg
.toBuffer() // Convert to buffer
.then(async (outputBuffer) => {
await fs.writeFile(outputPath, outputBuffer); // Write the buffer to file
const r2Key = `processed-images/${path.basename(outputPath)}`;
const uploadParams = {
Bucket: process.env.R2_BUCKET,
Key: r2Key,
Body: await fs.readFile(outputPath),
};
const upload = new Upload({
client: r2Client,
params: uploadParams,
});
await upload.done();
logger.log("Image uploaded to R2 storage.", {
path: `/${process.env.R2_BUCKET}/${r2Key}`,
});
await fs.unlink(outputPath); // Clean up the temporary file
return { r2Key };
});
},
});
```
## Testing your task
To test this task in the dashboard, you can use the following payload:
```json
{
"imageUrl": "<an-image-url.jpg>", // Replace with a URL to a JPEG image
"watermarkUrl": "<an-image-url.png>" // Replace with a URL to a PNG watermark image
}
```
<LocalDevelopment packages={"the Sharp image processing library"} />