diff --git a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts index 597da6ea087..62340f0c7f7 100644 --- a/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts +++ b/apps/docs/components/Navigation/NavigationMenu/NavigationMenu.constants.ts @@ -1301,6 +1301,10 @@ export const functions: NavMenuConstant = { name: 'Slack Bot responding to mentions', url: '/guides/functions/examples/slack-bot-mention', }, + { + name: 'Image Transformation & Optimization', + url: '/guides/functions/examples/image-manipulation', + }, ], }, { diff --git a/apps/docs/content/guides/functions/examples/image-manipulation.mdx b/apps/docs/content/guides/functions/examples/image-manipulation.mdx new file mode 100644 index 00000000000..0c9ac6c99bf --- /dev/null +++ b/apps/docs/content/guides/functions/examples/image-manipulation.mdx @@ -0,0 +1,78 @@ +--- +title: 'Image Manipulation' +description: 'How to optimize and transform images using Edge Functions.' +--- + +Supabase Storage has [out-of-the-box support](https://supabase.com/docs/guides/storage/serving/image-transformations?queryGroups=language&language=js) for the most common image transformations and optimizations you need. +If you need to do anything custom beyond what Supabase Storage provides, you can use Edge Functions to write custom image manipulation scripts. + +In this example, we will use [magick-wasm](https://github.com/dlemstra/magick-wasm) to perform image manipulations. `magick-wasm` is the WebAssembly port of the popular ImageMagick library and supports processing over 100 file formats. + + + +Edge Functions currently doesn't support image processing libraries such as `Sharp`, which depend on native libraries. Only WASM-based libraries are supported. + + + +### Prerequisites + +Make sure you have the latest version of the [Supabase CLI](https://supabase.com/docs/guides/cli#installation) installed. + +### Create the Edge Function + +Create a new function locally: + +```bash +supabase functions new image-blur + +``` + +### Write the function + +In this example, we are implementing a function allowing users to upload an image and get a blurred thumbnail. + +Here's the implementation in `index.ts` file: + +<$CodeSample +path="edge-functions/supabase/functions/image-manipulation/index.ts" +lines={[[1, -1]]} +/> + +### Test it locally + +You can test the function locally by running: + +```bash +supabase start +supabase functions serve --no-verify-jwt + +``` + +Then, make a request using `curl` or your favorite API testing tool. + +```bash +curl --location '' \\ +--form 'file=@"/path/to/image.png"' +--output '/path/to/output.png' + +``` + +If you open the `output.png` file you will find a transformed version of your original image. + +### Deploy to your hosted project + +Now, let's deploy the function to your Supabase project. + +```bash +supabase link +supabase functions deploy image-blur + +``` + + + +Hosted Edge Functions have [limits](https://supabase.com/docs/guides/functions/limits) on memory and CPU usage. + +If you try to perform complex image processing or handle large images (> 5MB) your function may return a resource limit exceeded error. + + diff --git a/examples/edge-functions/supabase/functions/image-manipulation/index.ts b/examples/edge-functions/supabase/functions/image-manipulation/index.ts new file mode 100644 index 00000000000..17171d6fa50 --- /dev/null +++ b/examples/edge-functions/supabase/functions/image-manipulation/index.ts @@ -0,0 +1,43 @@ +// This is an example showing how to use Magick WASM to do image manipulations in Edge Functions. +// +import { + ImageMagick, + initializeImageMagick, + MagickFormat, +} from "npm:@imagemagick/magick-wasm@0.0.30"; + +const wasmBytes = await Deno.readFile( + new URL( + "magick.wasm", + import.meta.resolve("npm:@imagemagick/magick-wasm@0.0.30"), + ), +); +await initializeImageMagick( + wasmBytes, +); + +Deno.serve(async (req) => { + const formData = await req.formData(); + const content = await formData.get("file").bytes(); + + let result = ImageMagick.read( + content, + (img): Uint8Array => { + // resize the image + img.resize(500, 300); + // add a blur of 60x5 + img.blur(60, 5); + + return img.write( + (data) => data, + ); + }, + ); + + return new Response( + result, + { headers: { "Content-Type": "image/png" } }, + ); +}); + +