This commit is contained in:
Qing 2023-11-17 08:56:33 +08:00
parent ef1179a858
commit 53aea791c5
9 changed files with 1219 additions and 584 deletions

View File

@ -84,7 +84,6 @@
"socket.io-client": "^4.5.4", "socket.io-client": "^4.5.4",
"source-map-loader": "^3.0.0", "source-map-loader": "^3.0.0",
"style-loader": "^3.3.1", "style-loader": "^3.3.1",
"tailwindcss": "^3.0.2",
"terser-webpack-plugin": "^5.2.5", "terser-webpack-plugin": "^5.2.5",
"typescript": "4.x", "typescript": "4.x",
"webpack": "^5.64.4", "webpack": "^5.64.4",

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,166 @@
@use 'sass:math';
$drag-handle-shortside: 12px;
$drag-handle-longside: 40px;
$drag-bar-size: 12px;
$half-handle-shortside: math.div($drag-handle-shortside, 2);
$half-handle-longside: math.div($drag-handle-longside, 2);
$half-drag-bar-size: math.div($drag-bar-size, 2);
.extender-border {
outline-color: var(--yellow-accent);
outline-style: dashed;
}
.info-bar {
position: absolute;
pointer-events: auto;
font-size: 1rem;
padding: 0.2rem 0.8rem;
display: flex;
align-items: center;
justify-content: center;
gap: 12px;
color: var(--text-color);
background-color: var(--page-bg);
border-radius: 9999px;
border: var(--editor-toolkit-panel-border);
box-shadow: 0 0 0 1px #0000001a, 0 3px 16px #00000014, 0 2px 6px 1px #00000017;
&:hover {
cursor: move;
}
}
.extender-wrapper {
position: absolute;
height: 100%;
width: 100%;
z-index: 2;
pointer-events: none;
}
.extender {
position: relative;
top: 0;
bottom: 0;
left: 0;
right: 0;
z-index: 2;
pointer-events: none;
// display: flex;
// flex-direction: column;
// align-items: center;
box-shadow: 0 0 0 9999px rgba(0, 0, 0, 0.5);
}
.drag-bar {
position: absolute;
pointer-events: auto;
// display: none;
&.ord-top {
top: 0;
left: 0;
width: 100%;
height: $drag-bar-size;
margin-top: -$half-drag-bar-size;
cursor: ns-resize;
}
&.ord-right {
right: 0;
top: 0;
width: $drag-bar-size;
height: 100%;
margin-right: -$half-drag-bar-size;
cursor: ew-resize;
}
&.ord-bottom {
bottom: 0;
left: 0;
width: 100%;
height: $drag-bar-size;
margin-bottom: -$half-drag-bar-size;
cursor: ns-resize;
}
&.ord-left {
top: 0;
left: 0;
width: $drag-bar-size;
height: 100%;
margin-left: -$half-drag-bar-size;
cursor: ew-resize;
}
}
.drag-handle {
width: $drag-handle-shortside;
height: $drag-handle-shortside;
z-index: 4;
position: absolute;
display: block;
content: '';
border: 2px solid var(--yellow-accent);
background-color: var(--yellow-accent-light);
pointer-events: auto;
&:hover {
background-color: var(--yellow-accent);
}
&.ord-topleft {
cursor: nw-resize;
top: (-$half-handle-shortside)-1px;
left: (-$half-handle-shortside)-1px;
}
&.ord-topright {
cursor: ne-resize;
top: -($half-handle-shortside)-1px;
right: -($half-handle-shortside)-1px;
}
&.ord-bottomright {
cursor: se-resize;
bottom: -($half-handle-shortside)-1px;
right: -($half-handle-shortside)-1px;
}
&.ord-bottomleft {
cursor: sw-resize;
bottom: -($half-handle-shortside)-1px;
left: -($half-handle-shortside)-1px;
}
&.ord-top,
&.ord-bottom {
left: calc(50% - $half-handle-shortside);
cursor: ns-resize;
}
&.ord-top {
top: (-$half-handle-shortside)-1px;
}
&.ord-bottom {
bottom: -($half-handle-shortside)-1px;
}
&.ord-left,
&.ord-right {
top: calc(50% - $half-handle-shortside);
cursor: ew-resize;
}
&.ord-left {
left: (-$half-handle-shortside)-1px;
}
&.ord-right {
right: -($half-handle-shortside)-1px;
}
}

