Front-End Development Mastering Image Alignment: Centering Images with HTML & CSS Adding Video to Your React Native App with react-native-video HTML Image Slider: Do It Yourself and 1-Step Image Gallery Widget How to Effectively Manage Digital Assets in a PHP Image Gallery Introducing Angular Image Editor: Your New Editing Too Mastering Javascript Image Annotation Mastering JavaScript Image Popup Python Video Player: 3 Free Options and a Quick Tutorial Image Recognition Machine Learning: Use Cases and Common Algorithms HTML/CSS: How to Center Images Vertically and Horizontally How to Create an Image Map Understand CSS Background Position with 4 Simple Examples Java for Image Processing: 4 Libraries You Should Know Python Video Processing: 6 Useful Libraries and a Quick Tutorial Blur Image CSS: Two Ways to Blur Images for Gorgeous Effects Designing a Video Flipping App for Android Build an App for Embedding Video Watermarks on Android Devices Change Image on Hover with HTML and CSS How to Align Images with CSS Full Page Background Image with CSS: Tutorial and 5 Automation Tips Using CSS to Scale Page Elements and a Better Way to Scale Your Images CSS Background Image: Quick Tutorial and 3 Automation Tips Featured Image: Best Practices to Feature Images on Your Website Image Gallery Websites: Tips and Tricks for a Stunning Image Gallery 6 Ways to Stretch a Background Image with CSS Auto Cropping for Images and Video: Features & Best Practices FLAC vs. WAV: 4 Key Differences and How to Choose Converting Audio to Video: A Practical Guide FLAC vs. AIFF: 5 Key Differences and How to Choose FLAC vs. MQA: 5 Key Differences and How to Choose Converting WAV Files To OGG The Ultimate Guide On Converting OGG Files To WAV Sound Choices: FLAC vs. MP3 AAC vs MP3 – The Future of Audio Files All about AIFF and how it compares to WAV and MP3 Integrating Cloudinary with Netlify Integrating Cloudinary with Svelte and SvelteKit Integrating Cloudinary with Nuxt Integrating Cloudinary with Gatsby File Upload as a Service: How It Works and 5 Leading Solutions Native Mobile App Development Creative Uses for CSS Inner Border and 3 Ways to Set a Border Integrating Cloudinary with Next.js Front-End Development: The Complete Guide

Introducing Angular Image Editor: Your New Editing Too

angular image editor

Photo editing apps play a significant role in our digital lives. Over 4 in 10 smartphone users regularly use photo editing apps, enhancing their photos and selfies before sharing them online. Whether you’re building a personal website, an e-commerce platform, or a content-rich application, image editing capabilities play a crucial role. That’s where an image editor comes into play—a versatile component that empowers developers to integrate image editing features into their Angular applications.

In this article, we’ll create an image editor in Angular. From resizing and rotating to adding attractive filters, this tool can simplify image manipulation while utilizing the robust capabilities of Cloudinary, a leading cloud-based media management platform.

In this article:

angular image editor

Features of Angular Image Editors

Angular Image Editors are powerful tools designed to integrate seamlessly into web applications, providing sophisticated features for manipulating images directly within the browser. Here’s a glimpse into what these editors can typically offer:

  • Layer Management – Enables the addition, removal, and adjustment of multiple layers within an image, akin to professional-grade software.
  • Undo/Redo Commands – Essential for a forgiving editing process, allowing users to experiment without fear of making irreversible mistakes.
  • Real-time Previews – Offers an immediate visual feedback loop, ensuring adjustments are seen instantaneously.
  • Customizable Filters and Effects – These editors let users easily enhance their images with basic brightness and contrast adjustments and more complex effects like blurs and color corrections.
  • Annotation Tools – A suite of annotation options, including text addition, shapes, and drawing tools for detailed image markups.
  • Placeholders/icons: Provides placeholder images/icons for intros, error states, or building out UI mockups.
  • Responsive Design – Ensures the editor’s interface is accessible and user-friendly across all device sizes, from desktops to mobile phones.
  • Integration Capabilities – Designed to fit smoothly into Angular applications, these editors can be easily plugged into existing projects, enhancing their functionality without disrupting workflow.

Leveraging these features, Angular Image Editors empower developers to provide end-users with a rich, interactive experience directly in their web applications. By offering various tools and options, they bridge the gap between professional image editing and web-based applications, meeting the growing demand for in-browser creativity and customization.

angular image editor

Creating An Angular Image Editor

For this tutorial, we will create our image editor using Cloudinary’s various image transformation features. If you haven’t already, you can sign up for free. For now, we will use our Cloudinary API credentials, so head over to Cloudinary and log in to your account.

Next, click the Programmable Media button on your Cloudinary Programmable Media Dashboard. Copy these credentials, as we’ll need them to connect to Cloudinary’s cloud:

angular image editor

With this, we can begin creating our Angular app.

Setting Up and Creating Our Angular Image Editor

Before we begin creating our image editor, we will need to install Angular. To do this, simply run the following command:

npm install -g @angular/cli@17

