This tutorial is out of date and no longer maintained.
So you want to allow for image uploads in your Angular 2+ apps, but would like to limit the dimension of uploaded images directly on the frontend before even uploading anything? The ng2-img-max
module is just what you need! ng2-img-max
will use web workers when available to perform the resizing computations, leaving the main thread alone.
First, install the module using npm:
- npm install ng2-img-max blueimp-canvas-to-blob --save
Or Yarn:
- yarn add ng2-img-max blueimp-canvas-to-blob
blueimp-canvas-to-blob
is a polyfill needed in order for canvas.toBlob() to be available on browsers like Safari and older versions of Internet Explorer.
Include the polyfill script in your project. If you’re using the Angular CLI, you can just add the script in your .angular-cli.json
file:
...
"scripts": [
"../node_modules/blueimp-canvas-to-blob/js/canvas-to-blob.min.js"
],
Note: You will want to restart your local server after adding a script to the Angular CLI configuration.
Now let’s import the module in your app module or into a feature module:
// ...
import { Ng2ImgMaxModule } from 'ng2-img-max';
@NgModule({
declarations: [AppComponent],
imports: [
// ...
Ng2ImgMaxModule
],
providers: [],
bootstrap: [AppComponent]
})
export class AppModule {}
And finally, the ng2-img-max
service can be imported and injected in a component like this:
import { Component } from '@angular/core';
import { Ng2ImgMaxService } from 'ng2-img-max';
@Component({ ... })
export class AppComponent {
constructor(private ng2ImgMax: Ng2ImgMaxService) {}
}
n2ImgMax
Let’s add a file input to our component’s template like this:
<input type="file" (change)="onImageChange($event)" accept="image/*">
And define the onImageChange
method in the component class. This will limit the image to a width of 400px
and a height of 300px
:
uploadedImage: Blob;
constructor(private ng2ImgMax: Ng2ImgMaxService) {}
onImageChange(event) {
let image = event.target.files[0];
this.ng2ImgMax.resizeImage(image, 400, 300).subscribe(
result => {
this.uploadedImage = result;
},
error => {
console.log('Oh no!', error);
}
);
}
Note: If you have multiple images to resize at once, use the resize
method instead and pass-in an array of image files as the first argument.
The result is of type Blob
, but you can convert that to a proper file using the File
constructor like this if you want:
uploadedImage: File;
constructor(private ng2ImgMax: Ng2ImgMaxService) {}
onImageChange(event) {
let image = event.target.files[0];
this.ng2ImgMax.resizeImage(image, 400, 300).subscribe(
result => {
this.uploadedImage = new File([result], result.name);
},
error => {
console.log('Oh no!', error);
}
);
}
Note: You can now upload the file to your backend. Don’t forget to validate things on the backend side, because nothing here prevents some conniving user from uploading oversized or non-image files directly to your backend.
Say you want to only limit the height to 300px, and have the width resized accordingly to keep the aspect ratio the same. Just set whichever side should just fallow to a value of 10000
:
// ...
onImageChange(event) {
let image = event.target.files[0];
this.ng2ImgMax.resizeImage(image, 10000, 300).subscribe(
result => {
this.uploadedImage = new File([result], result.name);
},
error => {
console.log('Oh no!', error);
}
);
}
You can also use the compress
or compressImage
methods to perform lossy compression instead of resizing the image. Pass-in a maximum value in megabytes. You’ll obviously want to run some tests to see how small you’ll want to go here while still keeping the images looking good to the eye.
In the following example, we’re limiting the resulting image to about 75Kb:
onImageChange(event) {
let image = event.target.files[0];
this.ng2ImgMax.compressImage(image, 0.075).subscribe(
result => {
this.uploadedImage = new File([result], result.name);
this.getImagePreview(this.uploadedImage);
},
error => {
console.log('Oh no!', error);
}
);
}
You’ll probably want to give a preview of the image to be uploaded to your users. You can do this using the FileReader object. You’ll also need to use Angular’s DomSanitizer to tell it to trust the base64-encoded data URI created using the FileReader
object:
Here’s what our component now looks like. The interesting new method here is getImagePreview
:
import { Component } from '@angular/core';
import { Ng2ImgMaxService } from 'ng2-img-max';
import { DomSanitizer } from '@angular/platform-browser';
@Component({ ... })
export class AppComponent {
uploadedImage: File;
imagePreview: string;
constructor(
private ng2ImgMax: Ng2ImgMaxService,
public sanitizer: DomSanitizer
) {}
onImageChange(event) {
let image = event.target.files[0];
this.ng2ImgMax.resizeImage(image, 10000, 375).subscribe(
result => {
this.uploadedImage = new File([result], result.name);
this.getImagePreview(this.uploadedImage);
},
error => {
console.log('Oh no!', error);
}
);
}
getImagePreview(file: File) {
const reader: FileReader = new FileReader();
reader.readAsDataURL(file);
reader.onload = () => {
this.imagePreview = reader.result;
};
}
}
And in our template we can use the sanitizer to display the image like this:
<img
*ngIf="imagePreview"
[src]="sanitizer.bypassSecurityTrustUrl(imagePreview)">
And that’s all there is to it!
You can also check out the ng2-img-tools
package by the same author for more browser-side image manipulation like cropping.
Thanks for learning with the DigitalOcean Community. Check out our offerings for compute, storage, networking, and managed databases.
This textbox defaults to using Markdown to format your answer.
You can type !ref in this text area to quickly search our full set of tutorials, documentation & marketplace offerings and insert the link!
Sign up for Infrastructure as a Newsletter.
Working on improving health and education, reducing inequality, and spurring economic growth? We'd like to help.
Get paid to write technical tutorials and select a tech-focused charity to receive a matching donation.