View File

@ -0,0 +1,408 @@
import React, { useEffect, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil'
import {
extenderX,
extenderY,
extenderHeight,
extenderWidth,
isInpaintingState,
} from '../../store/Atoms'
const DOC_MOVE_OPTS = { capture: true, passive: false }
const DRAG_HANDLE_BORDER = 2
const DRAG_HANDLE_SHORT = 12
const DRAG_HANDLE_LONG = 40
interface EVData {
initX: number
initY: number
initHeight: number
initWidth: number
startResizeX: number
startResizeY: number
ord: string // top/right/bottom/left
}
interface Props {
maxHeight: number
maxWidth: number
scale: number
minHeight: number
minWidth: number
show: boolean
}
const clamp = (
newPos: number,
newLength: number,
oldPos: number,
oldLength: number,
minLength: number,
maxLength: number
) => {
if (newPos !== oldPos && newLength === oldLength) {
if (newPos < 0) {
return [0, oldLength]
}
if (newPos + newLength > maxLength) {
return [maxLength - oldLength, oldLength]
}
} else {
if (newLength < minLength) {
if (newPos === oldPos) {
return [newPos, minLength]
}
return [newPos + newLength - minLength, minLength]
}
if (newPos < 0) {
return [0, newPos + newLength]
}
if (newPos + newLength > maxLength) {
return [newPos, maxLength - newPos]
}
}
return [newPos, newLength]
}
const Extender = (props: Props) => {
const { minHeight, minWidth, maxHeight, maxWidth, scale, show } = props
const [x, setX] = useRecoilState(extenderX)
const [y, setY] = useRecoilState(extenderY)
const [height, setHeight] = useRecoilState(extenderHeight)
const [width, setWidth] = useRecoilState(extenderWidth)
const isInpainting = useRecoilValue(isInpaintingState)
const [isResizing, setIsResizing] = useState(false)
const [isMoving, setIsMoving] = useState(false)
useEffect(() => {
setX(Math.round((maxWidth - 512) / 2))
setY(Math.round((maxHeight - 512) / 2))
}, [maxHeight, maxWidth])
const [evData, setEVData] = useState<EVData>({
initX: 0,
initY: 0,
initHeight: 0,
initWidth: 0,
startResizeX: 0,
startResizeY: 0,
ord: 'top',
})
const onDragFocus = () => {
console.log('focus')
}
const clampLeftRight = (newX: number, newWidth: number) => {
return clamp(newX, newWidth, x, width, minWidth, maxWidth)
}
const clampTopBottom = (newY: number, newHeight: number) => {
return clamp(newY, newHeight, y, height, minHeight, maxHeight)
}
const onPointerMove = (e: PointerEvent) => {
if (isInpainting) {
return
}
const curX = e.clientX
const curY = e.clientY
const offsetY = Math.round((curY - evData.startResizeY) / scale)
const offsetX = Math.round((curX - evData.startResizeX) / scale)
const moveTop = () => {
const newHeight = evData.initHeight - offsetY
const newY = evData.initY + offsetY
const [clampedY, clampedHeight] = clampTopBottom(newY, newHeight)
setHeight(clampedHeight)
setY(clampedY)
}
const moveBottom = () => {
const newHeight = evData.initHeight + offsetY
const [clampedY, clampedHeight] = clampTopBottom(evData.initY, newHeight)
setHeight(clampedHeight)
setY(clampedY)
}
const moveLeft = () => {
const newWidth = evData.initWidth - offsetX
const newX = evData.initX + offsetX
const [clampedX, clampedWidth] = clampLeftRight(newX, newWidth)
setWidth(clampedWidth)
setX(clampedX)
}
const moveRight = () => {
const newWidth = evData.initWidth + offsetX
const [clampedX, clampedWidth] = clampLeftRight(evData.initX, newWidth)
setWidth(clampedWidth)
setX(clampedX)
}
if (isResizing) {
switch (evData.ord) {
case 'topleft': {
moveTop()
moveLeft()
break
}
case 'topright': {
moveTop()
moveRight()
break
}
case 'bottomleft': {
moveBottom()
moveLeft()
break
}
case 'bottomright': {
moveBottom()
moveRight()
break
}
case 'top': {
moveTop()
break
}
case 'right': {
moveRight()
break
}
case 'bottom': {
moveBottom()
break
}
case 'left': {
moveLeft()
break
}
default:
break
}
}
if (isMoving) {
const newX = evData.initX + offsetX
const newY = evData.initY + offsetY
const [clampedX, clampedWidth] = clampLeftRight(newX, evData.initWidth)
const [clampedY, clampedHeight] = clampTopBottom(newY, evData.initHeight)
setWidth(clampedWidth)
setHeight(clampedHeight)
setX(clampedX)
setY(clampedY)
}
}
const onPointerDone = (e: PointerEvent) => {
if (isResizing) {
setIsResizing(false)
}
if (isMoving) {
setIsMoving(false)
}
}
useEffect(() => {
if (isResizing || isMoving) {
document.addEventListener('pointermove', onPointerMove, DOC_MOVE_OPTS)
document.addEventListener('pointerup', onPointerDone, DOC_MOVE_OPTS)
document.addEventListener('pointercancel', onPointerDone, DOC_MOVE_OPTS)
return () => {
document.removeEventListener(
'pointermove',
onPointerMove,
DOC_MOVE_OPTS
)
document.removeEventListener('pointerup', onPointerDone, DOC_MOVE_OPTS)
document.removeEventListener(
'pointercancel',
onPointerDone,
DOC_MOVE_OPTS
)
}
}
}, [isResizing, isMoving, width, height, evData])
const onCropPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
const { ord } = (e.target as HTMLElement).dataset
if (ord) {
setIsResizing(true)
setEVData({
initX: x,
initY: y,
initHeight: height,
initWidth: width,
startResizeX: e.clientX,
startResizeY: e.clientY,
ord,
})
}
}
const createCropSelection = () => {
return (
<div
className="drag-elements"
onFocus={onDragFocus}
onPointerDown={onCropPointerDown}
>
<div
className="drag-bar ord-top"
data-ord="top"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-bar ord-right"
data-ord="right"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-bar ord-bottom"
data-ord="bottom"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-bar ord-left"
data-ord="left"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-handle ord-topleft"
data-ord="topleft"
aria-label="topleft"
tabIndex={0}
role="button"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-handle ord-topright"
data-ord="topright"
aria-label="topright"
tabIndex={0}
role="button"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-handle ord-bottomleft"
data-ord="bottomleft"
aria-label="bottomleft"
tabIndex={0}
role="button"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-handle ord-bottomright"
data-ord="bottomright"
aria-label="bottomright"
tabIndex={0}
role="button"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-handle ord-top"
data-ord="top"
aria-label="top"
tabIndex={0}
role="button"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-handle ord-right"
data-ord="right"
aria-label="right"
tabIndex={0}
role="button"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-handle ord-bottom"
data-ord="bottom"
aria-label="bottom"
tabIndex={0}
role="button"
style={{ transform: `scale(${1 / scale})` }}
/>
<div
className="drag-handle ord-left"
data-ord="left"
aria-label="left"
tabIndex={0}
role="button"
style={{ transform: `scale(${1 / scale})` }}
/>
</div>
)
}
const onInfoBarPointerDown = (e: React.PointerEvent<HTMLDivElement>) => {
setIsMoving(true)
setEVData({
initX: x,
initY: y,
initHeight: height,
initWidth: width,
startResizeX: e.clientX,
startResizeY: e.clientY,
ord: '',
})
}
const createInfoBar = () => {
return (
<div
className="info-bar"
onPointerDown={onInfoBarPointerDown}
style={{
transform: `scale(${1 / scale})`,
top: `${10 / scale}px`,
left: `${10 / scale}px`,
}}
>
<div className="crop-size">
{width} x {height}
</div>
</div>
)
}
const createBorder = () => {
return (
<div
className="extender-border"
style={{
height,
width,
outlineWidth: `${DRAG_HANDLE_BORDER / scale}px`,
}}
/>
)
}
return (
<div
className="extender-wrapper"
style={{ visibility: show ? 'visible' : 'hidden' }}
>
<div className="extender" style={{ height, width, left: x, top: y }}>
{createBorder()}
{createInfoBar()}
{createCropSelection()}
</div>
</div>
)
}
export default Extender

