Optimizing for Speed: Leveraging Client-Side Image Compression with HTML Canvas

Image Compression May 17, 2024

At Halodoc we believe that reducing API latency directly improves user experience by making the application more responsive and faster to use. This can lead to increased user satisfaction and engagement.

Halodoc successfully tackled the challenge of slow upload API response times by implementing image compression. This strategic move has led to a remarkable improvement in our API's performance, significantly reducing response times and enhancing the overall user experience. By compressing images on the client side before transmission, we've not only optimized data transfer but also minimized latency, ensuring that our users can upload images swiftly and efficiently. This improvement reflects our commitment to innovation and customer satisfaction, showcasing our ability to proactively address performance bottlenecks and deliver a more responsive and seamless service.

In this blog we will take a look at  how we implemented image compression on client side without any external package.

Why Compress Images on the Client Side?

  1. Faster Load Times: One of the primary reasons to compress images on the client side is to reduce their file size. Smaller images load faster, which can significantly improve the overall loading speed of your website. This is particularly important for mobile users and those with slower internet connections.
  2. Bandwidth Optimization: Compressed images consume less bandwidth when they are uploaded to a server. This can lead to cost savings, especially for websites or applications that handle a large volume of image uploads.
  3. Improved User Experience: Faster load times result in a better user experience. Visitors to your website are more likely to stay and engage with your content if they don't have to wait for large images to load.
  4. Reduced Server Load: By compressing images on the client side, you can reduce the load on your server. This can improve server performance and response times, especially during peak traffic periods.
  5. Storage Space Conservation: Compressed images take up less storage space on the server, which can be important for websites that store a large number of images.

Before compressing images on the client side, several factors should be considered to ensure the best balance between image quality and performance. Here are some key points to consider:

  1. Image Quality: Determine the acceptable level of image quality for our application. Higher compression ratios can lead to lower quality images, which may be acceptable for some use cases but not for others.
  2. File Size: Consider the target file size for your images. Compressing images too much can result in a loss of detail and visual artifacts, while insufficient compression can lead to larger file sizes and slower loading times.
  3. Performance Impact: Consider the performance impact of image compression on the client side. Compressing images can consume CPU resources, especially for large images or devices with limited processing power.
  4. Browser Compatibility: Ensure that the compression algorithm we choose is supported by the browsers used by your target audience. Consider using fallbacks or polyfills for older browsers that do not support modern image formats like WebP.
  5. User Experience: Balance image quality and file size to provide a good user experience. Images should load quickly without sacrificing too much quality, especially on slower network connections.

How to Compress Images on the Client Side

There are couple of libraries available like compressorjs but in this blog we will talk about HTML canvas which provides APIs for dynamically rendering and manipulating images within web pages. By leveraging these capabilities, developers can create interactive image compression tools that allow users to adjust compression settings and preview the results in real-time.

1) Setup component to view uploaded image and compressed image

Lets create the component image-uploader to view the uploaded and compressed image with the size.

Image Preview Code

The UI for the above code snippet looks like below.

2) Adding Listener to handle input change

Now lets add the function which listens to the input change whenever user wants to upload an image.

Above code snippet shows whenever there is change in the selected file we calculating the size of the file and setSelectedFileSrc function converting type File to dataURL .The FileReader object lets web applications asynchronously read the contents of files (or raw data buffers) stored on the user's computer, using File or Blob objects to specify the file or data to read.

3) Setup Image Compression Service

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.

In this service we instantiating renderer2 as we need it to host DOM element which we are seeing in the upcoming section.And we have compressFile function which takes imageDataUrlSource , ratio , quality , maxWidth , maxHeight as an parameters and return result of compress that is an Observable of compressed imageDataUrl.

4) Resize and compress image with HTML canvas

Let’s get to the fun part and make the compress function in ImageCompressService

As shown in the above code snippet  compress function takes imageDataUrl, ratio (scaling factor), quality,  maxWidth and maxHeight of the image after compression.

Lets understand the compress logic stepwise:

Step 1:  We convert quality and ratio factor to 0 to 1 range

Step 2: Creating canvas and getting context to draw the content.

Step 3: Getting actual width of the image

