0

I am trying to crop an image in react by using the react-image-crop library, and I got the cropping functionality working.

import React, { useCallback, useRef, useState } from "react";
import ReactCrop, { Crop } from "react-image-crop";
import "react-image-crop/dist/ReactCrop.css";

export const ImageCropper = () => {
  const [upImg, setUpImg] = useState<string>(
    "https://www.vintagemovieposters.co.uk/wp-content/uploads/2020/04/IMG_5274-scaled.jpeg"
  );
  const imgRef = useRef<HTMLImageElement | null>(null);
  const [crop, setCrop] = useState<Partial<Crop>>({
    unit: "%",
    aspect: 0.68,
    height: 100
  });

  const onLoad: (image: HTMLImageElement) => boolean | void = useCallback(
    (img) => {
      imgRef.current = img;

      const aspect = 0.68;

      const width =
        img.width / aspect < img.height * aspect
          ? 100
          : ((img.height * aspect) / img.width) * 100;
      const height =
        img.width / aspect > img.height * aspect
          ? 100
          : (img.width / aspect / img.height) * 100;
      const y = (100 - height) / 2;
      const x = (100 - width) / 2;

      setCrop({
        unit: "%",
        width,
        height,
        x,
        y,
        aspect
      });
    },
    []
  );

  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      <ReactCrop
        src={upImg}
        onImageLoaded={onLoad}
        crop={crop}
        onChange={(crop, percentageCrop) => {
          setCrop(percentageCrop);
        }}
        keepSelection={true}
      />
      <div
        style={{
          width: imgRef.current?.width! * (crop.width! / 100),
          height: imgRef.current?.height! * (crop.height! / 100),
          overflow: "hidden"
        }}
      >
        <img
          alt="cropped_image"
          src={upImg}
          style={{
            width: imgRef.current?.width!,
            height: imgRef.current?.height!,
            transform: `translate(-${
              (crop.x! / 100) * imgRef.current?.width!
            }px, -${(crop.y! / 100) * imgRef.current?.height!}px )`
          }}
        />
      </div>
    </div>
  );
};

enter image description here

However, what I am trying to achieve is:

  • keep the original image after cropping
  • put the image in a preview div with specific dimensions (235px x 346px)
  • transform the image to fit within that preview div with the same defined crop
  • make sure the preview div matches with the highlighted crop

what I tried is the code above, but the issue with it is that the width + height change dynamically.

I tried to use fixed width and height values, but the cropping is off. I also tried using the scale property in transform, but it was off too:

  return (
    <div style={{ display: "flex", flexDirection: "column" }}>
      <ReactCrop
        src={upImg}
        onImageLoaded={onLoad}
        crop={crop}
        onChange={(crop, percentageCrop) => {
          console.log("percent", percentageCrop);
          setCrop(percentageCrop);
        }}
        keepSelection={true}
      />
      <div
        style={{
          width: 235,
          height: 346,
          overflow: "hidden"
        }}
      >
        <img
          alt="cropped_image"
          src={upImg}
          style={{
            width: imgRef.current?.width!,
            height: imgRef.current?.height!,
            transform: `translate(-${
              (crop.x! / 100) * imgRef.current?.width!
            }px, -${(crop.y! / 100) * imgRef.current?.height!}px) scale(${
              crop.width/100
            }, ${crop.height/100})`
          }}
        />
      </div>
    </div>
  );

enter image description here

I need to figure out how to constrain them to (235px x 346px), and "zoom" the image to match the crop from react-image-crop.

How can I do that?

Example in code sandbox

Riexn
  • 113
  • 2
  • 11

0 Answers0