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.
The final project can be viewed on Codesandbox.
You can find the full source code on my Github repository.
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.
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.
yarn create nuxt-app nuxtjs-profile-picture-generator
# OR
npx create-nuxt-app nuxtjs-profile-picture-generator
# OR
npm init nuxt-app nuxtjs-profile-picture-generator
Code language: PHP (php)
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:
cd nuxtjs-profile-picture-generator
yarn dev
# OR
npm run dev
Code language: PHP (php)
The application will now be running on http://localhost:3000
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.
yarn add @nuxtjs/cloudinary
# OR
npm install @nuxtjs/cloudinary
Code language: CSS (css)
Once installed, add it to the modules
section of our nuxt.config.js
file:
// nuxt.config.js
export default {
....
modules: [
'@nuxtjs/cloudinary'
]
...
}
Code language: JavaScript (javascript)
We will now configure our Cloudinary instance by adding a cloudinary
section in our nuxt.config.js
file:
// nuxt.config.js
export default {
...
cloudinary: {
cloudName: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,
useComponent: true,
secure: true
}
}
Code language: JavaScript (javascript)
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:
touch .env
Code language: CSS (css)
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
<!-- .env -->
NUXT_ENV_CLOUDINARY_CLOUD_NAME=<your-cloud-name>
Code language: HTML, XML (xml)
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.
<!-- pages/index.vue -->
...
<form v-else @submit.prevent="upload">
<input
type="file"
name="file"
@change="handleFile"
/>
<p v-if="uploading">Uploading...</p>
<button
v-else-if="image"
type="submit"
>
Convert
</button>
</form>
...
Code language: HTML, XML (xml)
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.
// pages/index.vue
<script>
export default {
data() {
return {
uploading: false,
image: null,
cloudinaryImage: null,
};
},
...
methods: {
async handleFile(e) {
this.image = e.target.files[0];
},
async readData(f) {
return new Promise((resolve) => {
const reader = new FileReader();
reader.onloadend = () => resolve(reader.result);
reader.readAsDataURL(f);
});
},
async upload() {
this.uploading = true;
const imageData = await this.readData(this.image);
this.cloudinaryImage = await this.$cloudinary.upload(imageData, {
upload_preset: "default-preset",
folder: "nuxtjs-profile-picture-generator",
});
this.uploading = false;
},
},
};
</script>
Code language: HTML, XML (xml)
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.
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.
// pages/index.vue
<script>
export default {
...
computed: {
imageUrl() {
return this.cloudinaryImage
? this.$cloudinary.image.url(this.cloudinaryImage.public_id, {
gravity: "faces",
height: 200,
width: 200,
crop: "thumb",
})
: "https://via.placeholder.com/200";
},
},
...
};
</script>
Code language: HTML, XML (xml)
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.
<!-- pages/index.vue -->
<template>
...
<img :src="imageUrl" />
...
<a
v-if="cloudinaryImage"
target="_blank"
:href="imageUrl"
>
Download
</a>
...
</template>
Code language: HTML, XML (xml)
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.