sekoyo/react-image-crop

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.

sekoyo commented

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