View File

@ -1,5 +1,6 @@
import React, { ReactNode, useEffect, useState } from 'react' import React, { ReactNode, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import * as Tabs from '@radix-ui/react-tabs'
import { import {
AIModel, AIModel,
CV2Flag, CV2Flag,
@ -9,13 +10,21 @@ import {
import Selector from '../shared/Selector' import Selector from '../shared/Selector'
import { Switch, SwitchThumb } from '../shared/Switch' import { Switch, SwitchThumb } from '../shared/Switch'
import Tooltip from '../shared/Tooltip' import Tooltip from '../shared/Tooltip'
import { LDMSampler } from './HDSettingBlock' import HDSettingBlock, { LDMSampler } from './HDSettingBlock'
import NumberInputSetting from './NumberInputSetting' import NumberInputSetting from './NumberInputSetting'
import SettingBlock from './SettingBlock' import SettingBlock from './SettingBlock'
import Flex from '../shared/Layout'
import ManualRunInpaintingSettingBlock from './ManualRunInpaintingSettingBlock'
const ERASE_TAB = 'erase_tab'
const INPAINTING_DIFFUSION_TAB = 'inpainting_diffusion_tab'
const DIFFUSION_TAB = 'diffusion_tab'
const OTHER_TAB = 'other_tab'
function ModelSettingBlock() { function ModelSettingBlock() {
const [setting, setSettingState] = useRecoilState(settingState) const [setting, setSettingState] = useRecoilState(settingState)
const isDisableModelSwitch = useRecoilValue(isDisableModelSwitchState) const isDisableModelSwitch = useRecoilValue(isDisableModelSwitchState)
const [tab, setTab] = useState(ERASE_TAB)
const onModelChange = (value: AIModel) => { const onModelChange = (value: AIModel) => {
setSettingState(old => { setSettingState(old => {
@ -190,112 +199,63 @@ function ModelSettingBlock() {
} }
} }
const renderPaperCodeBadge = (): ReactNode => {
switch (setting.model) {
case AIModel.LAMA:
return renderModelDesc(
'Resolution-robust Large Mask Inpainting with Fourier Convolutions',
'https://arxiv.org/abs/2109.07161',
'https://github.com/saic-mdal/lama'
)
case AIModel.LDM:
return renderModelDesc(
'High-Resolution Image Synthesis with Latent Diffusion Models',
'https://arxiv.org/abs/2112.10752',
'https://github.com/CompVis/latent-diffusion'
)
case AIModel.ZITS:
return renderModelDesc(
'Incremental Transformer Structure Enhanced Image Inpainting with Masking Positional Encoding',
'https://arxiv.org/abs/2203.00867',
'https://github.com/DQiaole/ZITS_inpainting'
)
case AIModel.MAT:
return renderModelDesc(
'Mask-Aware Transformer for Large Hole Image Inpainting',
'https://arxiv.org/abs/2203.15270',
'https://github.com/fenglinglwb/MAT'
)
case AIModel.FCF:
return renderModelDesc(
'Keys to Better Image Inpainting: Structure and Texture Go Hand in Hand',
'https://arxiv.org/abs/2208.03382',
'https://github.com/SHI-Labs/FcF-Inpainting'
)
case AIModel.SD15:
return renderModelDesc(
'Stable Diffusion 1.5',
'https://ommer-lab.com/research/latent-diffusion-models/',
'https://github.com/CompVis/stable-diffusion'
)
case AIModel.ANYTHING4:
return renderModelDesc(
'andite/anything-v4.0',
'https://huggingface.co/andite/anything-v4.0',
'https://huggingface.co/andite/anything-v4.0'
)
case AIModel.REALISTIC_VISION_1_4:
return renderModelDesc(
'SG161222/Realistic_Vision_V1.4',
'https://huggingface.co/SG161222/Realistic_Vision_V1.4',
'https://huggingface.co/SG161222/Realistic_Vision_V1.4'
)
case AIModel.SD2:
return renderModelDesc(
'Stable Diffusion 2',
'https://ommer-lab.com/research/latent-diffusion-models/',
'https://github.com/Stability-AI/stablediffusion'
)
case AIModel.Mange:
return renderModelDesc(
'Manga Inpainting',
'https://www.cse.cuhk.edu.hk/~ttwong/papers/mangainpaint/mangainpaint.html',
'https://github.com/msxie92/MangaInpainting'
)
case AIModel.CV2:
return renderModelDesc(
'OpenCV Image Inpainting',
'https://docs.opencv.org/4.6.0/df/d3d/tutorial_py_inpainting.html',
'https://docs.opencv.org/4.6.0/df/d3d/tutorial_py_inpainting.html'
)
case AIModel.PAINT_BY_EXAMPLE:
return renderModelDesc(
'Paint by Example',
'https://arxiv.org/abs/2211.13227',
'https://github.com/Fantasy-Studio/Paint-by-Example'
)
case AIModel.PIX2PIX:
return renderModelDesc(
'InstructPix2Pix',
'https://arxiv.org/abs/2211.09800',
'https://github.com/timothybrooks/instruct-pix2pix'
)
case AIModel.KANDINSKY21:
return renderModelDesc(
'Kandinsky 2.1',
'https://huggingface.co/kandinsky-community/kandinsky-2-1-inpaint',
'https://huggingface.co/kandinsky-community/kandinsky-2-1-inpaint'
)
default:
return <></>
}
}
return ( return (
<SettingBlock // <SettingBlock
className="model-setting-block" // className="model-setting-block"
title="Model" // title="Model"
titleSuffix={renderPaperCodeBadge()} // input={
input={ // <Selector
<Selector // value={setting.model as string}
value={setting.model as string} // options={Object.values(AIModel)}
options={Object.values(AIModel)} // onChange={val => onModelChange(val as AIModel)}
onChange={val => onModelChange(val as AIModel)} // disabled={isDisableModelSwitch}
disabled={isDisableModelSwitch} // />
/> // }
} // optionDesc={renderOptionDesc()}
optionDesc={renderOptionDesc()} // />
/> <Flex
style={{
justifyContent: 'start',
flexDirection: 'column',
gap: 10,
alignItems: 'start',
}}
>
<Flex style={{ justifyContent: 'space-between', width: '100%' }}>
<div>Current Model</div>
<div>{setting.model}</div>
</Flex>
<Tabs.Root
className="TabsRoot"
defaultValue={ERASE_TAB}
onValueChange={val => setTab(val)}
>
<Tabs.List className="TabsList" aria-label="Object remove model">
<Tabs.Trigger className="TabsTrigger" value={ERASE_TAB}>
Erase
</Tabs.Trigger>
<Tabs.Trigger
className="TabsTrigger"
value={INPAINTING_DIFFUSION_TAB}
>
Inpainting Diffusion
</Tabs.Trigger>
<Tabs.Trigger className="TabsTrigger" value={DIFFUSION_TAB}>
Diffusion
</Tabs.Trigger>
<Tabs.Trigger className="TabsTrigger" value={OTHER_TAB}>
Other
</Tabs.Trigger>
</Tabs.List>
<Tabs.Content value={ERASE_TAB}>
<ManualRunInpaintingSettingBlock />
<HDSettingBlock />
</Tabs.Content>
<Tabs.Content value={INPAINTING_DIFFUSION_TAB}>123</Tabs.Content>
<Tabs.Content value={DIFFUSION_TAB}>123</Tabs.Content>
<Tabs.Content value={OTHER_TAB}>123</Tabs.Content>
</Tabs.Root>
</Flex>
) )
} }

View File

@ -28,7 +28,6 @@ interface SettingModalProps {
export default function SettingModal(props: SettingModalProps) { export default function SettingModal(props: SettingModalProps) {
const { onClose } = props const { onClose } = props
const [setting, setSettingState] = useRecoilState(settingState) const [setting, setSettingState] = useRecoilState(settingState)
const isSD = useRecoilValue(isSDState)
const isDiffusionModels = useRecoilValue(isDiffusionModelsState) const isDiffusionModels = useRecoilValue(isDiffusionModelsState)
const handleOnClose = () => { const handleOnClose = () => {
@ -57,9 +56,8 @@ export default function SettingModal(props: SettingModalProps) {
show={setting.show} show={setting.show}
> >
<DownloadMaskSettingBlock /> <DownloadMaskSettingBlock />
{isDiffusionModels ? <></> : <ManualRunInpaintingSettingBlock />} <ManualRunInpaintingSettingBlock />
<ModelSettingBlock /> <ModelSettingBlock />
{isDiffusionModels ? <></> : <HDSettingBlock />}
</Modal> </Modal>
) )
} }

View File

@ -85,7 +85,7 @@
} }
.resize-title-tile { .resize-title-tile {
width: 86px; width: 60px;
font-size: 0.5rem; font-size: 0.5rem;
color: var(--text-color-gray); color: var(--text-color-gray);
} }

View File

@ -1,6 +1,7 @@
import React, { FormEvent } from 'react' import React, { FormEvent, useState } from 'react'
import { useRecoilState, useRecoilValue } from 'recoil' import { useRecoilState, useRecoilValue } from 'recoil'
import * as PopoverPrimitive from '@radix-ui/react-popover' import * as PopoverPrimitive from '@radix-ui/react-popover'
import * as Tabs from '@radix-ui/react-tabs'
import { useToggle } from 'react-use' import { useToggle } from 'react-use'
import { import {
ControlNetMethod, ControlNetMethod,
@ -10,6 +11,8 @@ import {
propmtState, propmtState,
SDSampler, SDSampler,
settingState, settingState,
SIDE_PANEL_TAB,
SIDE_PANEL_TAB_TYPE,
} from '../../store/Atoms' } from '../../store/Atoms'
import NumberInputSetting from '../Settings/NumberInputSetting' import NumberInputSetting from '../Settings/NumberInputSetting'
import SettingBlock from '../Settings/SettingBlock' import SettingBlock from '../Settings/SettingBlock'
@ -23,6 +26,7 @@ const INPUT_WIDTH = 30
const SidePanel = () => { const SidePanel = () => {
const [open, toggleOpen] = useToggle(true) const [open, toggleOpen] = useToggle(true)
const [tab, setTab] = useState<SIDE_PANEL_TAB_TYPE>(SIDE_PANEL_TAB.inpainting)
const [setting, setSettingState] = useRecoilState(settingState) const [setting, setSettingState] = useRecoilState(settingState)
const [negativePrompt, setNegativePrompt] = const [negativePrompt, setNegativePrompt] =
useRecoilState(negativePropmtState) useRecoilState(negativePropmtState)
@ -95,10 +99,38 @@ const SidePanel = () => {
> >
Config Config
</PopoverPrimitive.Trigger> </PopoverPrimitive.Trigger>
<PopoverPrimitive.Portal> <PopoverPrimitive.Portal>
<PopoverPrimitive.Content className="side-panel-content"> <PopoverPrimitive.Content className="side-panel-content">
{isControlNet && renderConterNetSetting()} <Tabs.Root
className="TabsRoot"
style={{ alignSelf: 'center' }}
defaultValue={tab}
onValueChange={val => setTab(val as SIDE_PANEL_TAB_TYPE)}
>
<Tabs.List className="TabsList">
<Tabs.Trigger
className="TabsTrigger"
value={SIDE_PANEL_TAB.inpainting}
>
In Painting
</Tabs.Trigger>
<Tabs.Trigger
className="TabsTrigger"
value={SIDE_PANEL_TAB.outpainting}
>
Out Painting
</Tabs.Trigger>
</Tabs.List>
</Tabs.Root>
{isControlNet && tab === SIDE_PANEL_TAB.inpainting ? (
renderConterNetSetting()
) : (
<></>
)}
{tab === SIDE_PANEL_TAB.inpainting ? (
<SettingBlock <SettingBlock
title="Croper" title="Croper"
input={ input={
@ -114,8 +146,11 @@ const SidePanel = () => {
</Switch> </Switch>
} }
/> />
) : (
<></>
)}
<ImageResizeScale /> {tab === SIDE_PANEL_TAB.inpainting ? <ImageResizeScale /> : <></>}
{/* {/*
<NumberInputSetting <NumberInputSetting
@ -158,6 +193,7 @@ const SidePanel = () => {
}} }}
/> />
{tab === SIDE_PANEL_TAB.inpainting ? (
<NumberInputSetting <NumberInputSetting
title="Mask Blur" title="Mask Blur"
width={INPUT_WIDTH} width={INPUT_WIDTH}
@ -170,7 +206,11 @@ const SidePanel = () => {
}) })
}} }}
/> />
) : (
<></>
)}
{tab === SIDE_PANEL_TAB.outpainting ? (
<SettingBlock <SettingBlock
title="Match Histograms" title="Match Histograms"
desc="Match the inpainting result histogram to the source image histogram, will improves the inpainting quality for some images." desc="Match the inpainting result histogram to the source image histogram, will improves the inpainting quality for some images."
@ -187,6 +227,9 @@ const SidePanel = () => {
</Switch> </Switch>
} }
/> />
) : (
<></>
)}
<SettingBlock <SettingBlock
className="sub-setting-block" className="sub-setting-block"

View File

@ -3,6 +3,13 @@ import _ from 'lodash'
import { HDStrategy, LDMSampler } from '../components/Settings/HDSettingBlock' import { HDStrategy, LDMSampler } from '../components/Settings/HDSettingBlock'
import { ToastState } from '../components/shared/Toast' import { ToastState } from '../components/shared/Toast'
function strEnum<T extends string>(o: Array<T>): { [K in T]: K } {
return o.reduce((res, key) => {
res[key] = key
return res
}, Object.create(null))
}
export enum AIModel { export enum AIModel {
LAMA = 'lama', LAMA = 'lama',
LDM = 'ldm', LDM = 'ldm',
@ -17,7 +24,7 @@ export enum AIModel {
Mange = 'manga', Mange = 'manga',
PAINT_BY_EXAMPLE = 'paint_by_example', PAINT_BY_EXAMPLE = 'paint_by_example',
PIX2PIX = 'instruct_pix2pix', PIX2PIX = 'instruct_pix2pix',
KANDINSKY21 = 'kandinsky2.1', KANDINSKY22 = 'kandinsky2.2',
} }
export enum ControlNetMethod { export enum ControlNetMethod {
@ -351,6 +358,20 @@ export const croperState = atom<Rect>({
}, },
}) })
export const SIDE_PANEL_TAB = strEnum(['inpainting', 'outpainting'])
export type SIDE_PANEL_TAB_TYPE = keyof typeof SIDE_PANEL_TAB
export interface SidePanelState {
tab: SIDE_PANEL_TAB_TYPE
}
export const sidePanelTabState = atom<SidePanelState>({
key: 'sidePanelTabState',
default: {
tab: SIDE_PANEL_TAB.inpainting,
},
})
export const croperX = selector({ export const croperX = selector({
key: 'croperX', key: 'croperX',
get: ({ get }) => get(croperState).x, get: ({ get }) => get(croperState).x,
@ -387,6 +408,52 @@ export const croperWidth = selector({
}, },
}) })
export const extenderState = atom<Rect>({
key: 'extenderState',
default: {
x: 0,
y: 0,
width: 512,
height: 512,
},
})
export const extenderX = selector({
key: 'extenderX',
get: ({ get }) => get(extenderState).x,
set: ({ get, set }, newValue: any) => {
const rect = get(extenderState)
set(extenderState, { ...rect, x: newValue })
},
})
export const extenderY = selector({
key: 'extenderY',
get: ({ get }) => get(extenderState).y,
set: ({ get, set }, newValue: any) => {
const rect = get(extenderState)
set(extenderState, { ...rect, y: newValue })
},
})
export const extenderHeight = selector({
key: 'extenderHeight',
get: ({ get }) => get(extenderState).height,
set: ({ get, set }, newValue: any) => {
const rect = get(extenderState)
set(extenderState, { ...rect, height: newValue })
},
})
export const extenderWidth = selector({
key: 'extenderWidth',
get: ({ get }) => get(extenderState).width,
set: ({ get, set }, newValue: any) => {
const rect = get(extenderState)
set(extenderState, { ...rect, width: newValue })
},
})
interface ToastAtomState { interface ToastAtomState {
open: boolean open: boolean
desc: string desc: string
@ -567,7 +634,7 @@ const defaultHDSettings: ModelsHDSettings = {
hdStrategyCropMargin: 128, hdStrategyCropMargin: 128,
enabled: true, enabled: true,
}, },
[AIModel.KANDINSKY21]: { [AIModel.KANDINSKY22]: {
hdStrategy: HDStrategy.ORIGINAL, hdStrategy: HDStrategy.ORIGINAL,
hdStrategyResizeLimit: 768, hdStrategyResizeLimit: 768,
hdStrategyCropTrigerSize: 512, hdStrategyCropTrigerSize: 512,
@ -728,7 +795,7 @@ export const isSDState = selector({
settings.model === AIModel.SD2 || settings.model === AIModel.SD2 ||
settings.model === AIModel.ANYTHING4 || settings.model === AIModel.ANYTHING4 ||
settings.model === AIModel.REALISTIC_VISION_1_4 || settings.model === AIModel.REALISTIC_VISION_1_4 ||
settings.model === AIModel.KANDINSKY21 settings.model === AIModel.KANDINSKY22
) )
}, },
}) })