I am implementing a cropping functionality where I work with a downscaled version of the original image. The original image is stored in IndexedDB, and every time I fetch it, it is in its initial dimensions and fully intact. My goal is to apply cropping and rotation operations on the downscaled image and then use the cropping dimensions to crop the corresponding area from the original image.
Everything works as expected when performing a single crop operation. However, the problem arises when I crop the downscaled image at 0° rotation, then rotate it to 90°, and crop again. When I download the cropped image after these operations, the cropped area does not match the expected part of the original image. I believe this issue stems from incorrect calculations when converting dimensions between the downscaled and original image, or during rotation adjustments.
Below is the relevant code I am using:
const adjustCumulativeCropForRotation = (cumulativeCrop, originalWidth, originalHeight, rotation) => {
if (!cumulativeCrop) return null; // No cumulative crop to adjust
const { x, y, width, height } = cumulativeCrop;
switch (rotation) {
case 90:
return {
x: y,
y: originalWidth - width - x,
width,
height
};
case 180:
return {
x: originalWidth - width - x,
y: originalHeight - height - y,
width,
height,
};
case 270:
return {
x: originalHeight - height - y,
y: x,
width: height,
height: width,
};
case 0:
default:
return cumulativeCrop; // No adjustment needed
}
};
// Handle processing the original image
const handleProcessOriginalImage = async () => {
try {
const { originalImage, originalImageName } = await getOriginalImageFromDB();
if (!originalImage) {
console.error("Original image not found");
return;
}
// Rotate the original image before cropping
const rotatedImageBlob = await rotateImage(
originalImage instanceof Blob ? URL.createObjectURL(originalImage) : originalImage,
rotation
);
const dimensions = await getImageDimensions(URL.createObjectURL(rotatedImageBlob));
const { width: originalWidth, height: originalHeight } = dimensions;
const { width: downscaledWidth, height: downscaledHeight } = downscaledImageDimensions;
const { x: cropX, y: cropY, width: cropWidth, height: cropHeight } = cropDimensions;
// Set the current image dimensions
let currentOriginalWidth = currentCroppedImageDimensions?.width || originalWidth;
let currentOriginalHeight = currentCroppedImageDimensions?.height || originalHeight;
if (rotation === 90 || rotation === 270) {
currentOriginalWidth = currentCroppedImageDimensions?.height || originalHeight;
currentOriginalHeight = currentCroppedImageDimensions?.width || originalWidth;
}
// Scale the current crop to the original image dimensions
const scaledCrop = {
x: Math.round((cropX / downscaledWidth) * currentOriginalWidth),
y: Math.round((cropY / downscaledHeight) * currentOriginalHeight),
width: Math.round((cropWidth / downscaledWidth) * currentOriginalWidth),
height: Math.round((cropHeight / downscaledHeight) * currentOriginalHeight),
};
let recalculatedCumulativeCrop = cumulativeCrop;
if (rotation !== 0 && recalculatedCumulativeCrop) {
recalculatedCumulativeCrop = adjustCumulativeCropForRotation(
recalculatedCumulativeCrop,
originalWidth, // Always use initial original dimensions
originalHeight,
rotation
);
}
// Update cumulative crop with new crop
let updatedCumulativeCrop = recalculatedCumulativeCrop
? {
x: recalculatedCumulativeCrop.x + scaledCrop.x,
y: recalculatedCumulativeCrop.y + scaledCrop.y,
width: scaledCrop.width,
height: scaledCrop.height,
}
: { ...scaledCrop };
// Update the state asynchronously
setCumulativeCrop(updatedCumulativeCrop);
setCurrentCroppedImageDimensions({
width: scaledCrop.width,
height: scaledCrop.height,
});
// Process the original image using the updated crop
const processedBlob = await processOriginalImage(rotatedImageBlob, updatedCumulativeCrop, rotation);
// Download the processed image
downloadImage(processedBlob, originalImageName);
} catch (error) {
console.error("Error processing original image:", error);
}
};
I suspect the issue is in how I calculate or adjust the cropping dimensions when the image is rotated or scaled. How can I correctly compute the cropping area to ensure the selected portion matches the original image, regardless of rotation or scaling? Any insights or suggestions to fix this would be highly appreciated!