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

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” />

Originally published at https://www.devstringx.com on Jan 10, 2022.

--

--

--

Devstringx Technologies is highly recommended IT company for custom software development, mobile app development and automation testing services

Love podcasts or audiobooks? Learn on the go with our new app.

Recommended from Medium

Using the useCallback React hook

React Query and why you should use it!

New Props, Who Dis? Updating Local State In Your React.js Components With ComponentDidUpdate

Why You Should Use Next.js for Your Next Web Application

Node.js: Instagram feed (B2C) on website (Part Two)

Tech For Brainlets: Server Side Rendering vs Client Side Rendering

Forms and Validation in React

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Devstringx Technologies

Devstringx Technologies

Devstringx Technologies is highly recommended IT company for custom software development, mobile app development and automation testing services

More from Medium

IBM Message Gateway monitoring with Instana

Fixing AWS Upload Error

Exceptional Handling in Java

Dynamic JSON Translator

Java Project Structure.