Next, open up a sample project directory and use the following command to create a project:

ng new image-editor

This will create a new image-editor directory and generate the initial project structure. Navigate to the image-editor directory and open up the project in your IDE. Here, we will begin by installing the Cloudinary Angular JS SDK using the following command:

npm i @cloudinary/url-gen @cloudinary/ng

With this, our setup is complete, and we can begin coding our image editor. We will start by opening up the app.component.ts file in your project’s src/app directory. Here, we will first add some imports that will allow us to access Cloudinary’s features:

import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { CloudinaryModule } from '@cloudinary/ng';
import { Cloudinary, CloudinaryImage } from '@cloudinary/url-gen';
import { byAngle } from '@cloudinary/url-gen/actions/rotate';
import { fill } from '@cloudinary/url-gen/actions/resize';
import { sepia, grayscale, cartoonify } from '@cloudinary/url-gen/actions/effect';

Next, we will add a simple component decorator and start defining our AppComponent class:

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet, CloudinaryModule],
  templateUrl: './app.component.html',
})

Now, we will begin by creating two variables, img!, to store the Cloudinary image object, and imageId, to store the public ID of our image. Then, we declare a Cloudinary instance and initialize our Cloudinary API:

export class AppComponent implements OnInit {
  img!: CloudinaryImage;
  imageId: string = 'cld-sample';
  cld: Cloudinary; // Declare a Cloudinary instance

  constructor() {
    // Initialize Cloudinary configuration
    this.cld = new Cloudinary({
      cloud: {
        cloudName: 'your_cloud_name',
        apiKey: 'your_api_key',
        apiSecret: 'your_api_secret',
      },
    });

Next, we will use the ngOnInit() hook to load a default image and resize it to a width and height of 300 and 200, respectively:

  ngOnInit() {
    // Load the default image and resize it
    this.img = this.cld.image(this.imageId);
    this.img = this.cld.image(this.imageId).resize(fill().width(300).height(200));
  }

Now, we will create a loadImage() function that takes the public ID of an image as a parameter and loads it onto the app.

  loadImage(imageId: string) {
    this.imageId = imageId; // Update the imageId property
    this.img = this.cld.image(imageId);
    this.img = this.cld.image(this.imageId).resize(fill().width(300).height(200)); // Default dimensions of image
  }

Finally, we will define a transformImage() function that will use the effects selected on our app to transform our loaded image. Here is what our complete app.component.ts file looks like:

import { Component, OnInit } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterOutlet } from '@angular/router';
import { CloudinaryModule } from '@cloudinary/ng';
import { Cloudinary, CloudinaryImage } from '@cloudinary/url-gen';
import { byAngle } from '@cloudinary/url-gen/actions/rotate';
import { fill } from '@cloudinary/url-gen/actions/resize';
import { sepia, grayscale, cartoonify } from '@cloudinary/url-gen/actions/effect';

@Component({
  selector: 'app-root',
  standalone: true,
  imports: [CommonModule, RouterOutlet, CloudinaryModule],
  templateUrl: './app.component.html',
})
export class AppComponent implements OnInit {
  img!: CloudinaryImage;
  imageId: string = 'cld-sample';
  cld: Cloudinary; // Declare a Cloudinary instance

  constructor() {
    // Initialize Cloudinary configuration
    this.cld = new Cloudinary({
      cloud: {
        cloudName: 'your_cloud_name',
        apiKey: 'your_api_key',
        apiSecret: 'your_api_secret',
      },
    });
  }

  ngOnInit() {
    // Load the default image and resize it
    this.img = this.cld.image(this.imageId);
    this.img = this.cld.image(this.imageId).resize(fill().width(300).height(200));
  }

  loadImage(imageId: string) {
    this.imageId = imageId; // Update the imageId property
    this.img = this.cld.image(imageId);
    this.img = this.cld.image(this.imageId).resize(fill().width(300).height(200)); // Default dimensions of image
  }

