---
title: Sharp
---

import { Image } from 'astro:assets';
import icon from '../../../assets/icon-sharp.svg';

<span title="Label: Pro" data-view-component="true" class="Label Label--api text-uppercase">
  Unstable API
</span>
<span title="Label: Pro" data-view-component="true" class="Label Label--version text-uppercase">
  0.8.0
</span>
<span title="Label: Pro" data-view-component="true" class="Label Label--package">
  <a target="_blank" href="https://www.npmjs.com/package/@project-lakechain/sharp-image-transform">
    @project-lakechain/sharp-image-transform
  </a>
</span>
<span class="language-icon">
  <svg role="img" viewBox="0 0 24 24" width="30" xmlns="http://www.w3.org/2000/svg" style="fill: #3178C6;"><title>TypeScript</title><path d="M1.125 0C.502 0 0 .502 0 1.125v21.75C0 23.498.502 24 1.125 24h21.75c.623 0 1.125-.502 1.125-1.125V1.125C24 .502 23.498 0 22.875 0zm17.363 9.75c.612 0 1.154.037 1.627.111a6.38 6.38 0 0 1 1.306.34v2.458a3.95 3.95 0 0 0-.643-.361 5.093 5.093 0 0 0-.717-.26 5.453 5.453 0 0 0-1.426-.2c-.3 0-.573.028-.819.086a2.1 2.1 0 0 0-.623.242c-.17.104-.3.229-.393.374a.888.888 0 0 0-.14.49c0 .196.053.373.156.529.104.156.252.304.443.444s.423.276.696.41c.273.135.582.274.926.416.47.197.892.407 1.266.628.374.222.695.473.963.753.268.279.472.598.614.957.142.359.214.776.214 1.253 0 .657-.125 1.21-.373 1.656a3.033 3.033 0 0 1-1.012 1.085 4.38 4.38 0 0 1-1.487.596c-.566.12-1.163.18-1.79.18a9.916 9.916 0 0 1-1.84-.164 5.544 5.544 0 0 1-1.512-.493v-2.63a5.033 5.033 0 0 0 3.237 1.2c.333 0 .624-.03.872-.09.249-.06.456-.144.623-.25.166-.108.29-.234.373-.38a1.023 1.023 0 0 0-.074-1.089 2.12 2.12 0 0 0-.537-.5 5.597 5.597 0 0 0-.807-.444 27.72 27.72 0 0 0-1.007-.436c-.918-.383-1.602-.852-2.053-1.405-.45-.553-.676-1.222-.676-2.005 0-.614.123-1.141.369-1.582.246-.441.58-.804 1.004-1.089a4.494 4.494 0 0 1 1.47-.629 7.536 7.536 0 0 1 1.77-.201zm-15.113.188h9.563v2.166H9.506v9.646H6.789v-9.646H3.375z"/></svg>
</span>
<span class="language-icon" style="margin-right: 10px">
  <a target="_blank" href="https://sharp.pixelplumbing.com/">
    <Image width="30" src={icon} alt="Icon" style="border-radius: 50%" />
  </a>
</span>
<div style="margin-top: 26px"></div>

---

The Sharp middleware can be used to apply transformations to images at scale, such as resizing, cropping, rotating, and applying filters on images. It is based on the [`Sharp`](https://sharp.pixelplumbing.com/) library which provides a very efficient way to apply transformations to images using [`libvips`](https://www.libvips.org/).

<br />

![Sharp](../../../assets/sharp-image-transform.png)

<br />

---

### 🖼️ Transforming Images

To use this middleware, you import it in your CDK stack and declare the transforms you want to apply on images. Developers can use the same API as the native [Sharp API](https://sharp.pixelplumbing.com/) to declare the transforms to apply on images.

> ℹ️ The below example showcases how to resize input images to 200x200 pixels.

```typescript
import { SharpImageTransform, sharp } from '@project-lakechain/sharp-image-transform';
import { CacheStorage } from '@project-lakechain/core';

class Stack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string) {
    const cache = new CacheStorage(this, 'Cache');
    
    // Create the Sharp image transform.
    const transform = new SharpImageTransform.Builder()
      .withScope(this)
      .withIdentifier('Transform')
      .withCacheStorage(cache)
      .withSource(source)
      .withSharpTransforms(
        sharp().resize(200, 200) // 👈 Specify a transform
      )
      .build();
  }
}
```

<br />

---

#### Chaining Transforms

The Sharp API transform actions can be chained to apply multiple transforms to an image.

> ℹ️ The below example resizes input images to a width of 500px, applies a grayscale filter, flips the image, and converts it to PNG.

```typescript
const transform = new SharpImageTransform.Builder()
  .withScope(this)
  .withIdentifier('Transform')
  .withCacheStorage(cache)
  .withSource(source)
  .withSharpTransforms(
    sharp()
      .resize(500)
      .grayscale()
      .flip()
      .png()
  )
  .build();
```

<br />

---

### 🔗 External References

Some of the Sharp APIs, such as the [`composite`](https://sharp.pixelplumbing.com/api-composite) API, can combine other images with the currently processed image. You can use a `reference`, part of the Lakechain DSL language, to pass an external image to these APIs.

> ℹ️ The below example applies an external image on S3 as a watermark to the currently processed image.

```typescript
import { SharpImageTransform, sharp } from '@project-lakechain/sharp-image-transform';
import * as r from '@project-lakechain/core/dsl/vocabulary/reference';

// Sample bucket.
const bucket = new s3.Bucket(this, 'Bucket', {});

// Create the Sharp image transform.
const transform = new SharpImageTransform.Builder()
  .withScope(this)
  .withIdentifier('Transform')
  .withCacheStorage(cache)
  .withSource(source)
  .withSharpTransforms(
    sharp()
      .composite([{
        input: r.reference(
          r.url(`s3://${bucket.bucketName}/watermark/watermark.png`)
        )
      }])
      .png()
  )
  .build();

