Search code examples
javascripthtml5-canvas

Reduce the dimension of base64 image maintaining aspect ratio in javascript


I have a base64 string for an image, which i have to display as an icon. If the dimension of an image are bigger i have to display icon maintaining aspect ratio. I have written a logic to identify if the image is landscape or portrait based on which height and width will be settled for canvas. But seems height and width of icons are not proper as i have hard coded it.

      var canvas = document.createElement("canvas");
      var ctx = canvas.getContext("2d");          
      var height, width;
      if (this.height>this.width) {
            height = 50;
            width = 30;
      } else if (this.height<this.width) {
            height = 30;
            width = 50;
      }
      canvas.width = width;
      canvas.height = height;
      ctx.drawImage(image,
            0, 0, this.width, this.height,
            0, 0, canvas.width, canvas.height
      );
      var scaledImage = new Image();
      scaledImage.src = canvas.toDataURL();

Is there any way we can calculate it dynamically or any other way to preserve aspect ratio for icons.

Working Example can be found on https://codepen.io/imjaydeep/pen/ewBZRK

enter image description here

It will be fine if some space will be left on x-y axis.


Solution

  • You just need to calculate the scale or ratio and multiply both dimensions by that. Here's an example function, and here's your edited codepen.

    Creates trimmed, scaled image:

    enter image description here

    function scaleDataURL(dataURL, maxWidth, maxHeight){
      return new Promise(done=>{
        var img = new Image;
        img.onload = ()=>{
          var scale, newWidth, newHeight, canvas, ctx;
          if(img.width < maxWidth){
            scale = maxWidth / img.width;
          }else{
            scale = maxHeight / img.height;
          }
          newWidth = img.width * scale;
          newHeight = img.height * scale;
          canvas = document.createElement('canvas');
          canvas.height = newHeight;
          canvas.width = newWidth;
          ctx = canvas.getContext('2d');
          ctx.drawImage(img, 0, 0, img.width, img.height, 0, 0, newWidth, newHeight);
          done(canvas.toDataURL());
        };
        img.src = dataURL;
      }); 
    }
    

    Or, if you want the image to always be the provided dimensions with empty surrounding area, you can use this: (codepen)

    Creates scaled image of exact provided dimensions:

    enter image description here

    function scaleDataURL(dataURL, maxWidth, maxHeight){
      return new Promise(done=>{
        var img = new Image;
        img.onload = ()=>{
          var scale, newWidth, newHeight, canvas, ctx, dx, dy;
          if(img.width < maxWidth){
            scale = maxWidth / img.width;
          }else{
            scale = maxHeight / img.height;
          }
          newWidth = img.width * scale;
          newHeight = img.height * scale;
          canvas = document.createElement('canvas');
          canvas.height = maxWidth;
          canvas.width = maxHeight;
          ctx = canvas.getContext('2d');
          dx = (maxWidth - newWidth) / 2;
          dy = (maxHeight - newHeight) / 2;
          console.log(dx, dy);
          ctx.drawImage(img, 0, 0, img.width, img.height, dx, dy, newWidth, newHeight);
          done(canvas.toDataURL());
        };
        img.src = dataURL;
      }); 
    }