From 8d83caaae067121b2e44deac7b097a0e7d501892 Mon Sep 17 00:00:00 2001 From: psychedelicious <4822129+psychedelicious@users.noreply.github.com> Date: Sat, 5 Jul 2025 20:03:52 +1000 Subject: [PATCH] feat(ui): extract aspect ratios from canvas reducers --- .../controlLayers/store/canvasSlice.ts | 64 ++++--------------- .../src/features/controlLayers/store/types.ts | 59 +++++++++++++---- .../parameters/components/Bbox/constants.ts | 13 ---- 3 files changed, 59 insertions(+), 77 deletions(-) delete mode 100644 invokeai/frontend/web/src/features/parameters/components/Bbox/constants.ts diff --git a/invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts b/invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts index 952eaf401f..e6af138b1d 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/canvasSlice.ts @@ -32,7 +32,6 @@ import { } from 'features/controlLayers/util/getScaledBoundingBoxDimensions'; import { simplifyFlatNumbersArray } from 'features/controlLayers/util/simplify'; import { isMainModelBase, zModelIdentifierField } from 'features/nodes/types/common'; -import { ASPECT_RATIO_MAP } from 'features/parameters/components/Bbox/constants'; import { API_BASE_MODELS } from 'features/parameters/types/constants'; import { getGridSize, getIsSizeOptimal, getOptimalDimension } from 'features/parameters/util/optimalDimension'; import type { IRect } from 'konva/lib/types'; @@ -69,9 +68,13 @@ import type { T2IAdapterConfig, } from './types'; import { + ASPECT_RATIO_MAP, + CHATGPT_ASPECT_RATIOS, DEFAULT_ASPECT_RATIO_CONFIG, + FLUX_KONTEXT_ASPECT_RATIOS, getEntityIdentifier, getInitialCanvasState, + IMAGEN_ASPECT_RATIOS, isChatGPT4oAspectRatioID, isFluxKontextAspectRatioID, isFLUXReduxConfig, @@ -1100,62 +1103,21 @@ export const canvasSlice = createSlice({ (state.bbox.modelBase === 'imagen3' || state.bbox.modelBase === 'imagen4') && isImagenAspectRatioID(id) ) { - // Imagen3 has specific output sizes that are not exactly the same as the aspect ratio. Need special handling. - if (id === '16:9') { - state.bbox.rect.width = 1408; - state.bbox.rect.height = 768; - } else if (id === '4:3') { - state.bbox.rect.width = 1280; - state.bbox.rect.height = 896; - } else if (id === '1:1') { - state.bbox.rect.width = 1024; - state.bbox.rect.height = 1024; - } else if (id === '3:4') { - state.bbox.rect.width = 896; - state.bbox.rect.height = 1280; - } else if (id === '9:16') { - state.bbox.rect.width = 768; - state.bbox.rect.height = 1408; - } + const { width, height } = IMAGEN_ASPECT_RATIOS[id]; + state.bbox.rect.width = width; + state.bbox.rect.height = height; state.bbox.aspectRatio.value = state.bbox.rect.width / state.bbox.rect.height; state.bbox.aspectRatio.isLocked = true; } else if (state.bbox.modelBase === 'chatgpt-4o' && isChatGPT4oAspectRatioID(id)) { - // gpt-image has specific output sizes that are not exactly the same as the aspect ratio. Need special handling. - if (id === '3:2') { - state.bbox.rect.width = 1536; - state.bbox.rect.height = 1024; - } else if (id === '1:1') { - state.bbox.rect.width = 1024; - state.bbox.rect.height = 1024; - } else if (id === '2:3') { - state.bbox.rect.width = 1024; - state.bbox.rect.height = 1536; - } + const { width, height } = CHATGPT_ASPECT_RATIOS[id]; + state.bbox.rect.width = width; + state.bbox.rect.height = height; state.bbox.aspectRatio.value = state.bbox.rect.width / state.bbox.rect.height; state.bbox.aspectRatio.isLocked = true; } else if (state.bbox.modelBase === 'flux-kontext' && isFluxKontextAspectRatioID(id)) { - if (id === '3:4') { - state.bbox.rect.width = 880; - state.bbox.rect.height = 1184; - } else if (id === '4:3') { - state.bbox.rect.width = 1184; - state.bbox.rect.height = 880; - } else if (id === '9:16') { - state.bbox.rect.width = 752; - state.bbox.rect.height = 1392; - } else if (id === '16:9') { - state.bbox.rect.width = 1392; - state.bbox.rect.height = 752; - } else if (id === '21:9') { - state.bbox.rect.width = 1568; - state.bbox.rect.height = 672; - } else if (id === '9:21') { - state.bbox.rect.width = 672; - state.bbox.rect.height = 1568; - } else if (id === '1:1') { - state.bbox.rect.width = 1024; - state.bbox.rect.height = 1024; - } + const { width, height } = FLUX_KONTEXT_ASPECT_RATIOS[id]; + state.bbox.rect.width = width; + state.bbox.rect.height = height; state.bbox.aspectRatio.value = state.bbox.rect.width / state.bbox.rect.height; state.bbox.aspectRatio.isLocked = true; } else { diff --git a/invokeai/frontend/web/src/features/controlLayers/store/types.ts b/invokeai/frontend/web/src/features/controlLayers/store/types.ts index 93ede27178..59f8f05679 100644 --- a/invokeai/frontend/web/src/features/controlLayers/store/types.ts +++ b/invokeai/frontend/web/src/features/controlLayers/store/types.ts @@ -434,21 +434,54 @@ export type LoRA = { export type EphemeralProgressImage = { sessionId: string; image: ProgressImage }; export const zAspectRatioID = z.enum(['Free', '21:9', '9:21', '16:9', '3:2', '4:3', '1:1', '3:4', '2:3', '9:16']); - -export const zImagen3AspectRatioID = z.enum(['16:9', '4:3', '1:1', '3:4', '9:16']); -export const isImagenAspectRatioID = (v: unknown): v is z.infer => - zImagen3AspectRatioID.safeParse(v).success; - -export const zChatGPT4oAspectRatioID = z.enum(['3:2', '1:1', '2:3']); -export const isChatGPT4oAspectRatioID = (v: unknown): v is z.infer => - zChatGPT4oAspectRatioID.safeParse(v).success; - -export const zFluxKontextAspectRatioID = z.enum(['21:9', '4:3', '1:1', '3:4', '9:21', '16:9', '9:16']); -export const isFluxKontextAspectRatioID = (v: unknown): v is z.infer => - zFluxKontextAspectRatioID.safeParse(v).success; - export type AspectRatioID = z.infer; export const isAspectRatioID = (v: unknown): v is AspectRatioID => zAspectRatioID.safeParse(v).success; +export const ASPECT_RATIO_MAP: Record, { ratio: number; inverseID: AspectRatioID }> = { + '21:9': { ratio: 21 / 9, inverseID: '9:21' }, + '16:9': { ratio: 16 / 9, inverseID: '9:16' }, + '3:2': { ratio: 3 / 2, inverseID: '2:3' }, + '4:3': { ratio: 4 / 3, inverseID: '4:3' }, + '1:1': { ratio: 1, inverseID: '1:1' }, + '3:4': { ratio: 3 / 4, inverseID: '4:3' }, + '2:3': { ratio: 2 / 3, inverseID: '3:2' }, + '9:16': { ratio: 9 / 16, inverseID: '16:9' }, + '9:21': { ratio: 9 / 21, inverseID: '21:9' }, +}; + +export const zImagen3AspectRatioID = z.enum(['16:9', '4:3', '1:1', '3:4', '9:16']); +type ImagenAspectRatio = z.infer; +export const isImagenAspectRatioID = (v: unknown): v is ImagenAspectRatio => zImagen3AspectRatioID.safeParse(v).success; +export const IMAGEN_ASPECT_RATIOS: Record = { + '16:9': { width: 1408, height: 768 }, + '4:3': { width: 1280, height: 896 }, + '1:1': { width: 1024, height: 1024 }, + '3:4': { width: 896, height: 1280 }, + '9:16': { width: 768, height: 1408 }, +}; + +export const zChatGPT4oAspectRatioID = z.enum(['3:2', '1:1', '2:3']); +type ChatGPT4oAspectRatio = z.infer; +export const isChatGPT4oAspectRatioID = (v: unknown): v is ChatGPT4oAspectRatio => + zChatGPT4oAspectRatioID.safeParse(v).success; +export const CHATGPT_ASPECT_RATIOS: Record = { + '3:2': { width: 1536, height: 1024 }, + '1:1': { width: 1024, height: 1024 }, + '2:3': { width: 1024, height: 1536 }, +} as const; + +export const zFluxKontextAspectRatioID = z.enum(['21:9', '4:3', '1:1', '3:4', '9:21', '16:9', '9:16']); +type FluxKontextAspectRatio = z.infer; +export const isFluxKontextAspectRatioID = (v: unknown): v is z.infer => + zFluxKontextAspectRatioID.safeParse(v).success; +export const FLUX_KONTEXT_ASPECT_RATIOS: Record = { + '3:4': { width: 880, height: 1184 }, + '4:3': { width: 1184, height: 880 }, + '9:16': { width: 752, height: 1392 }, + '16:9': { width: 1392, height: 752 }, + '21:9': { width: 1568, height: 672 }, + '9:21': { width: 672, height: 1568 }, + '1:1': { width: 1024, height: 1024 }, +}; const zAspectRatioConfig = z.object({ id: zAspectRatioID, diff --git a/invokeai/frontend/web/src/features/parameters/components/Bbox/constants.ts b/invokeai/frontend/web/src/features/parameters/components/Bbox/constants.ts deleted file mode 100644 index b614eaec86..0000000000 --- a/invokeai/frontend/web/src/features/parameters/components/Bbox/constants.ts +++ /dev/null @@ -1,13 +0,0 @@ -import type { AspectRatioID } from 'features/controlLayers/store/types'; - -export const ASPECT_RATIO_MAP: Record, { ratio: number; inverseID: AspectRatioID }> = { - '21:9': { ratio: 21 / 9, inverseID: '9:21' }, - '16:9': { ratio: 16 / 9, inverseID: '9:16' }, - '3:2': { ratio: 3 / 2, inverseID: '2:3' }, - '4:3': { ratio: 4 / 3, inverseID: '4:3' }, - '1:1': { ratio: 1, inverseID: '1:1' }, - '3:4': { ratio: 3 / 4, inverseID: '4:3' }, - '2:3': { ratio: 2 / 3, inverseID: '3:2' }, - '9:16': { ratio: 9 / 16, inverseID: '16:9' }, - '9:21': { ratio: 9 / 21, inverseID: '21:9' }, -};