Appwrite Image Previews Receive Massive New Updates
Tags: appwrite, image, storage, firebase
Published: 2021-07-05 09:19:53

Hey everyone, we have just pushed a massive update to the image preview API with few new image manipulation functionalities. Along with existing features like cropping, converting the output format, and adjustable image quality, we now support border (borderWidth and borderColor parameters), border radius (borderRadius parameter), opacity, and rotation parameters to manipulate images.

In this tutorial, we will learn how we can leverage those features to manipulate images to our liking without using any external services. So let us get started.

## Setting up the project
Before you continue with tutorial, make sure you have a hosted version of Appwrite, either locally or on a cloud. If not please go through our [docs](https://appwrite.io/docs) to install a local instance of Appwrite. You only need Docker to install and run Appwrite.

Once you have the project set up, you can upload few images to storage from the Appwrite console. Then we can use those image file IDs in the following examples to preview the result.

You can use any of our client SDKs or even [the REST API directly](https://medium.com/appwrite-io/how-to-connect-with-the-appwrite-backend-server-directly-using-only-the-appwrite-http-api-1e720b567395) to make a request to the Preview endpoint. In this tutorial we will be using both our Flutter and Web SDKs to make a request to preview images.

## Example requests
So, in order to use the newly introduced image capabilities, you can make a request using the Appwrite's storage service to the file preview endpoint. A request will look like following.

### Flutter

```dart
Storage storage = Storage(client);
final res = await storage.getFilePreview(
    fileId: fileId, //id of an existing file in the Appwrite Storage
    width: 600, // crop image to the width
    borderWidth: 5, //border width in pixels
    borderColor: 'ff0000', //hex color value without #
    borderRadius: 50, //border radius in pixels
    opacity: 0.8, //opacity between 0-1
    rotation: 45, //rotation between 0-360
    background: 'ff0000', // hex color value without #
    output: 'png', //output image format
)
```
The Above request will return a `Future<Response>` where the response is provided by `dio` package. And the `res.data` will consist of the Unit8List of bytes of the image, that you can preview in Flutter using `Image.memory(res.data)`.

### Web
```js
var appwrite = new Appwrite();
//appwrite.storage.getFilePreview(fileId, width, height, quality, borderWidth, borderColor, borderRadius, opacity, rotation, background, output)
final url = appwrite.storage.getFilePreview(fileId, 800, 0, 100, 5, 'ff0000', 50, 0.8, 45, 'ff0000', 'png');
```
The above request will return a URL, which can be used as a `src` attribute for an `<img>` in order to display the preview image.


## A Complete Example with Flutter SDK
Below is a complete example, where you can change different values to see the preview.
I am using [fast_color_picker](https://pub.dev/packages/fast_color_picker) to quickly pick border and background colors. Complete source code is available in [GitHub repository](https://github.com/lohanidamodar/image_api_features)

Here is how it looks:

![Flutter Demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/l434024hhihfmbfaf4af.png)

```dart
import 'package:appwrite/appwrite.dart';
import 'package:fast_color_picker/fast_color_picker.dart';
import 'package:flutter/material.dart';

const String fileId = "606ec6f150dc6"; //file id of the file from the storage
final String endPoint = "<https://localhost/v1>" // your endpoint
const String project = "606eba7792442"; // your project id

void main() {
  runApp(MyApp());
}

class MyApp extends StatelessWidget {
  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: 'Appwrite Image API',
      theme: ThemeData(
        primarySwatch: Colors.pink,
      ),
      home: HomePage(),
    );
  }
}

class HomePage extends StatefulWidget {
  @override
  _HomePageState createState() => _HomePageState();
}

class _HomePageState extends State<HomePage> {
  double borderRadius = 0;
  double borderWidth = 0;
  Color borderColor = Colors.red;
  Color backgroundColor = Colors.white;
  double opacity = 1;
  Client client = Client();
  Storage storage;

  @override
  void initState() {
    super.initState();
    client
        .setEndpoint(endPoint)
        .setProject(project)
        .setSelfSigned(); //use self signed only in development
    storage = Storage(client);
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: Text("Image API features"),
      ),
      body: ListView(
        children: [
          FutureBuilder(
            future: storage.getFilePreview(
              fileId: fileId,
              width: 600,
              borderWidth: borderWidth.toInt(),
              borderColor: borderColor != null
                  ? "${borderColor.value.toRadixString(16).substring(2)}"
                  : null,
              borderRadius: borderRadius.toInt(),
              opacity: opacity,
              background: backgroundColor != null
                  ? "${backgroundColor.value.toRadixString(16).substring(2)}"
                  : null,
              output: 'png',
            ),
            builder: (context, snapshot) {
              if (snapshot.hasData)
                return Padding(
                  padding: const EdgeInsets.all(16.0),
                  child: Image.memory(
                    snapshot.data.data,
                    fit: BoxFit.contain,
                  ),
                );
              return CircularProgressIndicator();
            },
          ),
          Row(
            children: [
              const SizedBox(width: 10.0),
              Text("BR"),
              Expanded(
                child: Slider(
                  label: "$borderRadius",
                  value: borderRadius,
                  min: 0,
                  max: 200,
                  divisions: 10,
                  onChanged: (val) {
                    setState(() {
                      borderRadius = val;
                    });
                  },
                ),
              ),
            ],
          ),
          Row(
            children: [
              const SizedBox(width: 10.0),
              Text("BW"),
              Expanded(
                child: Slider(
                  label: "$borderWidth",
                  value: borderWidth,
                  min: 0,
                  max: 10,
                  divisions: 5,
                  onChanged: (val) {
                    setState(() {
                      borderWidth = val;
                    });
                  },
                ),
              ),
            ],
          ),
          Row(
            children: [
              const SizedBox(width: 10.0),
              Text("OP"),
              Expanded(
                child: Slider(
                  label: "$opacity",
                  value: opacity,
                  min: 0,
                  max: 1,
                  divisions: 5,
                  onChanged: (val) {
                    setState(() {
                      opacity = val;
                    });
                  },
                ),
              ),
            ],
          ),
          Row(
            children: [
              const SizedBox(width: 10.0),
              Text("Border"),
              const SizedBox(width: 10.0),
              Expanded(
                child: FastColorPicker(
                  onColorSelected: (color) {
                    setState(() {
                      borderColor = color;
                    });
                  },
                  selectedColor: borderColor,
                ),
              ),
            ],
          ),
          Row(
            children: [
              const SizedBox(width: 10.0),
              Text("Background"),
              const SizedBox(width: 10.0),
              Expanded(
                child: FastColorPicker(
                  onColorSelected: (color) {
                    setState(() {
                      backgroundColor = color;
                    });
                  },
                  selectedColor: backgroundColor,
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }
}

```

## A Complete Example with Web SDK
Below is a simple example where we can change different values and see the preview image change. I am using web SDK from CDN. Complete source code can be found in [GitHub repository](https://github.com/lohanidamodar/image-api-features-web).

Here is how it looks

![Web Demo](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/bsjola228uzjgyde4zis.png)

```html
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
</head>

<body>
    <img id="image" src="" />
    <form>
        <label for="opacity">Opacity</label>
        <input type="range" id="opacity" name="opacity" min="0" max="1" value="1" step="0.1">
        <br>

        <label for="border-radius">Border Radius</label>
        <input type="range" id="border-radius" name="borderRadius" min="0" max="500" value="90" step="10">
        <br>

        <label for="border-width">Border Width</label>
        <input type="range" id="border-width" name="borderWidth" min="0" max="30" value="5" step="10">
        <br>

        <label for="border-color">Border Color</label>
        <input type="color" id="border-color" name="borderColor" value="#ffffff">
        <br>

        <label for="background">Background</label>
        <input type="color" id="background" name="background" value="#ffffff">
        <br>
    </form>
    <script src="https://cdn.jsdelivr.net/npm/appwrite@3.0.5"></script>
    <script>
        var appwrite = new window.Appwrite.Appwrite();
        appwrite
            .setEndpoint('https://demo.appwrite.io/v1')
            .setProject('607fce4176685');

        var fileId = "60b8c432cf0f6";
        var image = document.getElementById('image');
        var form = document.querySelector('form');
        var url = appwrite.storage.getFilePreview(fileId, 800, 0, 100, 0, '', 0, 1, 0, '', 'png');
        form.addEventListener('change', e => {
            var data = Object.fromEntries(new FormData(form));
            for (const key in data) {
                data[key] = data[key].replace('#', '');
            }
            image.src = appwrite.storage.getFilePreview(
                fileId, 
                800, 
                0, 
                100, 
                data.borderWidth, 
                data.borderColor, 
                data.borderRadius, 
                data.opacity, 
                0, 
                data.background);
        });
    </script>
</body>

</html>
```

### References

- [Appwrite Discord](https://appwrite.io/discord)
- [Appwrite Documentation](https://appwrite.io/docs)
- [Appwrite Homepage](https://appwrite.io)

## Learn More

* Checkout [Appwrite's](https://github.com/appwrite/appwrite) Github Repo.
* [Our Discord Server](https://appwrite.io/discord) is the place to be if you ever get stuck.
* You can find all our Documentation [here](https://appwrite.io/docs).