Nuxtjs Profile Picture Generator

Eugene Musebe

Introduction

Getting profile images seems like a simple task until we realize that most users just have normal solo photos of themselves. This means that they are not just headshots and the user’s face can be anywhere in the image. We thus need a smart way to obtain the headshots from user uploads. Let us learn how we can build this into our applications.

Codesandbox

The final project can be viewed on Codesandbox.

You can find the full source code on my Github repository.

Prerequisites

We will use Vue.Js to build this project. It defines itself as an intuitive JavaScript framework. Knowledge of Vue.Js is not required but some understanding of HTML, CSS, and JavaScript is required.

Setup

Nuxt.Js setup

Nuxt.Js is an intuitive Vue.Js framework that allows us to build powerful and simple web applications.

To set up our project we will use the create-nuxt-app utility. To use it, make sure you have Yarn or NPM v5.2+ or v6.1+ installed. Open your terminal in your preferred working directory.

1yarn create nuxt-app nuxtjs-profile-picture-generator
2
3# OR
4
5npx create-nuxt-app nuxtjs-profile-picture-generator
6
7# OR
8
9npm init nuxt-app nuxtjs-profile-picture-generator

The above will trigger a set of setup questions. Here are our recommended defaults:

Project name: nuxtjs-profile-picture-generator

Programming language: JavaScript

Package manager: Yarn

UI framework: TailwindCSS

Nuxt.Js modules: N/A

Linting tools: N/A

Testing framework: None

Rendering mode: Universal (SSR/SSG)

Deployment target: Server (Node.js hosting)

Development tools: N/A

What is your Github username: <your-github-username>

Once setup is complete, feel free to enter and run the project:

1cd nuxtjs-profile-picture-generator
2
3
4
5yarn dev
6
7# OR
8
9npm run dev

The application will now be running on http://localhost:3000

@nuxtjs/cloudinary setup

The platform we will use to handle our media is called Cloudinary.

We will install the recommended Nuxt.Js plugin: @nuxtjs/cloudinary. To install it, open the terminal in the project folder.

1yarn add @nuxtjs/cloudinary
2
3# OR
4
5npm install @nuxtjs/cloudinary

Once installed, add it to the modules section of our nuxt.config.js file:

1// nuxt.config.js
2
3export default {
4
5....
6
7modules: [
8
9'@nuxtjs/cloudinary'
10
11]
12
13...
14
15}

We will now configure our Cloudinary instance by adding a cloudinary section in our nuxt.config.js file:

1// nuxt.config.js
2
3export default {
4
5...
6
7cloudinary: {
8
9cloudName: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
10
11useComponent: true,
12
13secure: true
14
15}
16
17}

Here is our first encounter with environmental variables. These are values we configure outside of our project code. This is because they are either too sensitive to be in a code repository or because they are dependent on the environment in which our code is deployed. Let us create our env file:

1touch .env

To obtain your Cloudinary cloud name, check the Account Details on your dashboard. If you don't have an account, feel free to create one.

Add your cloud name to your env file

1<!-- .env -->
2
3NUXT_ENV_CLOUDINARY_CLOUD_NAME=<your-cloud-name>

Uploading your image

The first step will be enabling our app users to select and upload their full pictures. Let us create an HTML form to achieve this.

1<!-- pages/index.vue -->
2
3...
4
5<form v-else @submit.prevent="upload">
6
7<input
8
9type="file"
10
11name="file"
12
13@change="handleFile"
14
15/>
16
17<p v-if="uploading">Uploading...</p>
18
19<button
20
21v-else-if="image"
22
23type="submit"
24
25>
26
27Convert
28
29</button>
30
31</form>
32
33...

When a file is selected, the handleFile method will be called to set the selected file in the current state. The upload method is responsible for taking the selected file, reading its contents, and uploading it to Cloudinary.

1// pages/index.vue
2
3<script>
4
5export default {
6
7data() {
8
9return {
10
11uploading: false,
12
13image: null,
14
15cloudinaryImage: null,
16
17};
18
19},
20
21...
22
23methods: {
24
25async handleFile(e) {
26
27this.image = e.target.files[0];
28
29},
30
31async readData(f) {
32
33return new Promise((resolve) => {
34
35const reader = new FileReader();
36
37reader.onloadend = () => resolve(reader.result);
38
39reader.readAsDataURL(f);
40
41});
42
43},
44
45async upload() {
46
47this.uploading = true;
48
49const imageData = await this.readData(this.image);
50
51this.cloudinaryImage = await this.$cloudinary.upload(imageData, {
52
53upload_preset: "default-preset",
54
55folder: "nuxtjs-profile-picture-generator",
56
57});
58
59this.uploading = false;
60
61},
62
63},
64
65};
66
67</script>

The image file will be uploaded to the nuxtjs-profile-picture-generator folder using the default-preset upload preset. Upload presets are a set of rules we preconfigure to be applied to our uploads. To create an upload preset, proceed to the add upload preset page. Here are our recommended defaults:

Name: default-preset

Mode: unsigned

Unique filename: true

Delivery type: upload

Access mode: public

Once the file is uploaded, we store it in the cloudinaryImage variable.

Obtaining the profile picture

To get the profile picture, we will be using Cloudinary's inbuilt facial-detection transformations. The face gravity moves the crop cursor onto the face recognized in the image. This ensures that the face is in the center of the image. We then crop around the face. We use the thumb crop setting to ensure we get a thumbnail of the image based on the gravity setting.

1// pages/index.vue
2
3<script>
4
5export default {
6
7...
8
9computed: {
10
11imageUrl() {
12
13return this.cloudinaryImage
14
15? this.$cloudinary.image.url(this.cloudinaryImage.public_id, {
16
17gravity: "faces",
18
19height: 200,
20
21width: 200,
22
23crop: "thumb",
24
25})
26
27: "https://via.placeholder.com/200";
28
29},
30
31},
32
33...
34
35};
36
37</script>

We can now render the image for the app user to view the result. On top of this, let us add a download button to download the image.

1<!-- pages/index.vue -->
2
3<template>
4
5...
6
7<img :src="imageUrl" />
8
9...
10
11<a
12
13v-if="cloudinaryImage"
14
15target="_blank"
16
17:href="imageUrl"
18
19>
20
21Download
22
23</a>
24
25...
26
27</template>

Conclusion

With the above application, we can dynamically get quality profile pictures from our user's uploads. Read more on Cloudinay's face-detection based transformations to understand other ways we can apply these wonderful algorithms in our applications.

Eugene Musebe

Software Developer

I’m a full-stack software developer, content creator, and tech community builder based in Nairobi, Kenya. I am addicted to learning new technologies and loves working with like-minded people.