Editing photos in Ionic

August 31, 2017, 5:00 pm Categories:

Categories

Thanks to the underlying technologies that Ionic makes use of - namely Angular and Apache Cordova - developers can push the limits of what functionality their applications offer.

Over the course of this tutorial I'm going to take you through developing a very simple photo editing application that makes use of the Apache Cordova Camera plugin and the ng2-img-cropper node package.

This application will allow us to load an image from the device photolibrary, crop a selected area of the picture courtesy of a user friendly cropping tool and then retrieve the output for subsequent usage.

Nothing terribly complicated or fancy but useful and, I think, fun nonetheless.

Here's what we'll be building:

Ionic image editor in action

Getting started

In a suitable location on your computer create the following ionic project (assumes you are running the latest version of Ionic along with the necessary software for application development I.e. Node, Android Studio, Xcode etc):

ionic start ionic-artist blank

Once successfully generated change into the root directory of this new project:

cd ./ionic-artist

Then install the following platforms, plugins and node packages:

// Start with adding the necessary platforms
ionic cordova platform add ios
ionic cordova platform add android

// Proceed onto installing the necessary plugins/packages
ionic cordova plugin add cordova-plugin-camera
npm install --save @ionic-native/camera
npm install --save ng2-img-cropper

This is finally followed by generating a service which we'll use later on to handle interacting with the Camera plugin:

ionic g provider photo

Now let's move onto configuring the application's root module.

Rooting the application

As always importing and declaring, within the application's root module, the necessary modules that the application requires is a vital step before we can begin development.

Ensure that your ionic-artist/src/app/app.module.ts file resembles the following configuration:

import { BrowserModule } from '@angular/platform-browser';
import { HttpModule } from '@angular/http';
import { ErrorHandler, NgModule } from '@angular/core';
import { IonicApp, IonicErrorHandler, IonicModule } from 'ionic-angular';
import { SplashScreen } from '@ionic-native/splash-screen';
import { StatusBar } from '@ionic-native/status-bar';
import { Camera } from '@ionic-native/camera';
import { ImageCropperModule } from "ng2-img-cropper/index";

import { MyApp } from './app.component';
import { HomePage } from '../pages/home/home';
import { PhotoProvider } from '../providers/photo/photo';

@NgModule({
  declarations: [
    MyApp,
    HomePage
  ],
  imports: [
    BrowserModule,
    HttpModule,
    ImageCropperModule,
    IonicModule.forRoot(MyApp)
  ],
  bootstrap: [IonicApp],
  entryComponents: [
    MyApp,
    HomePage
  ],
  providers: [
    StatusBar,
    SplashScreen,
    Camera,
    {provide: ErrorHandler, useClass: IonicErrorHandler},
    PhotoProvider
  ]
})
export class AppModule {}

With these in place let's start getting stuck into some coding - beginning with our recently generated PhotoProvider service.

Camera

The ionic-artist/src/providers/photo/photo.ts service implements a single method - selectImage - for handling the opening of the device photolibrary, selection of the desired image and returning that as a base64 encoded string.

This is all made possible thanks to the incredibly helpful Apache Cordova Camera plugin which performs all the necessary background 'heavy lifting' for the selectImage method.

Our PhotoProvider service is structured as follows:

import { Injectable } from '@angular/core';
import { Http } from '@angular/http';
import 'rxjs/add/operator/map';


import { Camera, CameraOptions } from '@ionic-native/camera';

/*
  Generated class for the PhotoProvider provider.

  See https://angular.io/docs/ts/latest/guide/dependency-injection.html
  for more info on providers and Angular DI.
*/
@Injectable()
export class PhotoProvider {


   /**
    * Stores retrieved camera image from device photo library as a base64 string
    */
   public cameraImage : String;




   constructor(public http      : Http,
               private _CAMERA  : Camera) 
   {  }




