feat(ui): add crop layer to bbox

This commit is contained in:
psychedelicious
2024-10-03 19:22:20 +10:00
committed by Kent Keirsey
parent e49e5e9782
commit 150d3239e3
9 changed files with 48 additions and 0 deletions

View File

@@ -1563,6 +1563,7 @@
"saveCanvasToGallery": "Save Canvas to Gallery",
"saveBboxToGallery": "Save Bbox to Gallery",
"saveLayerToAssets": "Save Layer to Assets",
"cropLayerToBbox": "Crop Layer to Bbox",
"savedToGalleryOk": "Saved to Gallery",
"savedToGalleryError": "Error saving to gallery",
"newGlobalReferenceImageOk": "Created Global Reference Image",

View File

@@ -1,6 +1,7 @@
import { MenuGroup } from '@invoke-ai/ui-library';
import { useAppSelector } from 'app/store/storeHooks';
import { CanvasEntityMenuItemsCopyToClipboard } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCopyToClipboard';
import { CanvasEntityMenuItemsCropToBbox } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCropToBbox';
import { CanvasEntityMenuItemsDelete } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDelete';
import { CanvasEntityMenuItemsFilter } from 'features/controlLayers/components/common/CanvasEntityMenuItemsFilter';
import { CanvasEntityMenuItemsSave } from 'features/controlLayers/components/common/CanvasEntityMenuItemsSave';
@@ -12,6 +13,7 @@ import {
import { useEntityTitle } from 'features/controlLayers/hooks/useEntityTitle';
import { selectSelectedEntityIdentifier } from 'features/controlLayers/store/selectors';
import {
isCroppableEntityIdentifier,
isFilterableEntityIdentifier,
isSaveableEntityIdentifier,
isTransformableEntityIdentifier,
@@ -28,6 +30,7 @@ const CanvasContextMenuSelectedEntityMenuItemsContent = memo(() => {
{isTransformableEntityIdentifier(entityIdentifier) && <CanvasEntityMenuItemsTransform />}
{isSaveableEntityIdentifier(entityIdentifier) && <CanvasEntityMenuItemsCopyToClipboard />}
{isSaveableEntityIdentifier(entityIdentifier) && <CanvasEntityMenuItemsSave />}
{isCroppableEntityIdentifier(entityIdentifier) && <CanvasEntityMenuItemsCropToBbox />}
<CanvasEntityMenuItemsDelete />
</MenuGroup>
);

View File

@@ -1,6 +1,7 @@
import { MenuDivider } from '@invoke-ai/ui-library';
import { CanvasEntityMenuItemsArrange } from 'features/controlLayers/components/common/CanvasEntityMenuItemsArrange';
import { CanvasEntityMenuItemsCopyToClipboard } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCopyToClipboard';
import { CanvasEntityMenuItemsCropToBbox } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCropToBbox';
import { CanvasEntityMenuItemsDelete } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDelete';
import { CanvasEntityMenuItemsDuplicate } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDuplicate';
import { CanvasEntityMenuItemsFilter } from 'features/controlLayers/components/common/CanvasEntityMenuItemsFilter';
@@ -20,6 +21,7 @@ export const ControlLayerMenuItems = memo(() => {
<MenuDivider />
<CanvasEntityMenuItemsArrange />
<MenuDivider />
<CanvasEntityMenuItemsCropToBbox />
<CanvasEntityMenuItemsDuplicate />
<CanvasEntityMenuItemsCopyToClipboard />
<CanvasEntityMenuItemsSave />

View File

@@ -1,5 +1,6 @@
import { MenuDivider } from '@invoke-ai/ui-library';
import { CanvasEntityMenuItemsArrange } from 'features/controlLayers/components/common/CanvasEntityMenuItemsArrange';
import { CanvasEntityMenuItemsCropToBbox } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCropToBbox';
import { CanvasEntityMenuItemsDelete } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDelete';
import { CanvasEntityMenuItemsDuplicate } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDuplicate';
import { CanvasEntityMenuItemsTransform } from 'features/controlLayers/components/common/CanvasEntityMenuItemsTransform';
@@ -12,6 +13,7 @@ export const InpaintMaskMenuItems = memo(() => {
<MenuDivider />
<CanvasEntityMenuItemsArrange />
<MenuDivider />
<CanvasEntityMenuItemsCropToBbox />
<CanvasEntityMenuItemsDuplicate />
<CanvasEntityMenuItemsDelete />
</>

View File

@@ -1,6 +1,7 @@
import { MenuDivider } from '@invoke-ai/ui-library';
import { CanvasEntityMenuItemsArrange } from 'features/controlLayers/components/common/CanvasEntityMenuItemsArrange';
import { CanvasEntityMenuItemsCopyToClipboard } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCopyToClipboard';
import { CanvasEntityMenuItemsCropToBbox } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCropToBbox';
import { CanvasEntityMenuItemsDelete } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDelete';
import { CanvasEntityMenuItemsDuplicate } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDuplicate';
import { CanvasEntityMenuItemsFilter } from 'features/controlLayers/components/common/CanvasEntityMenuItemsFilter';
@@ -18,6 +19,7 @@ export const RasterLayerMenuItems = memo(() => {
<MenuDivider />
<CanvasEntityMenuItemsArrange />
<MenuDivider />
<CanvasEntityMenuItemsCropToBbox />
<CanvasEntityMenuItemsDuplicate />
<CanvasEntityMenuItemsCopyToClipboard />
<CanvasEntityMenuItemsSave />

View File

@@ -1,5 +1,6 @@
import { MenuDivider } from '@invoke-ai/ui-library';
import { CanvasEntityMenuItemsArrange } from 'features/controlLayers/components/common/CanvasEntityMenuItemsArrange';
import { CanvasEntityMenuItemsCropToBbox } from 'features/controlLayers/components/common/CanvasEntityMenuItemsCropToBbox';
import { CanvasEntityMenuItemsDelete } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDelete';
import { CanvasEntityMenuItemsDuplicate } from 'features/controlLayers/components/common/CanvasEntityMenuItemsDuplicate';
import { CanvasEntityMenuItemsTransform } from 'features/controlLayers/components/common/CanvasEntityMenuItemsTransform';
@@ -17,6 +18,7 @@ export const RegionalGuidanceMenuItems = memo(() => {
<MenuDivider />
<CanvasEntityMenuItemsArrange />
<MenuDivider />
<CanvasEntityMenuItemsCropToBbox />
<CanvasEntityMenuItemsDuplicate />
<CanvasEntityMenuItemsDelete />
</>

View File

@@ -0,0 +1,28 @@
import { MenuItem } from '@invoke-ai/ui-library';
import { useEntityAdapterSafe } from 'features/controlLayers/contexts/EntityAdapterContext';
import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
import { useIsEntityInteractable } from 'features/controlLayers/hooks/useEntityIsInteractable';
import { memo, useCallback } from 'react';
import { useTranslation } from 'react-i18next';
import { PiCropBold } from 'react-icons/pi';
export const CanvasEntityMenuItemsCropToBbox = memo(() => {
const { t } = useTranslation();
const entityIdentifier = useEntityIdentifierContext();
const adapter = useEntityAdapterSafe(entityIdentifier);
const isInteractable = useIsEntityInteractable(entityIdentifier);
const onClick = useCallback(() => {
if (!adapter) {
return;
}
adapter.cropToBbox();
}, [adapter]);
return (
<MenuItem onClick={onClick} icon={<PiCropBold />} isDisabled={!isInteractable}>
{t('controlLayers.cropLayerToBbox')}
</MenuItem>
);
});
CanvasEntityMenuItemsCropToBbox.displayName = 'CanvasEntityMenuItemsCropToBbox';

View File

@@ -18,6 +18,7 @@ import type { CanvasEntityIdentifier, CanvasRenderableEntityState, Rect } from '
import Konva from 'konva';
import { atom, computed } from 'nanostores';
import type { Logger } from 'roarr';
import type { ImageDTO } from 'services/api/types';
import stableHash from 'stable-hash';
import { assert } from 'tsafe';
@@ -295,6 +296,11 @@ export abstract class CanvasEntityAdapterBase<
return stableHash(arg);
};
cropToBbox = (): Promise<ImageDTO> => {
const { rect } = this.manager.stateApi.getBbox();
return this.renderer.rasterize({ rect, replaceObjects: true, attrs: { opacity: 1, filters: [] } });
};
destroy = (): void => {
this.log.debug('Destroying module');
this.subscriptions.forEach((unsubscribe) => unsubscribe());

View File

@@ -465,6 +465,8 @@ export function isTransformableEntityIdentifier(
);
}
export const isCroppableEntityIdentifier = isTransformableEntityIdentifier;
export function isSaveableEntityIdentifier(
entityIdentifier: CanvasEntityIdentifier
): entityIdentifier is CanvasEntityIdentifier<'raster_layer'> | CanvasEntityIdentifier<'control_layer'> {