Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Blog image transformation #1799

Draft
wants to merge 13 commits into
base: main
Choose a base branch
from
3 changes: 2 additions & 1 deletion src/lib/appwrite/index.ts
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import { PUBLIC_APPWRITE_ENDPOINT, PUBLIC_APPWRITE_PROJECT_ID } from '$env/static/public';
import { Client, Databases, Functions } from '@appwrite.io/console';
import { Client, Databases, Functions, Storage } from '@appwrite.io/console';

export const client = new Client();

client.setEndpoint(PUBLIC_APPWRITE_ENDPOINT).setProject(PUBLIC_APPWRITE_PROJECT_ID);

export const databases = new Databases(client);
export const functions = new Functions(client);
export const storage = new Storage(client);
46 changes: 46 additions & 0 deletions src/markdoc/tags/Storage_Image.svelte
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
<script lang="ts">
import { storage } from '$lib/appwrite';
import Image from '../nodes/Image.svelte';

export let file_id: string;
export let bucket_id: string = 'images';
export let alt: string = '';
export let title: string = '';
export let width: number = 0;
export let height: number = 0;
export let gravity: string = 'center';
export let quality: number = 90;
export let border_width: number = 0;
export let border_color: string = 'CDCA30';
export let border_radius: number = 0;
export let opacity: number = 1;
export let rotation: number = 0;
export let background_color: string = '000000';
export let output: string = 'webp';
export let just_img: boolean = false;

// Get the file preview URL from Appwrite Storage
const src = storage
.getFilePreview(
bucket_id,
file_id,
width,
height,
gravity as any,
quality,
border_width,
border_color,
border_radius,
opacity,
rotation,
background_color,
output as any
)
.toString();
</script>

