feat(ui): restore transparency effect for control layers

This commit is contained in:
psychedelicious 2024-08-20 12:05:46 +10:00
parent 6c6b1aaff6
commit fc75f7919f
9 changed files with 73 additions and 11 deletions

View File

@ -1698,6 +1698,8 @@
"filter": "Filter",
"convertToControlLayer": "Convert to Control Layer",
"convertToRasterLayer": "Convert to Raster Layer",
"enableTransparencyEffect": "Enable Transparency Effect",
"disableTransparencyEffect": "Disable Transparency Effect",
"fill": {
"fillStyle": "Fill Style",
"solid": "Solid",

View File

@ -4,6 +4,7 @@ import { CanvasEntityMenuItemsDelete } from 'features/controlLayers/components/c
import { CanvasEntityMenuItemsFilter } from 'features/controlLayers/components/common/CanvasEntityMenuItemsFilter';
import { CanvasEntityMenuItemsReset } from 'features/controlLayers/components/common/CanvasEntityMenuItemsReset';
import { ControlLayerMenuItemsControlToRaster } from 'features/controlLayers/components/ControlLayer/ControlLayerMenuItemsControlToRaster';
import { ControlLayerMenuItemsTransparencyEffect } from 'features/controlLayers/components/ControlLayer/ControlLayerMenuItemsTransparencyEffect';
import { memo } from 'react';
export const ControlLayerMenuItems = memo(() => {
@ -11,6 +12,7 @@ export const ControlLayerMenuItems = memo(() => {
<>
<CanvasEntityMenuItemsFilter />
<ControlLayerMenuItemsControlToRaster />
<ControlLayerMenuItemsTransparencyEffect />
<MenuDivider />
<CanvasEntityMenuItemsArrange />
<MenuDivider />

View File

@ -0,0 +1,40 @@
import { MenuItem } from '@invoke-ai/ui-library';
import { createSelector } from '@reduxjs/toolkit';
import { useAppDispatch, useAppSelector } from 'app/store/storeHooks';
import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext';
import {
controlLayerWithTransparencyEffectToggled,
selectCanvasV2Slice,
} from 'features/controlLayers/store/canvasV2Slice';
import { selectControlLayerOrThrow } from 'features/controlLayers/store/controlLayersReducers';
import { memo, useCallback, useMemo } from 'react';
import { useTranslation } from 'react-i18next';
import { PiDropHalfBold } from 'react-icons/pi';
export const ControlLayerMenuItemsTransparencyEffect = memo(() => {
const { t } = useTranslation();
const dispatch = useAppDispatch();
const entityIdentifier = useEntityIdentifierContext();
const selectWithTransparencyEffect = useMemo(
() =>
createSelector(selectCanvasV2Slice, (canvasV2) => {
const entity = selectControlLayerOrThrow(canvasV2, entityIdentifier.id);
return entity.withTransparencyEffect;
}),
[entityIdentifier.id]
);
const withTransparencyEffect = useAppSelector(selectWithTransparencyEffect);
const onToggle = useCallback(() => {
dispatch(controlLayerWithTransparencyEffectToggled({ id: entityIdentifier.id }));
}, [dispatch, entityIdentifier]);
return (
<MenuItem onClick={onToggle} icon={<PiDropHalfBold />}>
{withTransparencyEffect
? t('controlLayers.disableTransparencyEffect')
: t('controlLayers.enableTransparencyEffect')}
</MenuItem>
);
});
ControlLayerMenuItemsTransparencyEffect.displayName = 'ControlLayerMenuItemsTransparencyEffect';

View File

@ -100,6 +100,12 @@ export class CanvasLayerAdapter {
if (this.isFirstRender || opacity !== this.state.opacity) {
this.renderer.updateOpacity(opacity);
}
if (state.type === 'control_layer' && this.state.type === 'control_layer') {
if (this.isFirstRender || state.withTransparencyEffect !== this.state.withTransparencyEffect) {
this.renderer.updateTransparencyEffect(state.withTransparencyEffect);
}
}
// this.transformer.syncInteractionState();
if (this.isFirstRender) {
@ -129,12 +135,6 @@ export class CanvasLayerAdapter {
}
};
updateOpacity = (arg?: { opacity: number }) => {
this.log.trace('Updating opacity');
const opacity = get(arg, 'opacity', this.state.opacity);
this.renderer.konva.objectGroup.opacity(opacity);
};
repr = () => {
return {
id: this.id,

View File

@ -7,6 +7,7 @@ import type { CanvasLayerAdapter } from 'features/controlLayers/konva/CanvasLaye
import type { CanvasManager } from 'features/controlLayers/konva/CanvasManager';
import type { CanvasMaskAdapter } from 'features/controlLayers/konva/CanvasMaskAdapter';
import { CanvasRectRenderer } from 'features/controlLayers/konva/CanvasRect';
import { LightnessToAlphaFilter } from 'features/controlLayers/konva/filters';
import { getPatternSVG } from 'features/controlLayers/konva/patterns/getPatternSVG';
import { getPrefixedId, konvaNodeToBlob, konvaNodeToImageData, previewBlob } from 'features/controlLayers/konva/util';
import type {
@ -203,6 +204,11 @@ export class CanvasObjectRenderer {
}
};
updateTransparencyEffect = (withTransparencyEffect: boolean) => {
const filters = withTransparencyEffect ? [LightnessToAlphaFilter] : [];
this.konva.objectGroup.filters(filters);
};
updateCompositingRectFill = (fill: Fill) => {
this.log.trace('Updating compositing rect fill');
assert(this.konva.compositing, 'Missing compositing rect');

View File

@ -584,6 +584,7 @@ export const {
controlLayerControlModeChanged,
controlLayerWeightChanged,
controlLayerBeginEndStepPctChanged,
controlLayerWithTransparencyEffectToggled,
// IP Adapters
ipaAdded,
ipaRecalled,

View File

@ -36,6 +36,7 @@ export const controlLayersReducers = {
name: null,
type: 'control_layer',
isEnabled: true,
withTransparencyEffect: true,
objects: [],
opacity: 1,
position: { x: 0, y: 0 },
@ -70,7 +71,7 @@ export const controlLayersReducers = {
// Convert the raster layer to control layer
const rasterLayerState: CanvasRasterLayerState = {
...omit(deepClone(layer), ['type', 'controlAdapter']),
...omit(deepClone(layer), ['type', 'controlAdapter', 'withTransparencyEffect']),
id: newId,
type: 'raster_layer',
};
@ -151,4 +152,12 @@ export const controlLayersReducers = {
}
layer.controlAdapter.beginEndStepPct = beginEndStepPct;
},
controlLayerWithTransparencyEffectToggled: (state, action: PayloadAction<{ id: string }>) => {
const { id } = action.payload;
const layer = selectControlLayer(state, id);
if (!layer) {
return;
}
layer.withTransparencyEffect = !layer.withTransparencyEffect;
},
} satisfies SliceCaseReducers<CanvasV2State>;

View File

@ -89,6 +89,7 @@ export const rasterLayersReducers = {
id: newId,
type: 'control_layer',
controlAdapter,
withTransparencyEffect: true,
};
// Remove the raster layer

View File

@ -559,14 +559,14 @@ const zCanvasRectState = z.object({
});
export type CanvasRectState = z.infer<typeof zCanvasRectState>;
const zFilter = z.enum(['LightnessToAlphaFilter']);
export type Filter = z.infer<typeof zFilter>;
const zLayerEffect = z.enum(['LightnessToAlphaFilter']);
export type LayerEffect = z.infer<typeof zLayerEffect>;
const zCanvasImageState = z.object({
id: zId,
type: z.literal('image'),
image: zImageWithDims,
filters: z.array(zFilter),
filters: z.array(zLayerEffect),
});
export type CanvasImageState = z.infer<typeof zCanvasImageState>;
@ -699,7 +699,7 @@ const zCanvasControlAdapterStateBase = z.object({
isEnabled: z.boolean(),
position: zCoordinate,
opacity: zOpacity,
filters: z.array(zFilter),
filters: z.array(zLayerEffect),
weight: z.number().gte(-1).lte(2),
imageObject: zCanvasImageState.nullable(),
processedImageObject: zCanvasImageState.nullable(),
@ -755,6 +755,7 @@ export type CanvasRasterLayerState = z.infer<typeof zCanvasRasterLayerState>;
export const zCanvasControlLayerState = zCanvasRasterLayerState.extend({
type: z.literal('control_layer'),
withTransparencyEffect: z.boolean(),
controlAdapter: z.discriminatedUnion('type', [zControlNetConfig, zT2IAdapterConfig]),
});
export type CanvasControlLayerState = z.infer<typeof zCanvasControlLayerState>;