dfa1234 / ngx-image-compress

Angular library for uploading and compressing images
https://image-library.app
MIT License
86 stars 37 forks source link
angular canvas compression image-processing upload-images

ngx-image-compress

Angular utility for compressing images to a satisfying size, that you can choose

License Latest npm release NPM downloads Contributors

Build Status

Import

npm i ngx-image-compress

Angular 13+ differ as there is no need to import the service in your module. You can inject the service in the constructor of your component directly.
For any angular version before 13, you should first import the service in your module, like this:

import {NgxImageCompressService} from 'ngx-image-compress';

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

Usage

Here how to use the service in your component.

Using upload and compress function, independently

This option is giving control over the compression process.

compressFile() signature is detailed here

import {Component} from '@angular/core';
import {NgxImageCompressService} from 'ngx-image-compress';

@Component({
    selector: 'app-root',
    template: `
        <button (click)="compressFile()">Upload and compress Image</button>
        <img [src]="imgResultBeforeCompression" *ngIf="imgResultBeforeCompression" />
        <img [src]="imgResultAfterCompression" *ngIf="imgResultAfterCompression" />
    `,
})
export class AppComponent {
    constructor(private imageCompress: NgxImageCompressService) {}

    imgResultBeforeCompression: string = '';
    imgResultAfterCompression: string = '';

    compressFile() {
        this.imageCompress.uploadFile().then(({image, orientation}) => {
            this.imgResultBeforeCompression = image;
            console.log('Size in bytes of the uploaded image was:', this.imageCompress.byteCount(image));

            this.imageCompress
                .compressFile(image, orientation, 50, 50) // 50% ratio, 50% quality
                .then(compressedImage => {
                    this.imgResultAfterCompression = compressedImage;
                    console.log('Size in bytes after compression is now:', this.imageCompress.byteCount(compressedImage));
                });
        });
    }
}

Performing a single upload, and compressing automatically to a given max size

Quicker and effortless method.

Getting directly an image at a maximum of "X" MegaBytes, using a built-in algorithm:

import {Component} from '@angular/core';
import {NgxImageCompressService} from 'ngx-image-compress';

@Component({
    selector: 'app-root',
    template: `
        <button (click)="compressFile()">Upload and compress Image</button>
        <img [src]="imgResult" *ngIf="imgResult" />
    `,
})
export class AppComponent {
    constructor(private imageCompress: NgxImageCompressService) {}

    imgResult: string = '';

    compressFile() {
        const MAX_MEGABYTE = 2;
        this.imageCompress
            .uploadAndGetImageWithMaxSize(MAX_MEGABYTE) // this function can provide debug information using (MAX_MEGABYTE,true) parameters
            .then(
                (result: string) => {
                    this.imgResult = result;
                },
                (result: string) => {
                    console.error(
                        "The compression algorithm didn't succed! The best size we can do is",
                        this.imageCompress.byteCount(result),
                        'bytes'
                    );
                    this.imgResult = result;
                }
            );
    }
}

Same method but without the upload step

this.imageCompress.getImageWithMaxSizeAndMetas({image: 'base64ValueFromYourUpload'},MAX_MEGABYTE).then

Multiple files support

For uploading multiple files, instead of using

this.imageCompress.uploadFile()
  .then((singleFile: { image: string, fileName:string, orientation: number }) => //...

You can use

this.imageCompress.uploadMultipleFiles()
  .then((arrayOfFiles: { image: string, fileName:string, orientation: number }[]) => //...

Behavior if no files have been selected

With uploadFile() and uploadMultipleFiles(), nothing will happen when the user is selecting nothing, close the file selection, and cancel the upload.

If you want the upload promise to reject in such case, please use: uploadFileOrReject() or uploadMultipleFilesOrReject() instead.

compressFile() signature

The signature of compressFile() is:

compressFile(image, orientation, ratio, quality, maxWidth, maxHeight)

Parameter Type Description
image string DataUrl (string) representing the image
orientation number EXIF Orientation value using the DOC_ORIENTATION enum value
ratio number Maximum scale factor as a percentage (optional, default: 50) 1
quality number JPEG quality factor as a percentage (optional, default: 50) 2
maxWidth number Maximum width in pixels if you need to resize (optional, default: 0 - no resize)
maxHeight number Maximum height in pixels if you need to resize (optional, default: 0 - no resize)

[1] Ratio: "50" will decrease the resolution of each dimension by 2, i.e.: image of 2000 X 1500 pixels will become 1000 X 750 pixels, while the whole resolution will be reduced by 4.

[2] Quality: For more info about this parameter, read this guide

How it works under the hood?

We will use Renderer2, and transform the image using HTML canvas encrustation. In fact you can use the static version in the library and import renderer by yourself, or replace it with another DOM abstraction, using RendererFactory2.

There are mainly two advantage for using Renderer2 abstraction over direct DOM manipulation (by using ElementRef or window.document directly).

That's being said, please note that because of some iOS limitations/bugs when using Renderer2, we still are using window.document API, for the upload part only (not the canvas itself).

Change log

2023/02/14

2022/05/24

2022/05/10

2022/02/22

2022/01/19

2022/01/04

2021/12/21

2021/11/14

2020/11/18

2019/07/01

2019/01/09

2018/10/04

2017/12/06