   /**
     *
     * Select an image from the device photo library
     *
     * @public
     * @method selectImage
     * @return {Promise}
     */
   selectImage() : Promise<any>
   {
      return new Promise(resolve =>
      {
         let cameraOptions : CameraOptions = {
             sourceType         : this._CAMERA.PictureSourceType.PHOTOLIBRARY,
             destinationType    : this._CAMERA.DestinationType.DATA_URL,
             quality            : 100,
             targetWidth        : 320,
             targetHeight       : 240,
             encodingType       : this._CAMERA.EncodingType.JPEG,
             correctOrientation : true
         };

         this._CAMERA.getPicture(cameraOptions)
         .then((data) =>
         {
            this.cameraImage 	= "data:image/jpeg;base64," + data;
            resolve(this.cameraImage);
         });


      });
   }

}

With this in place we can now move onto coding the logic for the HomePage component which will allow us to select and edit an image of our choosing.

Home

Within the ionic-artist/src/pages/home/home.ts file we'll be accomplishing the following tasks:

  • Opening the device photolibrary
  • Selecting the desired image
  • Initialising the image cropping tool
  • Handling the cropping of the image
  • Retrieving the source data of the cropped image

We WON'T be doing anything fancy with the cropped image (such as saving that locally, converting to a Blob file or pushing to a remote storage solution such as Firebase Storage - those I'll leave to you to figure out....if you go through previous tutorials on this website you'll find resources to help you achieve these anyway ;) ).

I will show you how to access and retrieve the source data of the cropped image though so you can make decisions about how to subsequently use that.

The code for the ionic-artist/src/pages/home/home.ts file is displayed below and shouldn't require any further elaboration on my part as this is commented in full at each key stage of the class:

import { Component, ViewChild } from '@angular/core';
import { NavController } from 'ionic-angular';
import {ImageCropperComponent, CropperSettings, Bounds} from 'ng2-img-cropper';
import { PhotoProvider } from '../../providers/photo/photo';

@Component({
  selector: 'page-home',
  templateUrl: 'home.html'
})
export class HomePage {
   

   /**
    * Access the image cropper DOM element
    */
   @ViewChild('cropper') ImageCropper : ImageCropperComponent;




   /**
    * Object for storing - and eventually initialising - image cropper settings
    */
   public cropperSettings;




   /**
    * Will set the cropped width for the image
    */   
   public croppedWidth       : Number;
   



   /**
    * Will set the cropped height for the image
    */   
   public croppedHeight      : Number;




   /**
    * Object for storing image data
    */   
   public data               : any;




   /**
    * Determines whether the Save Image button is to be displayed or not
    */   
   public canSave            : boolean 				 = false;




   constructor(public navCtrl   : NavController,
               private _PHOTO   : PhotoProvider) 
   {
      // Here we set up the Image Cropper component settings
      this.cropperSettings                           = new CropperSettings();

      // Hide the default file input for image selection (we'll be
      // using the Camera plugin instead)
      this.cropperSettings.noFileInput               = true;

      // Create a new cropped image object when the cropping tool
      // is resized
      this.cropperSettings.cropOnResize              = true;

      // We want to convert the file type for a cropped image to a 
      // JPEG format
      this.cropperSettings.fileType                  = 'image/jpeg';

      // We want to be able to adjust the size of the cropping tool
      // by dragging from any corner in any direction
      this.cropperSettings.keepAspect 				 = false;

      // Create an object to store image related cropping data
      this.data                                      = {};
   }




   /**
     *
     * Determine the width & height for the cropped image (and enable the 
     * Save Image button)
     *
     * @public
     * @method handleCropping
     * @param bounds              {Bounds}      Capture the component's crop event 
                                                (and subsequent properties)
     * @return none
     */
   handleCropping(bounds : Bounds)
   {
      this.croppedHeight 		= bounds.bottom  -  bounds.top;
      this.croppedWidth 		= bounds.right   -  bounds.left;
      this.canSave              = true;
   }