Step 4: In this step we calculate ratio (scaling factor) based on the aspect ratio. An image’s aspect ratio (xratio : yratio) is the proportional relationship of the width to the height.

we are calculating the xratio and yratio based on the maxWidth and maxheight respectively. By comparing the aspects ratio and the ratio which is taken as parmeter we are taking the one which is minimum as ratio (scaling factor).

Step 5:  We are setting canvas width and height with the scaled down width and height

Step 6:  Now we are drawing downscaled image on the canvas. After that we are taking mime type of image like image/png or image/jpg etc.

Step 7: In this we are using toDataURL method provided by canvasElement which takes type (mime in this example) and a number between 0 and 1 indicating the image quality to be used when creating images using file formats that support lossy compression. Both of these parameters are optional.

So this function returns compressed imageDataUrl.

So after compressing the image the data return from compress function is string that is imageDataUrl but if we want to send the compressed image to server it needs to send as File so we need to create function to convert this imageDataSrcUrl to File.

ImageCompressService in Action

Now lets make use of ImageCompressService in our ImageUploader component

Injecting the service in our component

On compress button click we are calling onCompressImageClick inside which we are making use of  compressFile function from ImageCompressService with imageDataUrl , ratio (scaling factor) and quality .

Now lets see how all these work together to compress the image

As per the above screenshot we can see the size of uploaded image is around 6.5MB and after compressing the image the size of the image came down to ~1MB.


When compressing images using the HTML canvas, the quality, maxWidth, and maxHeight parameters can all impact the size of the compressed image:

  1. Quality: The quality parameter controls the level of compression applied to the image. It is a number between 0 and 1, where 0 is the lowest quality (highest compression) and 1 is the highest quality (lowest compression). Lower quality settings result in smaller file sizes but poorer image quality, while higher quality settings result in larger file sizes but better image quality.
  2. Max Width and Max Height: The maxWidth and maxHeight parameters specify the maximum dimensions (in pixels) that the compressed image should have. If the original image is larger than these dimensions, the canvas will resize the image to fit within the specified dimensions before applying compression. This can help reduce the file size of the compressed image, especially if the original image is very large.

By adjusting these parameters, we can control the trade-off between image quality and file size when compressing images using the HTML canvas.

At halodoc we have implemented this compression technique and achieved remarkable results for improving response time:

Before Implementing Image Compression

After Implementing Image Compression

Conclusion

Compressing images on the client side can be a useful technique for optimizing web performance and improving user experience. It allows us to reduce image file sizes without compromising too much on quality, thereby speeding up page load times and reducing bandwidth usage.

However, it's important to consider the trade-offs involved. Aggressive compression can lead to noticeable loss of image quality, which may not be acceptable for all use cases. It's also important to ensure compatibility with a wide range of browsers and devices, as not all compression techniques are supported universally.

In conclusion, client-side image compression can be a powerful tool for improving web performance, but it should be used judiciously, taking into account factors like image quality, browser compatibility, and performance impact.

Join us

Scalability, reliability, and maintainability are the three pillars that govern what we build at Halodoc Tech. We are actively looking for engineers at all levels, and if solving hard problems with challenging requirements is your forte, please reach out to us with your resume at careers.india@halodoc.com.

About Halodoc

Halodoc is the number 1 Healthcare application in Indonesia. Our mission is to simplify and bring quality healthcare across Indonesia, from Sabang to Merauke. We connect 20,000+ doctors with patients in need through our Tele-consultation service. We partner with 3500+ pharmacies in 100+ cities to bring medicine to your doorstep. We've also partnered with Indonesia's largest lab provider to provide lab home services, and to top it off we have recently launched a premium appointment service that partners with 500+ hospitals that allow patients to book a doctor appointment inside our application. We are extremely fortunate to be trusted by our investors, such as the Bill & Melinda Gates Foundation, Singtel, UOB Ventures, Allianz, GoJek, Astra, Temasek, and many more. We recently closed our Series D round and in total have raised around USD$100+ million for our mission. Our team works tirelessly to make sure that we create the best healthcare solution personalized for all of our patient's needs, and are continuously on a path to simplify healthcare for Indonesia.