skip to Main Content

Is there a way to adjust the brightness and contrast of the cropper image before I crop it with ngx-image-cropper and have those filters be applied when the image gets cropped?

EDIT 5/1/2024 – I know I can get the base64 image after I crop(), create a canvas and apply CSS filters (it’s what I’m currently doing). But I would like to see if there is a way to do it before I crop() or to the image that is being cropped, so as to avoid the labor of creating a new canvas with image after I crop just to alter CSS filter values, which were already done with the "imageCropper.sourceImage" on screen by the user. Here is an example of what I’m doing in the app.

This is for reference
enter image description here

// Called after the user changes a slider on screen to adjust the brightness
changeBrightness(event: any) {
    this.filterApplied = true;
    this.imageCropper.sourceImage.nativeElement.style.filter = 'brightness(' + event.target.value + '%) contrast(' + this.contrast + '%) saturate(' + this.saturate + '%)';
}
// Gets called when the user has visually inspected 
// his image on screen and is ok with it and is 
// ready to save it to the DB.
saveImage() {
    if (this.filterApplied) {
      const filteredImage = this.applyFilter(this.imageCropper.crop('base64').base64);
      this.saveToDb(filteredImage);
    } else {
      this.saveToDb(this.imageCropper.crop('base64').base64);
    }

applyFilter(base64) {
  // code left out for brevity
  // 1. create canvas and modify CSS filters
  // 2. return base64 image
}

I can adjust the source image (image on screen) brightness, contrast and saturation (see above), but when I crop() and then display the cropped image, the CSS that has been altered in the

immageCropper.sourceImage

doesn’t get used in the cropped image.

What I tried (see my snippet below) with no luck.

  1. Altered the imageCropper.sourceImage.nativeElement.style.filter
  2. Modified the loadedImage property from private to public and
    a.) Altered the imageCropper.loadedImage.original.image.style.filter
    b.) Altered the imageCropper.loadedImage.transformed.image.style.filter

I tried stepping through the libraries code to see what image was being used but got a little lost.

Here is a sample below of how I modify the CSS for the source image and my example on stackblitz code that shows what I’m doing.

@ViewChild("imageCropper") imageCropper: ImageCropperComponent;

crop() {
  this.imageCropper.sourceImage.nativeElement.style.filter = 'brightness(150%) contrast(150%) saturate(150%)';
  // I also tried loadedImage, both original and transformed with no luck
  // this.imageCropper.loadedImage.original.image.style.filter = 'brightness(' + event.target.value + '%) contrast(' + this.contrast + '%) saturate(' + this.saturate + '%)';
  // this.imageCropper.loadedImage.transformed.image.style.filter = 'brightness(' + event.target.value + '%) contrast(' + this.contrast + '%) saturate(' + this.saturate + '%)';
  this.imageCropper.crop();
}

2

Answers


  1. If you want to add the same filter to the cropped image after crop you can do the following :

    1- declare the filter option you want like that:

      filterImageOptions = 'brightness(150%) contrast(150%) saturate(150%)'
    

    2- Add a template reference to croppedImage :

        <img #corpImage class="logo-image-edit" [src]="croppedImage" />
    
    

    3- Read this reference using @ViewChild('corpImage'):

      @ViewChild("corpImage") public corpImage: ElementRef<HTMLImageElement>;
    
    

    4- Inside the function imageCropped add a setTimeout and then add the filterOptions to the croppedImage:

     imageCropped(event: ImageCroppedEvent) {
        this.croppedImage = event.base64;
        setTimeout(() =>{
          this.corpImage.nativeElement.style.filter = this.filterImageOptions;
    
        },0)
      }
    
    Login or Signup to reply.
  2. I don’t think adding CSS filter can change the filter inside of the image file itself, CSS will only add a "visual filter" on top of your image. I believe what you wanna do is to add filter to the "file" of the image right? If so, we can still use the same CSS rules that you have, but instead of applying it as a CSS filter, we can add it as a canvas filter.

    The first thing you wanna do is to create this function:

      private applyFilter(imageBase64): Promise<string> {
        return new Promise((resolve) => {
          const canvas = document.createElement('canvas');
          const image = new Image();
          const ctx = canvas.getContext('2d');
    
          image.onload = function () {
            canvas.width = image.width;
            canvas.height = image.height;
    
            ctx.filter = 'brightness(150%) contrast(150%) saturate(150%)'; // add your CSS filter here
    
            ctx.drawImage(image, 0, 0, image.width, image.height);
            resolve(canvas.toDataURL('image/png'));
          };
    
          image.src = imageBase64;
        });
      }
    

    The above function will do a similar thing as the cropping part, but this one is processing the image even before showing it. Basically when we get the imageBase64, we try to load it as an Image() then when it’s loaded we draw it to the canvas in which we apply the CSS filter to.

    Once the image is drawn to the canvas, we then return it as parameter to loadBase64Image() function which will finally show the image, by adding this line after this line .then((resultBase64: string) => this.fitImageToAspectRatio(resultBase64)):

    .then((resultBase64: string) => this.applyFilter(resultBase64))
    

    Technically it’s not CSS filter, it’s a property of canvas, but it accepts the same value as CSS filter.

    Here is the forked stackblitz.

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search