Download portion of image under rectangle

My code loads an image onto a plane. Then, it draws a rectangle on the image. It attempts to get the portion of the image underneath the rectangle. Finally, on button click, it downloads the extracted image. The problem is, the extracted image only contains part of the top of what’s under the rectangle. I’m not sure why my calculation is wrong. Any ideas? Or a working example?

let imgSrc = "image4.jpg";

  let scene = new THREE.Scene();
  let camera = new THREE.PerspectiveCamera(75, window.innerWidth / window.innerHeight, 0.1, 1000);
  camera.position.z = 2;

  const renderer = new THREE.WebGLRenderer({ alpha: true, antialias: true, preserveDrawingBuffer: true });
  renderer.setSize(window.innerWidth, window.innerHeight);
  document.body.appendChild(renderer.domElement);

  let planeGeom = new THREE.PlaneGeometry(4, 4);
  let planeMaterial, plane;

  let tex = new THREE.TextureLoader().load(imgSrc, (texture) => {
    texture.needsUpdate = true;
    const aspect = texture.image.height / texture.image.width;

    planeMaterial = new THREE.MeshBasicMaterial({
      color: 0xffffff,
      map: texture
    });

    plane = new THREE.Mesh(planeGeom, planeMaterial);
    plane.scale.set(1.0, aspect, 1.0);
    scene.add(plane);

    // Trigger the download
    document.getElementById("download").addEventListener("click", function () {
      adjustRectangleAndDownload(texture.image, plane);
    });
  });

  // Rectangle geometry setup
  let vertices = new Float32Array([
    -1.0, -1.0, 0.0,  // Vertex 1: bottom left
    1.0, -1.0, 0.0,   // Vertex 2: bottom right
    1.0, 1.0, 0.0,    // Vertex 3: top right
    -1.0, 1.0, 0.0    // Vertex 4: top left
  ]);

  let geometry = new THREE.BufferGeometry();
  geometry.setAttribute('position', new THREE.BufferAttribute(vertices, 3));

  // Use LineLoop to draw the rectangle
  let material = new THREE.LineBasicMaterial({ color: 0x0000ff });
  let rectangle = new THREE.LineLoop(geometry, material);
  rectangle.renderOrder = 1;

  // Add the rectangle to the scene
  scene.add(rectangle);

  // GET THE FOUR CORNERS OF THE RECTANGLE
  const verticesA = rectangle.geometry.attributes.position.array;

  // Function to adjust and download the image portion
  function adjustRectangleAndDownload(image, plane) {
    const imageWidth = image.width;
    const imageHeight = image.height;
    const planeScale = { x: plane.scale.x, y: plane.scale.y };

    // Convert scene coordinates to image pixel coordinates
    const pixelVertices = convertSceneCoordsToImageCoords(verticesA, imageWidth, imageHeight, planeGeom, planeScale);

    // Extracting the bounding box of the rectangle in image coordinates
    let minX = Math.min(...pixelVertices.filter((v, i) => i % 2 === 0));
    let minY = Math.min(...pixelVertices.filter((v, i) => i % 2 !== 0));
    let maxX = Math.max(...pixelVertices.filter((v, i) => i % 2 === 0));
    let maxY = Math.max(...pixelVertices.filter((v, i) => i % 2 !== 0));

    // Now use these points to crop the image and download it
    let canvas = document.createElement('canvas');
    let ctx = canvas.getContext('2d');
    // Set canvas size to the size of the rectangle
    canvas.width = maxX - minX;
    canvas.height = maxY - minY;

    // Crop and draw the image portion on the canvas
    ctx.drawImage(image, -minX, -minY, imageWidth, imageHeight);
    canvas.toBlob(function (blob) {
      let link = document.createElement('a');
      link.href = URL.createObjectURL(blob);
      link.download = 'cropped_image.png';
      document.body.appendChild(link);
      link.click();
      document.body.removeChild(link);
    }, 'image/png');
  }

  // Convert Three.js coordinates to image pixel coordinates, taking plane scaling into account
  function convertSceneCoordsToImageCoords(vertices, imageWidth, imageHeight, planeGeometry, planeScale) {
    const scaleX = imageWidth / (planeGeometry.parameters.width * planeScale.x);
    const scaleY = imageHeight / (planeGeometry.parameters.height * planeScale.y);

    let pixelVertices = [];
    for (let i = 0; i < vertices.length; i += 3) {
      const x = (vertices[i] + planeGeometry.parameters.width / 2) * scaleX;
      const y = (1 - (vertices[i + 1] + planeGeometry.parameters.height / 2) / planeGeometry.parameters.height) * scaleY;
      pixelVertices.push(x, y);
    }
    return pixelVertices;
  }

  window.addEventListener("resize", () => {
    camera.aspect = window.innerWidth / window.innerHeight;
    camera.updateProjectionMatrix();
    renderer.setSize(window.innerWidth, window.innerHeight);
  });

  (function animate() {
    requestAnimationFrame(animate);
    renderer.render(scene, camera);
  })();