Skip to content
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 20 additions & 5 deletions packages/image-crop/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,16 @@ const getCroppedPngImage = async (
imageSrc: HTMLImageElement,
scaleFactor: number,
pixelCrop: PixelCrop,
maxImageSize: number
maxImageSize: number,
minScale: number = 0.1
): Promise<string> => {
// Prevent infinite recursion by enforcing a minimum scale
if (scaleFactor < minScale) {
throw new Error(
`Unable to reduce image size below ${maxImageSize} bytes. Try using a smaller crop area or increasing maxImageSize.`
);
}

const canvas = document.createElement("canvas");
const ctx = canvas.getContext("2d");

Expand All @@ -65,9 +73,13 @@ const getCroppedPngImage = async (
const scaleX = imageSrc.naturalWidth / imageSrc.width;
const scaleY = imageSrc.naturalHeight / imageSrc.height;

ctx.imageSmoothingEnabled = false;
canvas.width = pixelCrop.width;
canvas.height = pixelCrop.height;
// Enable image smoothing for better quality when downscaling
ctx.imageSmoothingEnabled = true;
ctx.imageSmoothingQuality = "high";

// Apply scale factor to canvas dimensions to actually downscale the image
canvas.width = Math.max(1, Math.floor(pixelCrop.width * scaleFactor));
canvas.height = Math.max(1, Math.floor(pixelCrop.height * scaleFactor));

ctx.drawImage(
imageSrc,
Expand Down Expand Up @@ -129,6 +141,7 @@ const useImageCrop = () => {
export type ImageCropProps = {
file: File;
maxImageSize?: number;
minScale?: number;
onCrop?: (croppedImage: string) => void;
children: ReactNode;
onChange?: ReactCropProps["onChange"];
Expand All @@ -138,6 +151,7 @@ export type ImageCropProps = {
export const ImageCrop = ({
file,
maxImageSize = 1024 * 1024 * 5,
minScale = 0.1,
onCrop,
children,
onChange,
Expand Down Expand Up @@ -191,7 +205,8 @@ export const ImageCrop = ({
imgRef.current,
1,
completedCrop,
maxImageSize
maxImageSize,
minScale
);

onCrop?.(croppedImage);
Expand Down