markAspectCrop default value is incorrect
elmarti opened this issue · 4 comments
Setting a default crop on an image with an aspect ratio.
The default crop shown on the image is as expected, but when I hit save, the resultant cropped image is the bottom left quarter (or smaller) of the image.
If I resize the image, the crop works correctly. This is only a problem with the crop set in onImageLoad
import React, { useState, type ReactElement, useRef } from 'react';
import { type DimensionsModalProps } from './DimensionsModalProps';
import { Modal } from '../Modal/Modal';
import ReactCrop, { centerCrop, makeAspectCrop, type Crop } from 'react-image-crop';
import { Buffer } from 'buffer';
import { Button } from '../Button/Button';
import { Loader } from '../Loader/Loader';
export const DimensionsModal = ({ url, file, onComplete, show, setShow, x, y }: DimensionsModalProps): ReactElement => {
const [crop, setCrop] = useState<Crop>();
const [imageLoaded, setImageLoaded] = useState(false);
const imgRef = useRef(null);
const saveCroppedImage = (): void => {
if (!file) {
return;
}
if (!crop) {
return;
}
if(!imgRef.current){
return;
}
const canvas = document.createElement('canvas');
// get the image element
const image = imgRef.current as HTMLImageElement;
// draw the image on the canvas
if (image) {
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
const ctx = canvas.getContext('2d');
const pixelRatio = window.devicePixelRatio;
canvas.width = crop.width * pixelRatio * scaleX;
canvas.height = crop.height * pixelRatio * scaleY;
if (ctx) {
ctx.setTransform(pixelRatio, 0, 0, pixelRatio, 0, 0);
ctx.imageSmoothingQuality = 'high';
ctx.drawImage(
image,
crop.x * scaleX,
crop.y * scaleY,
crop.width * scaleX,
crop.height * scaleY,
0,
0,
crop.width * scaleX,
crop.height * scaleY
);
}
const base64Image = canvas.toDataURL(file.type); // can be changed to jpeg/jpg etc
if (base64Image) {
const buffer = Buffer.from(
base64Image.replace(/^data:image\/\w+;base64,/, ''),
'base64'
);
const newFile = new File([buffer], file.name, { type: file.type });
onComplete(newFile);
setShow(false);
}
}
};
function onImageLoad (e: any): void {
console.log({imgRef})
if(!imgRef.current){
return;
}
const { naturalWidth: width, naturalHeight: height } = (imgRef.current as HTMLImageElement);
const crop = centerCrop(
makeAspectCrop(
{
unit: '%',
width: 100,
height: 100
},
x / y,
width,
height
),
width,
height
);
setCrop(crop);
setImageLoaded(true);
}
return <Modal setShowModal={setShow} show={show}>
<Loader loading={!imageLoaded}>
<ReactCrop aspect={ x / y} crop={crop} onChange={c => {
console.log(c);
setCrop(c);
}}>
<img ref={imgRef} src={url} onLoad={onImageLoad}/>
</ReactCrop>
<Button onClick={saveCroppedImage}>Save</Button>
</Loader>
</Modal>;
};
Yes, I'm also facing the same issue.
Yes, I'm also facing the same issue.
I don't have this issue in the Codesandbox demo. I recommend you look there to see how your code differs: https://codesandbox.io/p/sandbox/react-image-crop-demo-with-react-hooks-y831o
P.S. You shouldn't use canvas.toDataURL
as it freezes up the main thread which is noticeable for larger images on mobile devices, and a data URL is also less efficient than a blob
If you see the same issue with the sandbox demo I'll re-open this
Running into this now @elmarti do you remember what your solution was?
No solution unfortunately and I now don't have access to the project any more. Although I recall there was very little difference in my code to the example