   /**
     *
     * Select an image from the device Photo Library
     *
     * @public
     * @method selectImage
     * @return none
     */
   selectImage()
   {
      this.canSave              = false;
      this._PHOTO.selectImage()
      .then((data : any) =>
      {
         // Create an Image object, assign retrieved base64 image from 
         // the device photo library
         let image : any        = new Image();
         image.src 				= data;


         // Assign the Image object to the ImageCropper component 
         this.ImageCropper.setImage(image);
      })
      .catch((error : any) =>
      {
         console.dir(error);
      });
   }




   /**
     *
     * Retrieve the cropped image value (base64 image data)
     *
     * @public
     * @method saveImage
     * @return none
     */
   saveImage()
   {
      console.dir(this.data.image);
   }




}

There are more options available for configuring the image cropping tool but, for the purposes of this tutorial, we'll settle for what has been declared/implemented in our HomePage component.

Our final step involves setting up the necessary HTML in our component template.

Templating the application

The ionic-artist/src/pages/home/home.html file is fairly simple and consists of 4 sections:

  • A select image button
  • The cropping tool (which our selected image will be loaded into)
  • The cropped image
  • A save image button

These are structured as follows:

<ion-header>
   <ion-navbar>
      <ion-title>
         Ionic Artist
      </ion-title>
   </ion-navbar>
</ion-header>

<ion-content padding>
  
   
   <!-- Select image from device photolibrary -->
   <button 
      ion-button
      block 
      color="primary" 
      (click)="selectImage()">Select an Image</button>
  


   <!-- Declare image cropper with following aspects:
        
        1. Template reference variable to allow component 
           class to 'hook' into the cropper tool in DOM
        2. Set image from the component class's data object
        3. Apply settings from the component class's
           cropperSettings object
        4. Call the handleCropping method in the image
           cropper's onCrop event
    -->
   <img-cropper 
      #cropper 
      [image]="data" 
      [settings]="cropperSettings" 
      (onCrop)="handleCropping($event)"></img-cropper>
  

   <!-- Display the cropped image -->
   <div 
      *ngIf="data.image">

       <img 
          [src]="data.image" 
          [width]="croppedWidth" 
          [height]="croppedHeight">
   </div>


   <!-- Display the save image button IF canSave
        property value is true
   -->
   <button 
      *ngIf="canSave"
      ion-button
      block 
      color="secondary" 
      (click)="saveImage()">Save Image</button>


</ion-content>

With the application codebase in place we can now attach a mobile/tablet device to our computer then build and run the application with the following commands (substitute android for ios if you are using that platform):

ionic cordova build ios --prod
ionic cordova run ios

All of which, if the build/run processes have been successfully executed, should launch the application on our device and allows us to start selecting and editing images like so:

Ionic image editor in action

If you're seeing the above (your device photolibrary images SHOULD be different from mine!) then congratulations you can successfully crop and save your selected images.

In summary

Thanks to the incredibly simple (yet powerful) Angular 2 image cropper tool we can quickly and easily implement functionality to trim images (if we need to) within our Ionic applications.

This is, of course, a very basic demonstration of how the tool could be used and there's a lot of areas into which we could extend this functionality such as saving the cropped image to a remote service (I.e. Firebase Storage) or subsequently adding post-editing features such as the ability to rotate/scale or manipulate pixel data within the cropped image.

These I will leave to you, should you wish to experiment further with the above possibilities.

Hopefully you've found the above tutorial useful and, if so, please feel free to share your comments, thoughts and suggestions in the comments area below.

I explore other areas of using the Ionic framework within my e-book featured below and if you're interested in learning more about my e-books please sign up to my FREE mailing list where you can receive updates on current/forthcoming e-books and blog articles.

Tags

Categories

Post a comment

All comments are welcome and the rules are simple - be nice and do NOT engage in trolling, spamming, abusiveness or illegal behaviour. If you fail to observe these rules you will be permanently banned from being able to comment.

Top