Images are undoubtedly the most often used visual elements in today’s digital environment. They are effective tools for communication and visual presentations and are used everywhere, from marketing materials to artistic movements to memes about cats.
However, the importance of serving users images in the right format to ensure that the necessary information is conveyed cannot be overstated. Not everyone can interpret an image the same way, and if you’re trying to get a certain point across, there’s no better way than making it the focal point. One common method for achieving this is image cropping.
In this article, we’ll show you how to build an image cropper functionality in your Angular projects using Cloudinary.
In this article:
What is Image Cropping?
Image cropping is a technique that involves trimming the edges of an image to improve framing, alter the aspect ratio, or focus the viewer’s attention on a particular part of the image. This process can eliminate unwanted components from the picture or adjust its composition to better fit the design aesthetics or functionality requirements of a webpage, application, or marketing materials.
Essentially, image cropping allows you to redefine the boundaries of your image to ensure only the most important elements remain visible.
Cropping an image is often done for a wide range of reasons. These include removing sensitive and personal information, compressing file size, focusing on an image’s specific area of interest, changing an image’s shape and aspect ratio, and so on.
Cropping Images with Cloudinary
In this section, we’ll show you how to use the @cloudinary/url-gen
package, which simplifies the generation of transformation URLs and includes special components and directives that allow you to integrate media assets easily in your Angular applications.
Prerequisites
Before you continue with this guide, we expect you’re familiar with HTML and CSS and have a good knowledge of JavaScript and Angular. If you’re not, check out the following resources before continuing.
You’ll also need to make sure you have the following prerequisites installed:
- Node.js and npm (Node Package Manager)
- Angular CLI (
npm install -g @angular/cli
) - A Cloudinary account (which you can sign up for a free account if you don’t have one)
Step 1: Setting up an Angular Project
First, create a new Angular project using the Angular CLI:
ng new angular-image-cropper`
Navigate to the project directory:
cd image-cropper-app
npm install @cloudinary/ng @cloudinary/url-gen
Finally, we’ll need to change one of our settings within Cloudinary before we can get started. Go to your Cloudinary dashboard and navigate to Settings > Security, set the Strict transformation option to disabled, as shown below, to allow the dynamic creation of new derived assets.
Step 2 – Import required packages
In this step, we import the necessary modules and components from Angular and Cloudinary and create a new instance of the Cloudinary object with our cloud name.
Open the src/app/app.component.ts
and replace its content with the following:
import { Component, CUSTOM_ELEMENTS_SCHEMA} from '@angular/core';import { CommonModule } from '@angular/common';import { Cloudinary, CloudinaryImage } from '@cloudinary/url-gen';import {fill} from "@cloudinary/url-gen/actions/resize";import {focusOn} from "@cloudinary/url-gen/qualifiers/gravity";import {FocusOn} from "@cloudinary/url-gen/qualifiers/focusOn";import {autoGravity} from "@cloudinary/url-gen/qualifiers/gravity";// Create and configure your Cloudinary instance.const cld = new Cloudinary({ cloud: { cloudName: '<YOUR_CLOUDINARY_CLOUDNAME>' } });
Make sure to replace <YOUR_CLOUDINARY_CLOUDNAME>
with your unique Cloudinary cloud name, which you can find within your dashboard.
Step 3 – Create Our Image Transformation Functions
Let’s add the code that will crop the uploaded images:
// Fill cropping with face detection gravity const fillCroppingWithFaces = (imageId: string) => { const myImage = cld.image(imageId); myImage.resize(fill().width(250).height(250).gravity(focusOn(FocusOn.faces()))); return myImage.toURL(); }; // Automatic gravity cropping const autoGravityCropping = (imageId: string) => { const myImage = cld.image(imageId); myImage.resize(fill().width(200).height(300).gravity(autoGravity())); return myImage.toURL(); };
- The
fillCroppingWithFaces
function takes the image ID as input, creates a new Cloudinary image object from it, and resizes the image to 250×250 pixels while applying a gravity effect that focuses on faces in the image using thefocusOn(FocusOn.faces())
qualifier. In this cropping mode, Cloudinary automatically crops the image to focus on faces detected in the image. - The
autoGravityCropping
function also takes the image ID as input, creates a new Cloudinary image object from it, and resizes the image to 200×300 pixels with theautoGravity()
qualifier applied to automatically apply a gravity effect. The gravity parameter allows you to select which area or object to extract in the image. You can learn more about it here.
Step 4 – Component Definition
Next, add the following code to define the component’s template and create the AppComponent
class component:
@Component({ selector: 'app-root', standalone: true, imports: [CommonModule], schemas: [CUSTOM_ELEMENTS_SCHEMA], template: ` <input type="file" (change)="onFileSelected($event)" /> <button (click)="uploadImage()" [disabled]="!selectedImage">Upload Image</button> <div *ngIf="originalImageUrl"> <h2>Original Image</h2> <img [src]="originalImageUrl" alt="Original Image" style="width: 50vw" /> </div> <div *ngIf="fillCroppingWithFacesUrl"> <h2>Fill Cropping with Face Detection Gravity</h2> <img [src]="fillCroppingWithFacesUrl" alt="Fill Cropping with Face Detection Gravity" /> </div> <div *ngIf="autoGravityCroppingUrl"> <h2>Automatic Gravity Cropping</h2> <img [src]="autoGravityCroppingUrl" alt="Automatic Gravity Cropping" /> </div> ` }) export class AppComponent { // ... }
Step 5 – Handle File Upload
Next, add the following code to the AppComponent
class to create the logic for handling file upload:
export class AppComponent { selectedImage: string | null = null; originalImageUrl: string | null = null; fillCroppingWithFacesUrl: string | null = null; autoGravityCroppingUrl: string | null = null; cloudName = '<YOUR_CLOUDINARY_CLOUDNAME>'; // Replace with your Cloudinary cloud name uploadPreset = 'YOUR_UPLAOD_PRESET_NAME'; // Replace with your Cloudinary upload preset onFileSelected(event: any) { const file = event.target.files[0]; const reader = new FileReader(); reader.onload = () => { this.selectedImage = reader.result as string; }; reader.readAsDataURL(file); } }
Since we’re using unauthenticated upload requests, which allow us to perform uploads without generating an authentication signature on the backend, we need to use an upload preset to control unsigned requests.
To enable unsigned uploads, navigate to the Upload page in your Cloudinary dashboard. You can also create an upload preset on the Upload Presets page within your settings.
Step 6 – Upload the Image File to Cloudinary
While we’re still in the Appcomponent
component, add the following code to handle the logic for sending the uploaded image to Cloudinary:
export class AppComponent { // ... uploadImage() { if (this.selectedImage) { const file = this.dataURItoBlob(this.selectedImage); const formData = new FormData(); formData.append('file', file); formData.append('upload_preset', this.uploadPreset); fetch(`https://api.cloudinary.com/v1_1/${this.cloudName}/upload`, { method: 'POST', body: formData }) .then(response => response.json()) .then(data => { console.log('Image uploaded:', data); this.originalImageUrl = data.secure_url; this.updateCroppedImages(data.public_id); }) .catch(error => { console.error('Error uploading image:', error); }); } } }
Step 7 – Create a Helper Method
Next, below the uploadImage
method, add the following code:
updateCroppedImages(publicId: string) { this.fillCroppingWithFacesUrl = fillCroppingWithFaces(publicId); this.autoGravityCroppingUrl = autoGravityCropping(publicId); } dataURItoBlob(dataURI: string) { const byteString = atob(dataURI.split(',')[1]); const mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]; const ab = new ArrayBuffer(byteString.length); const ia = new Uint8Array(ab); for (let i = 0; i < byteString.length; i++) { ia[i] = byteString.charCodeAt(i); } return new Blob([ab], { type: mimeString }); }
In the code above:
- The
updateCroppedImages
function updates the transformation functions with the uploaded image’s Cloudinary public ID so that each cropping transformation can be applied to the image. - The
dataURItoBlob
function is a helper function that converts the uploaded image’s data URL to a Blob object so we can upload it to Cloudinary.
Trying it Out
Finally, we can run npm run start
to start up the application. Here’s what the result of the code looks like:
You can find the complete code for this guide on GitHub.
Wrapping Up
Whether you are building an e-commerce platform to showcase products, creating a social networking site where users can upload profile pictures, or developing any application that requires custom image inputs, Angular and Cloudinary offer a powerful combination for developers. With Cloudinary’s cloud-based approach, managing and manipulating images becomes less resource-intensive, ensuring your app remains fast and responsive.
Leverage the power of Cloudinary within your Angular applications to crop images and optimize and deliver them efficiently across all devices. Whether you’re an experienced developer or just starting, Cloudinary’s extensive documentation and supportive community make it accessible to integrate and use.
Don’t miss out on the opportunity to create more engaging and visually appealing web applications. Dive into Cloudinary today and elevate your Angular projects to the next level.