How To Crop, Zoom, Scale, Flip, Rotate, Preview And Upload Image In Base64 With Example Using Angular

This blog will implement Image Cropping, Zooming, Scaling, Fliping, Rotate and Preview functionality while uploading. This is presented with a window for a user to crop any area on the browsed image and preview the image’s selected section.

The selected and cropped area of the image is converted into a base64 encoded string which can be easily uploaded to the server and saved as a real image into JPG or PNG formats.

Here I will explain the frontend part to implement Image selection and crop functionality from scratch.

Output:

image-cropper

Let’s Do This

Create an Angular Project

Firstly, We will create a new Angular 11 project using the Ng CLI tool. Here we will use the current version on Ng CLI which is v11.2.9.

$ ng new my-image-cropper

After successfully creating an Angular project,

$ cd my-image-cropper

Install and Configure Angular Image Cropper

Secondly, we will install the Angular Image Cropper package which is very easy to install and use in the project.

Here we will use ngx-image-cropper the package which very popular and loads of configurations which we will discuss with examples.

Installation:

Run following NPM command in terminal to install Image Cropper and Bootstrap 4 package:

     1. Image Cropper:

$ npm install ngx-image-cropper --save

     2. Bootstrap:

You need to just install bootstrap on your angular 11 and import the CSS file to the style.css file. this is only for CSS importing. so you can run the command below:

$ npm install bootstrap --save

Ok, now you need to import your bootstrap CSS on style.css file as like bellow:

@import "~bootstrap/dist/css/bootstrap.css";

Configure App Module:

To use Image Cropper anywhere in the Angular project, we will carry it in our App’s main module in app.module.ts then add in the imports array as shown below:

import { NgModule } from '@angular/core';
import { BrowserModule } from '@angular/platform-browser';
import { AppRoutingModule } from './app-routing.module';
import { AppComponent } from './app.component';
import { ImageCropperModule } from 'ngx-image-cropper';
import { FormsModule } from '@angular/forms';

@NgModule({
  declarations: [
    AppComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    ImageCropperModule,
    FormsModule
  ],
  providers: [],
  bootstrap: [AppComponent]
})
export class AppModule { }

Using Image Cropper:

To use image cropper in a component, simply add the following three elements in the template.

  1.  Input control of type file is required to select an image.
  2. The image-cropper component directive will display the selected image with a cropper area to select the portion of the actual image.
  3. The preview of the selected cropped image will be shown in the img element.

Update HTML Template:

<div class="container">
  <div class="row" style="margin-top: 5%;">
    <div class="row">
      <div class="text-center col-md-12">
        <input type="file" #myInput class="text-primary" (change)="fileChangeEvent($event)" />
        <button class="btn btn-info" (click)="clear()">Clear</button>
    </div>
    </div>
    <div class="row text-center p-2 m-2">
      <div class="col-md-3">
        <button (click)="rotateLeft()" class="mr-2 btn btn-dark">Rotate left</button>
      </div>
      <div class="col-md-3">
        <button (click)="rotateRight()" class="mr-2 btn btn-dark">Rotate right</button>
      </div>
      <div class="col-md-3">
        <button (click)="flipHorizontal()" class="mr-2 btn btn-dark" >Flip horizontal</button>
      </div>
      <div class="col-md-3">
        <button (click)="flipVertical()" class="mr-2 btn btn-dark">Flip vertical</button>
      </div>
    </div>
    <div class="row justify-content-center p-2 m-2">
      <div class="col-md-3">
        <button (click)="toggleContainWithinAspectRatio()" class="mr-2 btn btn-warning">{{containWithinAspectRatio?'Fill Aspect Ratio':'Contain Within Aspect Ratio'}}</button>
      </div>
      <div class="col-md-3">
        <button (click)="resetImage()" class="mr-2 btn btn-warning">Reset Image</button>
      </div>
    </div>
    <div class="row justify-content-center p-2 m-2">
          <div class="col-md-4">
            <input [(ngModel)]="rotation" placeholder="Rotation" class="form-control mr-2" type="number" (keyup)="updateRotation()" /> 
          </div>
          <div class="col-md-8">
            <button (click)="zoomOut()" class="mr-4 btn btn-success zoom-btn">Zoom -</button>
            <button (click)="zoomIn()"class="mr-2 btn btn-success">Zoom +</button>
          </div>
    </div>
  </div>
  <div class="row" style="margin-top: 5%;">
      <div class="text-center col-md-8">
          <h5>Crop Image</h5>
          <image-cropper 
          [imageChangedEvent]="imageChangedEvent"
          [maintainAspectRatio]="true"
          [containWithinAspectRatio]="containWithinAspectRatio"
          [aspectRatio]="4 / 3"
          [resizeToWidth]="256"
          [cropperMinWidth]="128"
          [onlyScaleDown]="true"
          [roundCropper]="false"
          [canvasRotation]="canvasRotation"
          [transform]="transform"
          [alignImage]="'left'"
          [style.display]="showCropper ? null : 'none'"
          format="png"
          (imageCropped)="imageCropped($event)"
          (imageLoaded)="imageLoaded()"
          (cropperReady)="cropperReady($event)"
          (loadImageFailed)="loadImageFailed()">
        </image-cropper>
      </div>
      <div class="text-center col-md-4">
          <h5>Preview</h5>
          <img [src]="croppedImage" />
      </div>
  </div>
