diff --git a/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityPreviewImage.tsx b/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityPreviewImage.tsx index 161eed1fda..142f2cdacc 100644 --- a/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityPreviewImage.tsx +++ b/invokeai/frontend/web/src/features/controlLayers/components/common/CanvasEntityPreviewImage.tsx @@ -1,13 +1,36 @@ import { Box, chakra, Flex } from '@invoke-ai/ui-library'; import { useStore } from '@nanostores/react'; +import { createSelector } from '@reduxjs/toolkit'; +import { rgbColorToString } from 'common/util/colorCodeTransformers'; import { useEntityAdapter } from 'features/controlLayers/contexts/EntityAdapterContext'; +import { useEntityIdentifierContext } from 'features/controlLayers/contexts/EntityIdentifierContext'; import { TRANSPARENCY_CHECKER_PATTERN } from 'features/controlLayers/konva/constants'; -import { memo, useEffect, useRef } from 'react'; +import { selectCanvasV2Slice, selectEntity } from 'features/controlLayers/store/canvasV2Slice'; +import { memo, useEffect, useMemo, useRef } from 'react'; +import { useSelector } from 'react-redux'; const ChakraCanvas = chakra.canvas; +const PADDING = 4; + export const CanvasEntityPreviewImage = memo(() => { + const entityIdentifier = useEntityIdentifierContext(); const adapter = useEntityAdapter(); + const selectMaskColor = useMemo( + () => + createSelector(selectCanvasV2Slice, (state) => { + const entity = selectEntity(state, entityIdentifier); + if (!entity) { + return null; + } + if (entity.type === 'inpaint_mask' || entity.type === 'regional_guidance') { + return rgbColorToString(entity.fill.color); + } + return null; + }), + [entityIdentifier] + ); + const maskColor = useSelector(selectMaskColor); const containerRef = useRef(null); const canvasRef = useRef(null); const cache = useStore(adapter.renderer.$canvasCache); @@ -26,8 +49,25 @@ export const CanvasEntityPreviewImage = memo(() => { canvasRef.current.width = rect.width; canvasRef.current.height = rect.height; - ctx.drawImage(canvas, rect.x, rect.y, rect.width, rect.height, 0, 0, rect.width, rect.height); - }, [adapter.transformer, adapter.transformer.nodeRect, adapter.transformer.pixelRect, cache]); + const scale = containerRef.current.offsetWidth / rect.width; + + const sx = rect.x; + const sy = rect.y; + const sWidth = rect.width; + const sHeight = rect.height; + const dx = PADDING / scale; + const dy = PADDING / scale; + const dWidth = rect.width - (PADDING * 2) / scale; + const dHeight = rect.height - (PADDING * 2) / scale; + + ctx.drawImage(canvas, sx, sy, sWidth, sHeight, dx, dy, dWidth, dHeight); + + if (maskColor) { + ctx.fillStyle = maskColor; + ctx.globalCompositeOperation = 'source-in'; + ctx.fillRect(0, 0, rect.width, rect.height); + } + }, [adapter.transformer, adapter.transformer.nodeRect, adapter.transformer.pixelRect, cache, maskColor]); return (