{#if just_img}
<img {src} {alt} {title} style="margin-bottom: 2rem;" />
{:else}
<Image {src} {alt} {title} />
{/if}
1 change: 1 addition & 0 deletions src/markdoc/tags/_Module.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -19,4 +19,5 @@
export { default as Accordion_Item } from './Accordion_Item.svelte';
export { default as Youtube } from './Youtube.svelte';
export { default as Call_To_Action } from './Call_To_Action.svelte';
export { default as Storage_Image } from './Storage_Image.svelte';
</script>
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
---
layout: post
title: Image transformation with Appwrite Storage
description: Learn how to dynamically transform images with Appwrite Storage for better performance.
date: 2025-02-28
cover: /images/blog/planetscale-databases-alternative/cover.png
timeToRead: 6
author: ebenezer-don
category: tutorial
---

Images are a core part of any modern web or mobile application. Whether you're displaying user avatars, product thumbnails, or full-screen backgrounds, images need to be optimized for performance, aesthetics, and consistency. Loading large, uncompressed images can slow down your app, and mismatched styles can break your UI. This is why dynamic image transformation should be a part of your app.

Instead of manually editing images before uploading them or storing multiple variations of the same file, Appwrite lets you manipulate images on the fly using the Storage preview endpoint. With a simple API call, you can resize, crop, compress, change formats, add borders, round corners, adjust opacity, and even apply background colors. The best part is that Appwrite automatically caches the transformed images, speeding up repeat requests.

This guide will walk you through everything you need to know about image transformation with Appwrite, and how to use the Storage preview endpoint to transform images. By the end, you'll be able to integrate image transformations into your app without touching an image editor.

Let's get started.

# Why dynamic image transformations?

Here are some of the benefits of transforming images dynamically:

1. **Optimize performance**
Uncompressed images can slow down your app and increase bandwidth usage. Appwrite allows you to dynamically resize and compress images, improving load times and reducing network costs.
2. **Maintain a consistent UI**
By adjusting borders, border-radius, and background color, you can ensure images match your app's theme and display correctly across different screen sizes.
3. **Improve user experience**
You can crop, rotate, and adjust opacity to fine-tune how images appear. This is useful for dynamic UI elements like profile pictures, cards, and galleries.
4. **Built-in caching**
Appwrite caches transformed images, which reduces processing time and ensures faster repeat requests.

# How image transformation works in Appwrite

Appwrite's **Storage preview endpoint** applies transformations dynamically when retrieving an image. The original file remains unchanged, while Appwrite generates a modified version on-the-fly and returns the transformed image.

Here's an example of how to transform an image. With each example, we'll use the Appwrite Storage SDK to show the actual result:

```jsx
import { Client, Storage } from 'appwrite'

const client = new Client()
const storage = new Storage(client)

client
.setEndpoint('<https://cloud.appwrite.io/v1>') // API Endpoint
.setProject('<PROJECT_ID>') // Project ID

const result = storage.getFilePreview(
'photos', // Bucket ID
'sunset.png', // File ID
1600, // Width
0, // Height (ignored if 0)
'center', // Cropping gravity
90, // Quality (1-100)
5, // Border width
'FD346E', // Border color (hex)
15, // Border radius
1, // Opacity (0-1)
0, // Rotation (degrees)
'FFFFFF', // Background color
'webp', // Output format
)
```

{% storage_image just_img=true file_id="cat-image" width=1600 height=0 gravity="center" quality=90 border_width=5 border_color="FD346E" border_radius=15 opacity=1 rotation=0 background_color="FFFFFF" output="webp" /%}


This returns a new URL for the transformed image, which can be used directly in your app. Let's break down the parameters:

# 1. Resizing the image

Resizing is one of the most common transformations. Whether you're displaying thumbnails, profile pictures, or high-resolution banners, controlling the width and height ensures that images fit well within your design. Appwrite allows you to set:

- **width**: 0-4000 pixels (Resizes while maintaining aspect ratio if height is not provided)
- **height**: 0-4000 pixels (Resizes while maintaining aspect ratio if width is not provided)

If only one dimension is set, Appwrite adjusts the other proportionally.

**Example:**

```jsx
const previewUrl = storage.getFilePreview(
'bucketID',
'fileID',
1600, // Width
600, // Height
)
```

{% storage_image just_img=true file_id="cat-image" width=1600 height=600 /%}

# 2. Cropping with gravity

Cropping allows you to remove unnecessary parts of an image and focus on the important area. The **gravity** parameter controls which part of the image remains visible when cropping.

## Common use cases

- Ensuring a profile picture always centers on a face
- Keeping product images aligned in an e-commerce store
- Removing excess background in UI components

## Gravity options

- `center` (default)
- `top-left`, `top`, `top-right`
- `left`, `right`
- `bottom-left`, `bottom`, `bottom-right`

**Example:**

```jsx
const previewUrl = storage.getFilePreview(
'bucketID',
'fileID',
1600,
1600,
'top-left', // Setting gravity to focus on top-left portion
)
```

{% storage_image just_img=true file_id="cat-image" width=1600 height=1600 gravity="top-left" /%}

# 3. Adjusting image quality

The **quality** parameter controls image compression, helping to balance clarity and file size.

- **Higher values (80-100)**: Retain more detail but result in larger file sizes.
- **Lower values (10-50)**: Reduce file size significantly but may introduce visible compression artifacts.

**Example:**

```jsx
const compressedImage = storage.getFilePreview(
'bucketID',
'fileID',
1600,
800,
'center',
10, // Quality
)
```

{% storage_image just_img=true file_id="cat-image" width=1600 height=800 gravity="center" quality=10 /%}

# 4. Adding borders and border radius

Borders help separate images from the background, while border radius adds rounded corners for a softer appearance.

- **borderWidth**: 0-100px
- **borderColor**: Hex color code (without `#`)
- **borderRadius**: 0-4000px (Higher values create more rounded corners)

**Example:**

```jsx
const previewUrl = storage.getFilePreview(
'bucketID',
'fileID',
1600,
1000,
'center',
100,
8, // border width
'FF3366', // border color
80 // border radius
)
```

{% storage_image just_img=true file_id="cat-image" width=1600 height=1000 gravity="center" quality=100 border_width=8 border_color="FF3366" border_radius=80 /%}

# 5. Controlling opacity

Setting **opacity** allows images to blend into backgrounds or appear as overlays.

- `0 = Fully transparent`
- `1 = Fully opaque`

**Example:**

```jsx
const overlayImage = storage.getFilePreview(
'bucketID',
'fileID',
1600,
1000,
'center',
100,
0,
'',
0,
0.3, // Opacity
)
```

{% storage_image just_img=true file_id="cat-image" width=1600 height=1000 gravity="center" quality=100 opacity=0.3 /%}

# 6. Rotating an Image

The **rotation** parameter allows you to rotate an image by a specified number of degrees.

- **0-360** degrees

**Example:**

```jsx
// 45-degree rotation with padding
const rotatedImage = storage.getFilePreview(
'bucketID',
'fileID',
400,
400,
'center',
100,
0,
'',
0,
1,
45, // Rotation
)
```

{% storage_image just_img=true file_id="cat-image" width=400 height=400 gravity="center" quality=100 rotation=45 background_color="FFFFFF" /%}

# 7. Changing background color

For transparent images (like PNGs), you can set a background color.

- **Hex color code** (without `#`)

**Example:**

```jsx
const previewUrl = storage.getFilePreview(
'bucketID',
'fileID',
1600,
800,
'center',
100,
0,
'',
0,
0.7, // Partial transparency to show background
0,
'FF9900' // Bright orange background
)
```

{% storage_image just_img=true file_id="cat-image" width=1600 height=800 gravity="center" quality=100 opacity=0.7 background_color="FF9900" /%}

# Final thoughts

With just a few lines of code, Appwrite's [image transformations](https://appwrite.io/docs/products/storage/images) eliminate the need for:

- Multiple image versions cluttering your storage
- Complex client-side image processing
- Manual image editing for each use case
- Third-party image processing services

Try replacing your next image processing task with a single API call, and you might be surprised how much time and performance you can gain.

Check out the [docs](https://appwrite.io/docs/storage) for more information on how to use Appwrite Storage.

# Further reading

- [Building a full-stack app with Svelte and Appwrite](https://appwrite.io/blog/post/build-fullstack-svelte-appwrite)
- [Setting up route protection in React Native](https://appwrite.io/blog/post/setting-up-route-protection-in-react-native)
- [A technical deep dive into image classification](https://appwrite.io/blog/post/image-classification)