fix: CRITICAL - prevent image clipping when rotating

When rotating images, the rotated corners extend beyond the original canvas
bounds, causing the image to be clipped and appear skewed.

Fixed by:
1. Calculate canvas size needed to fit rotated image
2. Use formula: newSize = sqrt((w*cos)^2 + (h*sin)^2)
3. Center image and rotate around center of new canvas
4. Update cropBounds to new canvas dimensions

Now when user rotates an image, the full rotated result is saved without
any clipping or skewing. The saved image dimensions will be larger than
the original to accommodate the rotation.

Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
This commit is contained in:
2026-04-22 14:19:20 +03:00
parent 8bcbf4a4a8
commit 743f377357
2 changed files with 21 additions and 15 deletions

View File

@@ -138,22 +138,27 @@ export function ImageAdjustmentModal({ imageUrl, onConfirm, onCancel }: ImageAdj
return;
}
// Use full image dimensions (no cropping)
const { width, height } = imageDimensions;
processCanvas.width = width;
processCanvas.height = height;
console.log('[Processing] Canvas dimensions:', width, 'x', height);
// Calculate canvas size needed to fit rotated image (prevent clipping)
const radians = (rotation * Math.PI) / 180;
const cos = Math.abs(Math.cos(radians));
const sin = Math.abs(Math.sin(radians));
const newWidth = Math.ceil(width * cos + height * sin);
const newHeight = Math.ceil(width * sin + height * cos);
processCanvas.width = newWidth;
processCanvas.height = newHeight;
console.log('[Processing] Original dimensions:', width, 'x', height);
console.log('[Processing] Canvas size for rotation:', newWidth, 'x', newHeight);
console.log('[Processing] Applying rotation:', rotation, '°');
// Apply rotation around center
// Apply rotation around center of canvas
ctx.save();
ctx.translate(width / 2, height / 2);
ctx.rotate((rotation * Math.PI) / 180);
ctx.translate(-width / 2, -height / 2);
console.log('[Processing] Drawing image with rotation applied');
ctx.drawImage(imageRef.current, 0, 0);
ctx.translate(newWidth / 2, newHeight / 2);
ctx.rotate(radians);
ctx.drawImage(imageRef.current, -width / 2, -height / 2);
ctx.restore();
console.log('[Processing] Canvas draw complete');
@@ -163,16 +168,17 @@ export function ImageAdjustmentModal({ imageUrl, onConfirm, onCancel }: ImageAdj
if (blob) {
console.log('[Result] Processed image blob size:', blob.size, 'bytes');
console.log('[Result] Blob type:', blob.type);
console.log('[Result] Final canvas size:', newWidth, 'x', newHeight);
console.log('=== END DEBUG ===');
// Return with full image bounds (no crop) and rotation
// Return with new canvas bounds and rotation
onConfirm({
rotation,
cropBounds: { x: 0, y: 0, width, height },
cropBounds: { x: 0, y: 0, width: newWidth, height: newHeight },
imageBlob: blob
});
} else {
console.log('[ERROR] Failed to convert canvas to blob');
onConfirm({ rotation, cropBounds: { x: 0, y: 0, width, height } });
onConfirm({ rotation, cropBounds: { x: 0, y: 0, width: newWidth, height: newHeight } });
}
}, 'image/jpeg', 0.95);
};

File diff suppressed because one or more lines are too long