Repository navigation
Open
Description
I'm having some issues when cropping an image taken from an iOS device, specially iPhones.
Apparently, the canvas width and height, after cropping, are greater than the original image and there's also
a canvas size limit on iOS devices, thus, the canvas.toBlob returns null because there's no actual canvas.
I've also tried the sanbBox demo and the same issue occurs.
How could I solve it? is there a way to resize the dimensions so it fits in the canvas? maintaining the proportions of the crop area.
My code below:
const getCroppedImg = () => {
const { crop, image } = cropRef.current.getCroppedArea();
return new Promise(resolve => {
const canvas = document.createElement('canvas');
const ctx = canvas.getContext('2d');
if (!ctx) {
throw new Error('No 2d context');
}
const scaleX = image.naturalWidth / image.width;
const scaleY = image.naturalHeight / image.height;
const pixelRatio = window.devicePixelRatio;
if (crop.unit === '%') {
canvas.width = (image.naturalWidth * crop.width) / 100;
canvas.height = (image.naturalHeight * crop.height) / 100;
} else {
canvas.width = Math.floor(crop.width * scaleX * pixelRatio);
canvas.height = Math.floor(crop.height * scaleY * pixelRatio);
ctx.scale(pixelRatio, pixelRatio);
}
ctx.imageSmoothingQuality = 'high';
const cropX = crop.x * scaleX;
const cropY = crop.y * scaleY;
const rotate = 0;
const rotateRads = rotate * TO_RADIANS;
const centerX = image.naturalWidth / 2;
const centerY = image.naturalHeight / 2;
ctx.save();
ctx.translate(-cropX, -cropY);
ctx.translate(centerX, centerY);
ctx.rotate(rotateRads);
ctx.scale(1, 1);
ctx.translate(-centerX, -centerY);
ctx.drawImage(
image,
0,
0,
image.naturalWidth,
image.naturalHeight,
0,
0,
image.naturalWidth,
image.naturalHeight
);
ctx.restore();
canvas.toBlob(blobFile => {
const croppedImageUrl = URL.createObjectURL(blobFile);
resolve({ file: blobFile, src: croppedImageUrl });
URL.revokeObjectURL(croppedImageUrl);
}, 'image/jpeg');
});
};Metadata
Metadata
Assignees
Labels
No labels
Activity
massimopibiri commentedon Apr 2, 2024
I struggled all day with this problem and I found a solution. Basically, IOS limit the memory for a canvas, and pictures of the iphones always pass that limit. So, you have to compress the image that you are loading to the canvas. My function to select the image looks like this:
imgUrl is the value of the img tag. It will be then enought compressed to be cropped by the canvas. By the way, since I did it, the crop is a lot faster for Android too. Canvas cropping is quite heavy.
PS. Remember that file compression degeneration is exponential. If you compress in backend too, the image can get a lot wrost.
MohammadrasiM commentedon Aug 12, 2024
Hi , thx it truly worked .
igorsantos07 commentedon Dec 23, 2025
To be more specific about the issue, iOS seems to refuse any image beyond 4096x4096, as reported by the canvas-size library docs. It also makes it explicit that there's not a single damn error message about what's going on with the canvas 🤡
That's also a documented issue at MDN's
canvaspage.The MDN reference is linked from the above-mentioned
browser-image-compressionlib. Given the canvas restriction is actually about dimensions rather than bytes, we've successfully implemented an "if iOS" flag that scales down the image in case it's larger than 4096 at any side, an option already supported by the compression library.Thanks for the pointers, Massimo!
I wonder if @dominictobias has anything that could be done at the cropper implementation. Maybe check dimensions and warn? Or maybe check how
canvas-sizechecks for valid dimensions and implement such check when rendering the cropping canvas?Nonetheless, I don't think the fix should come from this lib, but instead from implementers; the cropper shouldn't be responsible for resizing the picture, at least not without explicit developer consent.