// Grant the middleware access to the watermark image.
bucket.grantRead(transform);
```

<br />

---

### 👾 Using Funclets

While static transforms are convenient and allow developers to describe transforms using the Sharp expressive API, there are use-cases that require developers to apply transforms in a more dynamic way, or generate multiple transforms based on the input image. This level of flexibility can be achieved by using [Funclets](/project-lakechain/guides/funclets) instead of static transformations.

> ℹ️ Funclets allow you to specify a TypeScript function evaluated at runtime for each image in the cloud, and allows you to express in code the transformations you want to apply to the image.

Below is an example of how to specify a funclet that resizes input images to multiple sizes using TypeScript.

```typescript
import { SharpImageTransform, SharpFunction, CloudEvent } from '@project-lakechain/sharp-image-transform';

// Resizes input images to different sizes.
const imageResize = new SharpImageTransform.Builder()
  .withScope(this)
  .withIdentifier('SharpTransform')
  .withCacheStorage(cache)
  .withSource(trigger)
  .withSharpTransforms(async function*(event: CloudEvent, sharp: SharpFunction) {
    // Load the image in memory.
    const buffer = await event.data().document().data().asBuffer();

    // Resize the image to the specified sizes.
    for (const size of [100, 200, 300]) {
      yield sharp(buffer).resize(size).png();
    }
  })
  .build();
```

<br />

---

#### Inner Workings

The `.withSharpTransforms` method accepts a user-provided TypeScript [generator function](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*)
that can yield any number of Sharp transforms to apply to the image.
Each yielded Sharp transform will be automatically be passed to the next middlewares in the pipeline.

> ℹ️ The generator function signature is as follows.

```typescript
type SharpFunction = async function*(event: CloudEvent, sharp: SharpFunction): AsyncGenerator<SharpFunction, void, void>;
```

<br />

---

### 🏗️ Architecture

The Sharp transform middleware runs within a Lambda compute leveraging a Lambda Layer containing the Sharp library for ARM64.

![Architecture](../../../assets/sharp-image-transform-architecture.png)

<br />

---

### 🏷️ Properties

<br />

##### Supported Inputs

|  Mime Type  | Description |
| ----------- | ----------- |
| `image/jpeg` | JPEG images. |
| `image/png` | PNG images. |
| `image/tiff` | TIFF images. |
| `image/webp` | WebP images. |
| `image/avif` | AVIF images. |
| `image/gif` | GIF images. |
| `image/heic` | HEIC images. |
| `image/heif` | HEIF images. |

##### Supported Outputs

*This middleware supports as outputs the same types as the supported inputs.*

##### Supported Compute Types

| Type  | Description |
| ----- | ----------- |
| `CPU` | This middleware only supports CPU compute. |

<br />

---

### 📖 Examples

- [Image Transforms Pipeline](https://github.com/awslabs/project-lakechain/tree/main/examples/simple-pipelines/image-processing-pipelines/image-transforms-pipeline) - A pipeline showcasing how to transform images.
- [Image Watermarking Pipeline](https://github.com/awslabs/project-lakechain/tree/main/examples/simple-pipelines/image-processing-pipelines/image-watermarking-pipeline) - A pipeline showcasing how to watermark images.
- [Image Resize Pipeline](https://github.com/awslabs/project-lakechain/tree/main/examples/simple-pipelines/image-processing-pipelines/image-resize-pipeline) - A pipeline showcasing how to resize images to multiple sizes.
- [Face Extraction Pipeline](https://github.com/awslabs/project-lakechain/tree/main/examples/simple-pipelines/image-processing-pipelines/face-extraction-pipeline) - An example showcasing how to extract faces detected in images.
