fix(web): Ensure profile picture is cropped to 1:1 ratio (#25892)

* fix(web): Ensure profile picture is cropped to 1:1 ratio

Fixes #20097

The profile picture was being captured from the PhotoViewer element
which could have non-square dimensions based on the original image.

Changed to capture from the crop container element which has the
aspect-square class, ensuring the output is always 1:1 ratio.

* fix: remove trailing whitespace to pass prettier check

---------

Co-authored-by: Aditya Gaurav <aditya-ai-architect@users.noreply.github.com>
This commit is contained in:
Aditya Gaurav 2026-02-05 23:15:06 +05:30 committed by GitHub
parent 84b2979485
commit 3c77c724c5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -16,6 +16,7 @@
let { asset, onClose }: Props = $props();
let imgElement: HTMLDivElement | undefined = $state();
let cropContainer: HTMLDivElement | undefined = $state();
onMount(() => {
if (!imgElement) {
@ -51,16 +52,18 @@
};
const onSubmit = async () => {
if (!imgElement) {
if (!cropContainer) {
return;
}
try {
const imgElementHeight = imgElement.offsetHeight;
const imgElementWidth = imgElement.offsetWidth;
const blob = await domtoimage.toBlob(imgElement, {
width: imgElementWidth,
height: imgElementHeight,
// Get the container dimensions (which is always square due to aspect-square class)
const containerSize = cropContainer.offsetWidth;
// Capture the crop container which maintains 1:1 aspect ratio
const blob = await domtoimage.toBlob(cropContainer, {
width: containerSize,
height: containerSize,
});
if (await hasTransparentPixels(blob)) {
@ -83,6 +86,7 @@
<FormModal size="small" title={$t('set_profile_picture')} {onClose} {onSubmit}>
<div class="flex place-items-center items-center justify-center">
<div
bind:this={cropContainer}
class="relative flex aspect-square w-62.5 overflow-hidden rounded-full border-4 border-immich-primary bg-immich-dark-primary dark:border-immich-dark-primary dark:bg-immich-primary"
>
<PhotoViewer bind:element={imgElement} cursor={{ current: asset }} />