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-generator23# OR45npx create-nuxt-app nuxtjs-profile-picture-generator67# OR89npm 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-generator2345yarn dev67# OR89npm 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/cloudinary23# OR45npm install @nuxtjs/cloudinary
Once installed, add it to the modules
section of our nuxt.config.js
file:
1// nuxt.config.js23export default {45....67modules: [89'@nuxtjs/cloudinary'1011]1213...1415}
We will now configure our Cloudinary instance by adding a cloudinary
section in our nuxt.config.js
file:
1// nuxt.config.js23export default {45...67cloudinary: {89cloudName: process.env.NUXT_ENV_CLOUDINARY_CLOUD_NAME,1011useComponent: true,1213secure: true1415}1617}
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 -->23NUXT_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 -->23...45<form v-else @submit.prevent="upload">67<input89type="file"1011name="file"1213@change="handleFile"1415/>1617<p v-if="uploading">Uploading...</p>1819<button2021v-else-if="image"2223type="submit"2425>2627Convert2829</button>3031</form>3233...
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.vue23<script>45export default {67data() {89return {1011uploading: false,1213image: null,1415cloudinaryImage: null,1617};1819},2021...2223methods: {2425async handleFile(e) {2627this.image = e.target.files[0];2829},3031async readData(f) {3233return new Promise((resolve) => {3435const reader = new FileReader();3637reader.onloadend = () => resolve(reader.result);3839reader.readAsDataURL(f);4041});4243},4445async upload() {4647this.uploading = true;4849const imageData = await this.readData(this.image);5051this.cloudinaryImage = await this.$cloudinary.upload(imageData, {5253upload_preset: "default-preset",5455folder: "nuxtjs-profile-picture-generator",5657});5859this.uploading = false;6061},6263},6465};6667</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.vue23<script>45export default {67...89computed: {1011imageUrl() {1213return this.cloudinaryImage1415? this.$cloudinary.image.url(this.cloudinaryImage.public_id, {1617gravity: "faces",1819height: 200,2021width: 200,2223crop: "thumb",2425})2627: "https://via.placeholder.com/200";2829},3031},3233...3435};3637</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 -->23<template>45...67<img :src="imageUrl" />89...1011<a1213v-if="cloudinaryImage"1415target="_blank"1617:href="imageUrl"1819>2021Download2223</a>2425...2627</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.