How to Compress Image With Custom Ratio Without The Support of Third Party Library ?| Devstringx

Back to Blog
Image Compression using code only

How to Compress Image With Custom Ratio Without The Support of Third Party Library ?| Devstringx

Create New Angular Project

Let’s create a new angular project using the Angular CLI tool by executing the following CLI command

–        ng new image-compression

–        Would you like to add Angular routing? Yes

–        Which stylesheet format would you like to use? CSS

What’s Image Compression?

Image Compression is when we reduce the resolution of the actual image. Ex – suppose there is an image with resolution 1250 x 450 and for our logo we want the image to be compressed in 100 x 30 resolution then we have to reduce the height and width of the image with the required resolution (height and width) so that the UI won’t distort.

What’s Different Here?

In this blog we will not use any third-party library, this will be pure code. In third party libraries, the image compressed in their own format we cannot set the required height or width of the image also most of these libraries return base64 data and some API’s don’t accept base64 so in this blog, we will set the required resolution (height and width) of the image and after the compression of the image, the returned data will File not base64 so the API can accept it without any problem or we also can do many things with the file according to the requirement.

Create Service for Image Compression

Now we’ll create a new service for Image compression to keep the code of image compression in one place so that we won’t have to write the code again and again. To generate the image compression service in the service folder, execute the following command

–        ng generate service services/imageCompression

This will create an ImageCompressionService inside the services folder.

Update the ImageCompressionService

Now, open the image-compression-service.ts file inside the services folder and make the following changes:

Import {Observable} from ‘rxjs’

We will create a separate method in the image-compression-service.ts file called compress () that will take file, maxHeight, and maxWidth that will return an observable of File type.

The method will look like this:

compress(file: File, maxHeight: number, maxWidth: number): Observable<File> {

}

Here, if we didn’t want to pass the height or width, we only want to reduce only one of the parameters then we simply can pass null so that the height or width will remain original.

Now, inside the compress () function write this code:

const imageType = file.type || ‘image/jpeg’

const reader = new FileReader()

reader.readAsDataURL(file)

return Observable.create(observer => {

reader.onload = ev => {

const img = this.createImage(ev)

setTimeout(() => {

const canvas = document.createElement(‘canvas’)

if (img.height < img.width) {

if (maxWidth) {

canvas.width = img.width > maxWidth ? maxWidth : img.width

} else {

canvas.width = img.width

}

if (maxHeight) {

canvas.height = img.height > maxHeight ? maxHeight : img.height

} else {

canvas.height = img.height

}

} else {

if (maxHeight) {

canvas.height = img.height > maxHeight ? maxHeight : img.height

} else {

canvas.height = img.height

}

if (maxWidth) {

canvas.width = canvas.height * 50 / 100

} else {

canvas.width = canvas.width

}

}

const canvasCtx = <CanvasRenderingContext2D>canvas.getContext(‘2d’)

canvasCtx.drawImage(img, 0, 0, canvas.width, canvas.height)

canvasCtx.canvas.toBlob(

blob => {

observer.next(

new File([blob], file.name, {

type: imageType,

lastModified: Date.now(),

}),

)

},

imageType,

)

})

}

reader.onerror = error => observer.error(error)

})

Also Read:- Streaming YouTube Video in Angular Application

In this code, we are creating an instance/object of FileReader class and then reading the file as dataUrl using the reader.readAsDataUrl() method.

Now, we have to return the Observable of the file type but before this first create a method named createImage () that will create a new Image instance with the Image data.

private createImage(ev) {

const imageContent = ev.target.result

const img = new Image()

img.src = imageContent

return img

}

Your code will look like this. Now, using the createImage() function we will get an image with the actual image source, after that we will create a canvas using the document.createElement(‘canvas’) function. Now we will check if the actual image resolution (height or width) is less than the required resolution if yes then we will use the actual resolution of the image but if the actual resolution is greater than the required resolution then we will set the required resolution in the canvas.

and then we will create an instance canvasCtx using canvas.getContext(‘2d’) function and using that instance we will drawImage and then we will return it as BLOB like this –

Your Final Code Will Look Like This

image-compression.service.ts

import { Observable } from ‘rxjs’;

compress(file: File, maxHeight: number, maxWidth: number): Observable<File> {

const imageType = file.type || ‘image/jpeg’

const reader = new FileReader()

reader.readAsDataURL(file)

return Observable.create(observer => {

reader.onload = ev => {

const img = this.createImage(ev)

setTimeout(() => {

const canvas = document.createElement(‘canvas’)

if (img.height < img.width) {

if (maxWidth) {

canvas.width = img.width > maxWidth ? maxWidth : img.width

} else {

canvas.width = img.width

}

if (maxHeight) {

canvas.height = img.height > maxHeight ? maxHeight : img.height

} else {

canvas.height = img.height

}

} else {

if (maxHeight) {

canvas.height = img.height > maxHeight ? maxHeight : img.height

} else {

canvas.height = img.height

}

if (maxWidth) {

canvas.width = canvas.height * 50 / 100

} else {

canvas.width = canvas.width

}

}

const canvasCtx = <CanvasRenderingContext2D>canvas.getContext(‘2d’)

canvasCtx.drawImage(img, 0, 0, canvas.width, canvas.height)

canvasCtx.canvas.toBlob(

blob => {

observer.next(

new File([blob], file.name, {

type: imageType,

lastModified: Date.now(),

}),

)

},

imageType,

)

})

}

reader.onerror = error => observer.error(error)

})

}

private createImage(ev) {

const imageContent = ev.target.result

const img = new Image()

img.src = imageContent

return img

}

Also Read:- Generating Excel File in Angular 9 using “ExcelJs” with Custom Font Family 

app.component.ts

import { take } from ‘rxjs/operators’;

constructor(

private imageCompressor: ImageCompressionService

) {}

getFile(event): void {

const file = event.target.files[0]

this.imageCompressor.compress(file, 100, 20).pipe(take(1)).subscribe(compressedImage => {

console.log(compressedImage)

}

}

app.component.html

<input type=”file” (change)=”getFile($event)” accept=”.jpg,.jpeg,.png” />

Share this post

Back to Blog