</div>

Update Class Component:

In component class, import ImageCroppedEvent then defines a few variables and methods as shown below:

import { Component, ElementRef, ViewChild } from '@angular/core';
import { Dimensions, ImageCroppedEvent, ImageTransform } from 'ngx-image-cropper';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css'],
})
export class AppComponent {
  title = 'my-image-cropper';
  @ViewChild('myInput') myInputVariable!: ElementRef;

  imageChangedEvent: any = '';
  croppedImage: any = '';
  canvasRotation = 0;
  rotation = 0;
  scale = 1;
  showCropper = false;
  containWithinAspectRatio = false;
  transform: ImageTransform = {};

  fileChangeEvent(event: any): void {
    this.imageChangedEvent = event;
  }
  imageCropped(event: ImageCroppedEvent) {
    this.croppedImage = event.base64;
  }
  imageLoaded() {
    this.showCropper = true;
  }
  cropperReady(sourceImageDimensions: Dimensions) {
    // cropper ready
    console.log('Cropper ready', sourceImageDimensions);
  }
  loadImageFailed() {
    // show message
    console.log('Load failed');
  }

  clear() {
    this.croppedImage = '';
    this.imageChangedEvent = '';
    this.myInputVariable.nativeElement.value = '';
  }

  rotateLeft() {
    this.canvasRotation--;
    this.flipAfterRotate();
  }

  rotateRight() {
    this.canvasRotation++;
    this.flipAfterRotate();
  }

  private flipAfterRotate() {
    const flippedH = this.transform.flipH;
    const flippedV = this.transform.flipV;
    this.transform = {
      ...this.transform,
      flipH: flippedV,
      flipV: flippedH,
    };
  }

  flipHorizontal() {
    this.transform = {
      ...this.transform,
      flipH: !this.transform.flipH,
    };
  }

  flipVertical() {
    this.transform = {
      ...this.transform,
      flipV: !this.transform.flipV,
    };
  }

  resetImage() {
    this.scale = 1;
    this.rotation = 0;
    this.canvasRotation = 0;
    this.transform = {};
  }

  zoomOut() {
    this.scale -= 0.1;
    this.transform = {
      ...this.transform,
      scale: this.scale,
    };
  }

  zoomIn() {
    this.scale += 0.1;
    this.transform = {
      ...this.transform,
      scale: this.scale,
    };
  }

  toggleContainWithinAspectRatio() {
    this.containWithinAspectRatio = !this.containWithinAspectRatio;
  }

  updateRotation() {
    this.transform = {
      ...this.transform,
      rotate: this.rotation,
    };
  }
}

Update CSS Component:

input[type="file" i] {
  color: beige;
  border: 4px dashed;
  padding: 50px;
  margin: 0px 20px;
}

.zoom-btn {
  margin-right: 20px;
}

Now run the Angular application by hitting the following command:

$ ng -o serve

That’s it. Now you can see a screen like mine. You can download the source code from here.

I hope you guys understand how I can do this.  Let me know if you face any difficulties.

You can watch my previous blog here.

Happy Coding {;} ????

Submit a Comment

Your email address will not be published. Required fields are marked *

Subscribe

Select Categories