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>
);
};
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>
);
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?