Skip to content

Commit c2683b2

Browse files
fix(ui): issue w/ setting initial aspect ratio in cropper
1 parent 1aa396e commit c2683b2

File tree

3 files changed

+38
-21
lines changed

3 files changed

+38
-21
lines changed

invokeai/frontend/web/src/features/cropper/components/CropImageEditor.tsx

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,9 @@ export const CropImageEditor = memo(({ editor, onApplyCrop, onReady }: Props) =>
5656
editor.onCropBoxChange((crop) => {
5757
setCropBox(crop);
5858
});
59-
setAspectRatio(getAspectRatioString(editor.getCropAspectRatio()));
59+
editor.onAspectRatioChange((ratio) => {
60+
setAspectRatio(getAspectRatioString(ratio));
61+
});
6062
await onReady();
6163
editor.fitToContainer();
6264
},

invokeai/frontend/web/src/features/cropper/lib/editor.ts

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ export type CropBox = {
1919
*/
2020
type EditorCallbacks = {
2121
onCropBoxChange: Set<(crop: Readonly<CropBox>) => void>;
22+
onAspectRatioChange: Set<(ratio: number | null) => void>;
2223
onZoomChange: Set<(zoom: number) => void>;
2324
};
2425

@@ -180,6 +181,7 @@ export class Editor {
180181
private callbacks: EditorCallbacks = {
181182
onCropBoxChange: new Set(),
182183
onZoomChange: new Set(),
184+
onAspectRatioChange: new Set(),
183185
};
184186

185187
private cropBox: CropBox | null = null;
@@ -674,7 +676,7 @@ export class Editor {
674676
this.resetView();
675677

676678
if (initial) {
677-
this.aspectRatio = initial.aspectRatio;
679+
this.setCropAspectRatio(initial.aspectRatio);
678680
this.updateCropBox(initial.cropBox);
679681
} else {
680682
// Create default crop box (centered, 80% of image)
@@ -1460,6 +1462,10 @@ export class Editor {
14601462
width: newWidth,
14611463
height: newHeight,
14621464
});
1465+
1466+
for (const cb of this.callbacks.onAspectRatioChange) {
1467+
cb(ratio);
1468+
}
14631469
};
14641470

14651471
setCropBox = (box: CropBox) => {
@@ -1497,6 +1503,17 @@ export class Editor {
14971503
this.callbacks.onZoomChange.delete(cb);
14981504
};
14991505
};
1506+
1507+
/**
1508+
* Register a callback for when the aspect ratio changes.
1509+
*/
1510+
onAspectRatioChange = (cb: (ratio: number | null) => void): (() => void) => {
1511+
this.callbacks.onAspectRatioChange.add(cb);
1512+
return () => {
1513+
this.callbacks.onAspectRatioChange.delete(cb);
1514+
};
1515+
};
1516+
15001517
/**
15011518
* Resize the editor container and adjust the Konva stage accordingly.
15021519
*

invokeai/frontend/web/src/features/settingsAccordions/components/VideoSettingsAccordion/StartingFrameImage.tsx

Lines changed: 17 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { Box, Flex, FormLabel, Icon, IconButton, Text, Tooltip } from '@invoke-ai/ui-library';
1+
import { Flex, FormLabel, Icon, IconButton, Text, Tooltip } from '@invoke-ai/ui-library';
22
import { objectEquals } from '@observ33r/object-equals';
33
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
44
import { UploadImageIconButton } from 'common/hooks/useImageUploadButton';
@@ -97,33 +97,31 @@ export const StartingFrameImage = () => {
9797
}, [dispatch, originalImageDTO, startingFrameImage?.crop, uploadImage]);
9898

9999
const fitsCurrentAspectRatio = useMemo(() => {
100-
if (!originalImageDTO) {
100+
const imageDTO = croppedImageDTO ?? originalImageDTO;
101+
if (!imageDTO) {
101102
return true;
102103
}
103104

104-
return originalImageDTO.width / originalImageDTO.height === ASPECT_RATIO_MAP[videoAspectRatio]?.ratio;
105-
}, [originalImageDTO, videoAspectRatio]);
105+
const imageRatio = imageDTO.width / imageDTO.height;
106+
const targetRatio = ASPECT_RATIO_MAP[videoAspectRatio].ratio;
107+
108+
// Call it a fit if the image is within 10% of the target aspect ratio
109+
return Math.abs((imageRatio - targetRatio) / targetRatio) < 0.1;
110+
}, [croppedImageDTO, originalImageDTO, videoAspectRatio]);
106111

107112
return (
108113
<Flex justifyContent="flex-start" flexDir="column" gap={2}>
109114
<FormLabel display="flex" alignItems="center" gap={2}>
110115
<Text>{t('parameters.startingFrameImage')}</Text>
111-
<Tooltip label={t('parameters.startingFrameImageAspectRatioWarning', { videoAspectRatio: videoAspectRatio })}>
112-
<Box>
113-
<Icon as={PiWarningBold} size={16} color="warning.500" />
114-
</Box>
115-
</Tooltip>
116+
{!fitsCurrentAspectRatio && (
117+
<Tooltip label={t('parameters.startingFrameImageAspectRatioWarning', { videoAspectRatio: videoAspectRatio })}>
118+
<Flex alignItems="center">
119+
<Icon as={PiWarningBold} size={16} color="warning.300" />
120+
</Flex>
121+
</Tooltip>
122+
)}
116123
</FormLabel>
117-
<Flex
118-
position="relative"
119-
w={36}
120-
h={36}
121-
alignItems="center"
122-
justifyContent="center"
123-
borderWidth={1}
124-
borderStyle="solid"
125-
borderColor={fitsCurrentAspectRatio ? 'base.500' : 'warning.500'}
126-
>
124+
<Flex position="relative" w={36} h={36} alignItems="center" justifyContent="center">
127125
{!originalImageDTO && (
128126
<UploadImageIconButton
129127
w="full"

0 commit comments

Comments
 (0)