diff --git a/lama_cleaner/app/package.json b/lama_cleaner/app/package.json index 024166b..5e7db27 100644 --- a/lama_cleaner/app/package.json +++ b/lama_cleaner/app/package.json @@ -14,10 +14,12 @@ "@testing-library/react": "^12.1.2", "@testing-library/user-event": "^13.5.0", "@types/jest": "^27.0.2", + "@types/lodash": "^4.14.182", "@types/node": "^16.11.1", "@types/react": "^17.0.30", "@types/react-dom": "^17.0.9", "cross-env": "7.x", + "lodash": "^4.17.21", "nanoid": "^4.0.0", "npm-run-all": "4.x", "react": "^17.0.2", diff --git a/lama_cleaner/app/src/adapters/inpainting.ts b/lama_cleaner/app/src/adapters/inpainting.ts index f7fd3ef..e82f855 100644 --- a/lama_cleaner/app/src/adapters/inpainting.ts +++ b/lama_cleaner/app/src/adapters/inpainting.ts @@ -15,16 +15,20 @@ export default async function inpaint( const mask = dataURItoBlob(maskBase64) fd.append('mask', mask) + const hdSettings = settings.hdSettings[settings.model] fd.append('ldmSteps', settings.ldmSteps.toString()) fd.append('ldmSampler', settings.ldmSampler.toString()) fd.append('zitsWireframe', settings.zitsWireframe.toString()) - fd.append('hdStrategy', settings.hdStrategy) - fd.append('hdStrategyCropMargin', settings.hdStrategyCropMargin.toString()) + fd.append('hdStrategy', hdSettings.hdStrategy) + fd.append('hdStrategyCropMargin', hdSettings.hdStrategyCropMargin.toString()) fd.append( 'hdStrategyCropTrigerSize', - settings.hdStrategyCropTrigerSize.toString() + hdSettings.hdStrategyCropTrigerSize.toString() + ) + fd.append( + 'hdStrategyResizeLimit', + hdSettings.hdStrategyResizeLimit.toString() ) - fd.append('hdStrategyResizeLimit', settings.hdStrategyResizeLimit.toString()) if (sizeLimit === undefined) { fd.append('sizeLimit', '1080') diff --git a/lama_cleaner/app/src/components/Settings/HDSettingBlock.tsx b/lama_cleaner/app/src/components/Settings/HDSettingBlock.tsx index 9c77f53..1d0e353 100644 --- a/lama_cleaner/app/src/components/Settings/HDSettingBlock.tsx +++ b/lama_cleaner/app/src/components/Settings/HDSettingBlock.tsx @@ -1,6 +1,6 @@ import React, { ReactNode } from 'react' import { useRecoilState } from 'recoil' -import { settingState } from '../../store/Atoms' +import { hdSettingsState, settingState } from '../../store/Atoms' import Selector from '../shared/Selector' import NumberInputSetting from './NumberInputSetting' import SettingBlock from './SettingBlock' @@ -17,33 +17,25 @@ export enum LDMSampler { } function HDSettingBlock() { - const [setting, setSettingState] = useRecoilState(settingState) + const [hdSettings, setHDSettings] = useRecoilState(hdSettingsState) const onStrategyChange = (value: HDStrategy) => { - setSettingState(old => { - return { ...old, hdStrategy: value } - }) + setHDSettings({ hdStrategy: value }) } const onResizeLimitChange = (value: string) => { const val = value.length === 0 ? 0 : parseInt(value, 10) - setSettingState(old => { - return { ...old, hdStrategyResizeLimit: val } - }) + setHDSettings({ hdStrategyResizeLimit: val }) } const onCropTriggerSizeChange = (value: string) => { const val = value.length === 0 ? 0 : parseInt(value, 10) - setSettingState(old => { - return { ...old, hdStrategyCropTrigerSize: val } - }) + setHDSettings({ hdStrategyCropTrigerSize: val }) } const onCropMarginChange = (value: string) => { const val = value.length === 0 ? 0 : parseInt(value, 10) - setSettingState(old => { - return { ...old, hdStrategyCropMargin: val } - }) + setHDSettings({ hdStrategyCropMargin: val }) } const renderOriginalOptionDesc = () => { @@ -73,7 +65,7 @@ function HDSettingBlock() { @@ -91,13 +83,13 @@ function HDSettingBlock() { @@ -106,7 +98,7 @@ function HDSettingBlock() { } const renderHDStrategyOptionDesc = (): ReactNode => { - switch (setting.hdStrategy) { + switch (hdSettings.hdStrategy) { case HDStrategy.ORIGINAL: return renderOriginalOptionDesc() case HDStrategy.CROP: @@ -125,7 +117,7 @@ function HDSettingBlock() { input={ onStrategyChange(val as HDStrategy)} /> diff --git a/lama_cleaner/app/src/components/Settings/ModelSettingBlock.tsx b/lama_cleaner/app/src/components/Settings/ModelSettingBlock.tsx index 79b0f49..8d12abe 100644 --- a/lama_cleaner/app/src/components/Settings/ModelSettingBlock.tsx +++ b/lama_cleaner/app/src/components/Settings/ModelSettingBlock.tsx @@ -1,6 +1,6 @@ import React, { ReactNode } from 'react' import { useRecoilState } from 'recoil' -import { settingState } from '../../store/Atoms' +import { AIModel, settingState } from '../../store/Atoms' import Selector from '../shared/Selector' import { Switch, SwitchThumb } from '../shared/Switch' import Tooltip from '../shared/Tooltip' @@ -8,12 +8,6 @@ import { LDMSampler } from './HDSettingBlock' import NumberInputSetting from './NumberInputSetting' import SettingBlock from './SettingBlock' -export enum AIModel { - LAMA = 'lama', - LDM = 'ldm', - ZITS = 'zits', -} - function ModelSettingBlock() { const [setting, setSettingState] = useRecoilState(settingState) diff --git a/lama_cleaner/app/src/components/Workspace.tsx b/lama_cleaner/app/src/components/Workspace.tsx index a579578..f8beba9 100644 --- a/lama_cleaner/app/src/components/Workspace.tsx +++ b/lama_cleaner/app/src/components/Workspace.tsx @@ -4,13 +4,12 @@ import Editor from './Editor/Editor' import ShortcutsModal from './Shortcuts/ShortcutsModal' import SettingModal from './Settings/SettingsModal' import Toast from './shared/Toast' -import { settingState, toastState } from '../store/Atoms' +import { AIModel, settingState, toastState } from '../store/Atoms' import { currentModel, modelDownloaded, switchModel, } from '../adapters/inpainting' -import { AIModel } from './Settings/ModelSettingBlock' interface WorkspaceProps { file: File diff --git a/lama_cleaner/app/src/store/Atoms.tsx b/lama_cleaner/app/src/store/Atoms.tsx index 7e8f374..db212b5 100644 --- a/lama_cleaner/app/src/store/Atoms.tsx +++ b/lama_cleaner/app/src/store/Atoms.tsx @@ -1,8 +1,14 @@ -import { atom } from 'recoil' +import { atom, selector } from 'recoil' +import _ from 'lodash' import { HDStrategy, LDMSampler } from '../components/Settings/HDSettingBlock' -import { AIModel } from '../components/Settings/ModelSettingBlock' import { ToastState } from '../components/shared/Toast' +export enum AIModel { + LAMA = 'lama', + LDM = 'ldm', + ZITS = 'zits', +} + export const fileState = atom({ key: 'fileState', default: undefined, @@ -30,18 +36,22 @@ export const shortcutsState = atom({ default: false, }) +export interface HDSettings { + hdStrategy: HDStrategy + hdStrategyResizeLimit: number + hdStrategyCropTrigerSize: number + hdStrategyCropMargin: number +} + +type ModelsHDSettings = { [key in AIModel]: HDSettings } + export interface Settings { show: boolean downloadMask: boolean graduallyInpainting: boolean runInpaintingManually: boolean model: AIModel - - // For LaMa - hdStrategy: HDStrategy - hdStrategyResizeLimit: number - hdStrategyCropTrigerSize: number - hdStrategyCropMargin: number + hdSettings: ModelsHDSettings // For LDM ldmSteps: number @@ -51,22 +61,39 @@ export interface Settings { zitsWireframe: boolean } -export const settingStateDefault = { +const defaultHDSettings: ModelsHDSettings = { + [AIModel.LAMA]: { + hdStrategy: HDStrategy.RESIZE, + hdStrategyResizeLimit: 2048, + hdStrategyCropTrigerSize: 2048, + hdStrategyCropMargin: 128, + }, + [AIModel.LDM]: { + hdStrategy: HDStrategy.CROP, + hdStrategyResizeLimit: 1080, + hdStrategyCropTrigerSize: 1080, + hdStrategyCropMargin: 128, + }, + [AIModel.ZITS]: { + hdStrategy: HDStrategy.CROP, + hdStrategyResizeLimit: 1024, + hdStrategyCropTrigerSize: 1024, + hdStrategyCropMargin: 128, + }, +} + +export const settingStateDefault: Settings = { show: false, downloadMask: false, graduallyInpainting: true, runInpaintingManually: false, model: AIModel.LAMA, + hdSettings: defaultHDSettings, - ldmSteps: 50, + ldmSteps: 25, ldmSampler: LDMSampler.plms, zitsWireframe: true, - - hdStrategy: HDStrategy.RESIZE, - hdStrategyResizeLimit: 2048, - hdStrategyCropTrigerSize: 2048, - hdStrategyCropMargin: 128, } const localStorageEffect = @@ -76,20 +103,44 @@ const localStorageEffect = if (savedValue != null) { const storageSettings = JSON.parse(savedValue) storageSettings.show = false - setSelf({ ...settingStateDefault, ...storageSettings }) + + const restored = _.merge( + _.cloneDeep(settingStateDefault), + storageSettings + ) + setSelf(restored) } - onSet((newValue: Settings, _: string, isReset: boolean) => + onSet((newValue: Settings, val: string, isReset: boolean) => isReset ? localStorage.removeItem(key) : localStorage.setItem(key, JSON.stringify(newValue)) ) } +const ROOT_STATE_KEY = 'settingsState2' // Each atom can reference an array of these atom effect functions which are called in priority order when the atom is initialized // https://recoiljs.org/docs/guides/atom-effects/#local-storage-persistence export const settingState = atom({ - key: 'settingsState', + key: ROOT_STATE_KEY, default: settingStateDefault, - effects: [localStorageEffect('settingsState')], + effects: [localStorageEffect(ROOT_STATE_KEY)], +}) + +export const hdSettingsState = selector({ + key: 'hdSettings', + get: ({ get }) => { + const settings = get(settingState) + return settings.hdSettings[settings.model] + }, + set: ({ get, set }, newValue: any) => { + const settings = get(settingState) + const hdSettings = settings.hdSettings[settings.model] + const newHDSettings = { ...hdSettings, ...newValue } + + set(settingState, { + ...settings, + hdSettings: { ...settings.hdSettings, [settings.model]: newHDSettings }, + }) + }, }) diff --git a/lama_cleaner/app/yarn.lock b/lama_cleaner/app/yarn.lock index 0bf8b8b..a3e70f6 100644 --- a/lama_cleaner/app/yarn.lock +++ b/lama_cleaner/app/yarn.lock @@ -2333,6 +2333,11 @@ resolved "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz" integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= +"@types/lodash@^4.14.182": + version "4.14.182" + resolved "https://registry.yarnpkg.com/@types/lodash/-/lodash-4.14.182.tgz#05301a4d5e62963227eaafe0ce04dd77c54ea5c2" + integrity sha512-/THyiqyQAP9AfARo4pF+aCGcyiQ94tX/Is2I7HofNRqoYLgN1PBoOWu2/zTA5zMxzP5EFutMtWtGAFRKUe961Q== + "@types/minimatch@*": version "3.0.5" resolved "https://registry.npmjs.org/@types/minimatch/-/minimatch-3.0.5.tgz" @@ -7780,11 +7785,16 @@ lodash.uniq@^4.5.0: resolved "https://registry.npmjs.org/lodash.uniq/-/lodash.uniq-4.5.0.tgz" integrity sha1-0CJTc662Uq3BvILklFM5qEJ1R3M= -"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.21, lodash@^4.17.5, lodash@^4.7.0: +"lodash@>=3.5 <5", lodash@^4.17.11, lodash@^4.17.14, lodash@^4.17.15, lodash@^4.17.19, lodash@^4.17.20, lodash@^4.17.5, lodash@^4.7.0: version "4.17.21" resolved "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== +lodash@^4.17.21: + version "4.17.21" + resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" + integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== + loglevel@^1.6.8: version "1.7.1" resolved "https://registry.npmjs.org/loglevel/-/loglevel-1.7.1.tgz"