JSFiddle - React, Tailwind, and code Playground

by RAX7

HTML

<img id="dest" alt="">

CSS

img {
  display: block;
  width: 400px;
  height: 300px;
}

JavaScript

function loadImg(src) {
  return new Promise(resolve => {
    const img = new Image();
    img.addEventListener('load', () => resolve(img));
    img.crossOrigin = 'Anonymous';
    img.src = src;
  });
}

async function fillNewImage(destImage, options, offsetX = 0.5, offsetY = 0.5) {
  const sourceImage = await loadImg(options.url);
  const dw = destImage.clientWidth;
  const dh = destImage.clientHeight;

  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');
  canvas.width = dw;
  canvas.height = dh;

  const iw = options.width;
  const ih = options.height;

  const ratio = Math.min(dw / iw, dh / ih);
  let nw = iw * ratio;
  let nh = ih * ratio;
  let sx, sy, sw, sh, ar = 1;

  if (nw < dw) ar = dw / nw;
  if (Math.abs(ar - 1) < 1e-14 && nh < dh) ar = dh / nh;
  nw *= ar;
  nh *= ar;

  sw = iw / (nw / dw);
  sh = ih / (nh / dh);

  sx = (iw - sw) * offsetX + (options.x || 0);
  sx = Math.max(0, sx);

  sy = (ih - sh) * offsetY + (options.y || 0);
  sy = Math.max(0, sy);

  ctx.drawImage(sourceImage, sx, sy, sw, sh, 0, 0, dw, dh);
  
  let url;

  function imageLoaded() {
  	URL.revokeObjectURL(url);
    destImage.removeEventListener('load', imageLoaded);
  }

  destImage.addEventListener('load', imageLoaded);

  canvas.toBlob(function(blob){
    url = URL.createObjectURL(blob);
    destImage.src = url;
  });
}

const recivedData = {
  x: 240,
  y: 85,
  width: 600,
  height: 450,
  url: 'https://images.unsplash.com/photo-1549288498-bbec5bc4a554?ixlib=rb-1.2.1&auto=format&fit=crop&w=1500&q=90',
};

const destImg = document.querySelector('#dest');

fillNewImage(destImg, recivedData);