  transformImage() {
    const selectedEffect = (<HTMLInputElement>document.querySelector('input[name="effect"]:checked')).value;
    const selectedRotation = parseInt((<HTMLInputElement>document.querySelector('input[name="rotate"]:checked')).value);
    const width = parseInt((<HTMLInputElement>document.querySelector('#imageWidth')).value);
    const height = parseInt((<HTMLInputElement>document.querySelector('#imageHeight')).value);


    switch (selectedEffect) { // Apply effect transformation
      case 'cartoonify':
        this.img = this.cld.image(this.imageId).effect(cartoonify())
        break;
      case 'sepia':
        this.img = this.cld.image(this.imageId).effect(sepia())
        break;
      case 'grayscale':
        this.img = this.cld.image(this.imageId).effect(grayscale())
        break;
      case 'none':
        break;
    }


  if (selectedRotation !== 0) { // Apply rotation
    this.img = this.img.rotate(byAngle(selectedRotation));
  }


  if (!isNaN(width) && !isNaN(height)) { // Resize the image
    this.img = this.img.resize(fill().width(width).height(height));
  }
}
}

Now that our backend is complete, all we need to do is create a UI for our image editor. To do this, open up the app.component.html file. Here, we will begin by linking Bootstrap for styling the layout and form elements:

<main class="main d-flex justify-content-center align-items-center flex-column">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
  <style>
      .image-form {
          margin: 10px;
      }
      fieldset {
          border: 1px solid #ccc;
          padding: 10px;
          margin-bottom: 10px;
      }
      legend {
          font-weight: bold;
      }
      .form-check {
          margin-bottom: 5px;
      }
  </style>

Next, we define an input field for the Cloudinary image ID and its corresponding load button, allowing the user to enter the public ID of their Cloudinary image. Next, we use the advanced-image custom component. This component displays the loaded image with transformations applied.

Additionally, we provide user control via two fieldsets with radio buttons. The first allows selecting an effect (sepia, cartoonify, grayscale, or none), while the second lets users choose a rotation angle (0°, 90°, or -90°). Finally, we offer two input fields for custom sizing for the desired width and height alongside a transform button that triggers the transformImage() function to apply the selections. Here’s what our complete HTML file looks like:

<main class="main d-flex justify-content-center align-items-center flex-column">
  <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css">
  <style>
      .image-form {
          margin: 10px;
      }
      fieldset {
          border: 1px solid #ccc;
          padding: 10px;
          margin-bottom: 10px;
      }
      legend {
          font-weight: bold;
      }
      .form-check {
          margin-bottom: 5px;
      }
  </style>

  <!-- Input field for Cloudinary image ID -->
  <div class="image-form">
      <input class="m-2" type="text" placeholder="Enter Cloudinary image ID" #imageIdInput>
      <button class="btn btn-outline-secondary" type="button" (click)="loadImage(imageIdInput.value)">Load Image</button>
  </div>

  <!-- Display the loaded image -->
  <advanced-image [cldImg]="img"></advanced-image>

  <!-- Effect selection -->
  <fieldset>
      <legend>Effect</legend>
      <div role="group" aria-label="Basic radio toggle button group">
        <div class="form-check">
          <input type="radio" class="form-check-input" id="sepia" name="effect" value="sepia" autocomplete="off">
          <label class="form-check-label" for="sepia">Sepia</label>
        </div>
        <div class="form-check">
          <input type="radio" class="form-check-input" id="cartoonify" name="effect" value="cartoonify" autocomplete="off">
          <label class="form-check-label" for="cartoonify">Cartoonify</label>
        </div>
        <div class="form-check">
          <input type="radio" class="form-check-input" id="grayscale" name="effect" value="grayscale" autocomplete="off">
          <label class="form-check-label" for="grayscale">Grayscale</label>
        </div>
        <div class="form-check">
          <input type="radio" class="form-check-input" id="none" name="effect" value="none" autocomplete="off">
          <label class="form-check-label" for="none">None</label>
        </div>
      </div>
  </fieldset>

  <!-- Rotation selection -->
  <fieldset>
      <legend>Rotate</legend>
      <div role="group" aria-label="Rotation radio toggle button group">
        <div class="form-check">
          <input type="radio" class="form-check-input" id="rotate0" name="rotate" value="0" autocomplete="off">
          <label class="form-check-label" for="rotate0">0°</label>
        </div>
        <div class="form-check">
          <input type="radio" class="form-check-input" id="rotate90" name="rotate" value="90" autocomplete="off">
          <label class="form-check-label" for="rotate90">90°</label>
        </div>
        <div class="form-check">
          <input type="radio" class="form-check-input" id="rotateNeg90" name="rotate" value="-90" autocomplete="off">
          <label class="form-check-label" for="rotateNeg90">-90°</label>
        </div>
      </div>
  </fieldset>

  <!-- Input fields for width and height -->
  <div class="image-form">
    <input class="m-2" type="text" placeholder="Width" id="imageWidth">
    <input class="m-2" type="text" placeholder="Height" id="imageHeight">
  </div>


  <!-- Transform button -->
  <button class="btn btn-primary mt-2" (click)="transformImage()">Transform Image</button>
</main>

Testing Our Image Editor App

Now that our app is complete, all we need to do is run our code using the following command:

ng serve

angular image editor

Here is what our app looks like:

angular image editor

We will start by loading up an image with a public id, turtles, from our Cloudinary assets. To do this, search for turtles in the search bar and click on the Load Image button:

angular image editor

Next, we can add different transformations to our image. For example, here, we have added a Cartoonify effect and rotated the image by 90 degrees:

angular image editor

Final Thoughts

Conclusively, an image editor is more than just a tool; it’s a creative companion for developers. With its rich feature set and seamless integration with Cloudinary, you can elevate your web applications by providing users with powerful image editing capabilities. Whether you’re building a photo-sharing app, an e-commerce storefront, or a portfolio website, an image editor app in a language like Angular is your go-to solution.

So, why wait? Sign up for Cloudinary and unlock new possibilities for your projects!

More from Cloudinary:

How to Upload Images in Angular

Video Manipulations and Delivery for Angular Video Apps

Last updated: Jun 23, 2024