ValentinH / react-easy-crop

A React component to crop images/videos with easy interactions

Home Page:https://valentinh.github.io/react-easy-crop/

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

After Cropping the image got shifted to the corner

alisarfaraj opened this issue · comments

When i crop the image the after cropping, image got shifted to corner then cropped with cornered side of image i am not moving the image to anywhere so it should be cropped from center but it's not

what i am cropping

cropBefore

and what i am getting

afterCrop

Without any code, I'm not able to help you. The best for me to help would be to share a codesandbox.

this is the jsx code for image cropper

import React, { useCallback, useState } from "react";
import { Modal, Slider } from "antd";
import Cropper from "react-easy-crop";
import { Area } from "react-easy-crop/types";
import { getCroppedImg } from "@/utils/cropperFunction";
import {
  handleImageCropperToggle,
  imageCropperToggle,
} from "@/redux/reducers/modalsToggle";
import { IMAGE_VARIENTS } from "@/utils/enum";
import { useAppDispatch, useAppSelector } from "@/redux/hooks/hooks";

interface imageCropperI {
  fileToCrop: string;
  setCroppedImage: (arg: string | null) => void;
  imageType: IMAGE_VARIENTS;
  fileExtension: string;
}

const ImageCropperComponent = ({
  fileToCrop,
  setCroppedImage,
  imageType,
  fileExtension,
}: imageCropperI) => {
  // redux selector and dispatcher
  const dispatch = useAppDispatch();
  const toggleImageCropper = useAppSelector(imageCropperToggle);

  // state management
  const [crop, setCrop] = useState({ x: 0, y: 0 });
  const [rotation, setRotation] = useState(0);
  const [zoom, setZoom] = useState(1);
  const [croppedAreaPixels, setCroppedAreaPixels] = useState<Area | null>(null);

  const onCropComplete = useCallback((croppedAreaPixels: Area) => {
    setCroppedAreaPixels(croppedAreaPixels);
  }, []);

  const showCroppedImage = useCallback(async () => {
    try {
      const croppedImage = await getCroppedImg(
        fileToCrop,
        croppedAreaPixels,
        rotation,
        fileExtension
      );

      setCroppedImage(croppedImage);
      setTimeout(() => {
        dispatch(handleImageCropperToggle(false));
      }, 1000);
    } catch (e) {
      console.error(e);
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [croppedAreaPixels, rotation, setCroppedImage]);

  return (
    <Modal
      open={toggleImageCropper}
      onOk={() => showCroppedImage()}
      onCancel={() => dispatch(handleImageCropperToggle(false))}
      title="Crop your image in your desire ratio"
    >
      <div
        style={{
          position: "relative",
          width: "100%",
          height: 250,
          background: "#333",
        }}
      >
        <Cropper
          image={fileToCrop}
          crop={crop}
          rotation={rotation}
          zoom={zoom}
          aspect={
            imageType === IMAGE_VARIENTS.profile
              ? 1 / 1
              : imageType === IMAGE_VARIENTS.event
              ? 100 / 100
              : 1 / 1
          }
          cropShape={imageType === IMAGE_VARIENTS.event ? "rect" : "round"}
          onCropChange={setCrop}
          onRotationChange={setRotation}
          onCropComplete={onCropComplete}
          onZoomChange={setZoom}
        />
      </div>

      <div style={{ display: "flex", alignItems: "center", marginTop: "20px" }}>
        <h5 style={{ fontSize: "16px", fontWeight: 700 }}>Zoom</h5>
        <div style={{ width: "70%", marginLeft: "30px" }}>
          <Slider
            value={zoom}
            min={1}
            max={10}
            onChange={(zoom) => setZoom(zoom)}
          />
        </div>
      </div>
    </Modal>
  );
};

export default ImageCropperComponent;


and these are the functions used for cropping


import { Area } from "react-easy-crop/types";
// crop image function
export const createImage = (url: string): Promise<HTMLImageElement> =>
  new Promise((resolve, reject) => {
    const image = new Image();
    image.addEventListener("load", () => resolve(image));
    image.addEventListener("error", (error) => reject(error));
    image.setAttribute("crossOrigin", "anonymous");
    image.src = url;
  });

export function getRadianAngle(degreeValue: number) {
  return (degreeValue * Math.PI) / 180;
}

/**
 * Returns the new bounding area of a rotated rectangle.
 */
export function rotateSize(width: number, height: number, rotation: number) {
  const rotRad = getRadianAngle(rotation);

  return {
    width:
      Math.abs(Math.cos(rotRad) * width) + Math.abs(Math.sin(rotRad) * height),
    height:
      Math.abs(Math.sin(rotRad) * width) + Math.abs(Math.cos(rotRad) * height),
  };
}

// get cropped image
export async function getCroppedImg(
  imageSrc: string,
  pixelCrop: Area | null,
  rotation = 0,
  fileType: string,
  flip = { horizontal: false, vertical: false }
) {
  const image = await createImage(imageSrc);
  const canvas = document.createElement("canvas");
  const ctx = canvas.getContext("2d");

  if (!ctx) {
    return null;
  }

  const rotRad = getRadianAngle(rotation);

  // calculate bounding box of the rotated image
  const { width: bBoxWidth, height: bBoxHeight } = rotateSize(
    image.width,
    image.height,
    rotation
  );

  // set canvas size to match the bounding box
  canvas.width = bBoxWidth;
  canvas.height = bBoxHeight;

  // translate canvas context to a central location to allow rotating and flipping around the center
  ctx.translate(bBoxWidth / 2, bBoxHeight / 2);
  ctx.rotate(rotRad);
  ctx.scale(flip.horizontal ? -1 : 1, flip.vertical ? -1 : 1);
  ctx.translate(-image.width / 2, -image.height / 2);

  // draw rotated image
  ctx.drawImage(image, 0, 0);

  // croppedAreaPixels values are bounding box relative
  // extract the cropped image using these values
  if (pixelCrop) {
    const data = ctx.getImageData(
      pixelCrop.x,
      pixelCrop.y,
      pixelCrop.width,
      pixelCrop.height
    );

    // set canvas width to final desired crop size - this will clear existing context
    canvas.width = pixelCrop.width;
    canvas.height = pixelCrop.height;

    // paste generated rotate image at the top left corner
    ctx.putImageData(data, 0, 0);
  }

  // As Base64 string
  return canvas.toDataURL(`image/${fileType.split("/").pop()}`);

  //   return new Promise((resolve, reject) => {
  //     canvas.toBlob((blob) => {
  //       resolve(
  //         new File(
  //           [blob],
  //           `${Date.now() + `newFile.${fileType.split("/").pop()}`}`,
  //           {
  //             type: fileType,
  //           }
  //         )
  //       );
  //     }, fileType);
  //   });

  // // As a blob
  // return new Promise((resolve, reject) => {
  //   canvas.toBlob((file) => {
  //     resolve(URL.createObjectURL(file));
  //   }, "image/jpeg");
  // });
}


At the first glance (as this is a lot of code), I don't see the issue. I'd really be able to help if you could create a codesandbox showing the exact issue with the minimum amount of code.

Closing as there was no answer for a while. Comment to re-open 😉