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 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 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
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
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 to quickly pick border and background colors. Complete source code is available in GitHub repository
Here is how it looks:
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.
Here is how it looks
<!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
Learn More
- Checkout Appwrite's Github Repo.
- Our Discord Server is the place to be if you ever get stuck.
- You can find all our Documentation here.
Top comments (0)