Merge branch '0.14.0-forceUpdate'
This commit is contained in:
commit
0f70ab58a7
@ -1,17 +1,17 @@
|
||||
{
|
||||
"files": {
|
||||
"main.css": "/static/css/main.bdd774f1.chunk.css",
|
||||
"main.js": "/static/js/main.9f4ed6dc.chunk.js",
|
||||
"main.css": "/static/css/main.4c6c667e.chunk.css",
|
||||
"main.js": "/static/js/main.6b34bb53.chunk.js",
|
||||
"runtime-main.js": "/static/js/runtime-main.5e86ac81.js",
|
||||
"static/js/2.1b1d3019.chunk.js": "/static/js/2.1b1d3019.chunk.js",
|
||||
"static/js/2.918f0adb.chunk.js": "/static/js/2.918f0adb.chunk.js",
|
||||
"index.html": "/index.html",
|
||||
"static/js/2.1b1d3019.chunk.js.LICENSE.txt": "/static/js/2.1b1d3019.chunk.js.LICENSE.txt",
|
||||
"static/js/2.918f0adb.chunk.js.LICENSE.txt": "/static/js/2.918f0adb.chunk.js.LICENSE.txt",
|
||||
"static/media/_index.scss": "/static/media/WorkSans-SemiBold.1e98db4e.ttf"
|
||||
},
|
||||
"entrypoints": [
|
||||
"static/js/runtime-main.5e86ac81.js",
|
||||
"static/js/2.1b1d3019.chunk.js",
|
||||
"static/css/main.bdd774f1.chunk.css",
|
||||
"static/js/main.9f4ed6dc.chunk.js"
|
||||
"static/js/2.918f0adb.chunk.js",
|
||||
"static/css/main.4c6c667e.chunk.css",
|
||||
"static/js/main.6b34bb53.chunk.js"
|
||||
]
|
||||
}
|
@ -1 +1 @@
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#ffffff"/><title>lama-cleaner - Image inpainting powered by LaMa</title><link href="/static/css/main.bdd774f1.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,l,a=r[0],f=r[1],i=r[2],p=0,s=[];p<a.length;p++)l=a[p],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(c&&c(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var f=t[a];0!==o[f]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var a=this["webpackJsonplama-cleaner"]=this["webpackJsonplama-cleaner"]||[],f=a.push.bind(a);a.push=r,a=a.slice();for(var i=0;i<a.length;i++)r(a[i]);var c=f;t()}([])</script><script src="/static/js/2.1b1d3019.chunk.js"></script><script src="/static/js/main.9f4ed6dc.chunk.js"></script></body></html>
|
||||
<!doctype html><html lang="en"><head><meta charset="utf-8"/><meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=0"/><meta name="theme-color" content="#ffffff"/><title>lama-cleaner - Image inpainting powered by LaMa</title><link href="/static/css/main.4c6c667e.chunk.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div><script>!function(e){function r(r){for(var n,l,a=r[0],f=r[1],i=r[2],p=0,s=[];p<a.length;p++)l=a[p],Object.prototype.hasOwnProperty.call(o,l)&&o[l]&&s.push(o[l][0]),o[l]=0;for(n in f)Object.prototype.hasOwnProperty.call(f,n)&&(e[n]=f[n]);for(c&&c(r);s.length;)s.shift()();return u.push.apply(u,i||[]),t()}function t(){for(var e,r=0;r<u.length;r++){for(var t=u[r],n=!0,a=1;a<t.length;a++){var f=t[a];0!==o[f]&&(n=!1)}n&&(u.splice(r--,1),e=l(l.s=t[0]))}return e}var n={},o={1:0},u=[];function l(r){if(n[r])return n[r].exports;var t=n[r]={i:r,l:!1,exports:{}};return e[r].call(t.exports,t,t.exports,l),t.l=!0,t.exports}l.m=e,l.c=n,l.d=function(e,r,t){l.o(e,r)||Object.defineProperty(e,r,{enumerable:!0,get:t})},l.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},l.t=function(e,r){if(1&r&&(e=l(e)),8&r)return e;if(4&r&&"object"==typeof e&&e&&e.__esModule)return e;var t=Object.create(null);if(l.r(t),Object.defineProperty(t,"default",{enumerable:!0,value:e}),2&r&&"string"!=typeof e)for(var n in e)l.d(t,n,function(r){return e[r]}.bind(null,n));return t},l.n=function(e){var r=e&&e.__esModule?function(){return e.default}:function(){return e};return l.d(r,"a",r),r},l.o=function(e,r){return Object.prototype.hasOwnProperty.call(e,r)},l.p="/";var a=this["webpackJsonplama-cleaner"]=this["webpackJsonplama-cleaner"]||[],f=a.push.bind(a);a.push=r,a=a.slice();for(var i=0;i<a.length;i++)r(a[i]);var c=f;t()}([])</script><script src="/static/js/2.918f0adb.chunk.js"></script><script src="/static/js/main.6b34bb53.chunk.js"></script></body></html>
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
2
lama_cleaner/app/build/static/js/2.918f0adb.chunk.js
Normal file
2
lama_cleaner/app/build/static/js/2.918f0adb.chunk.js
Normal file
File diff suppressed because one or more lines are too long
1
lama_cleaner/app/build/static/js/main.6b34bb53.chunk.js
Normal file
1
lama_cleaner/app/build/static/js/main.6b34bb53.chunk.js
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -9,6 +9,7 @@
|
||||
"@radix-ui/react-select": "0.1.2-rc.27",
|
||||
"@radix-ui/react-switch": "^0.1.5",
|
||||
"@radix-ui/react-toast": "^0.1.1",
|
||||
"@radix-ui/react-tooltip": "^0.1.7",
|
||||
"@testing-library/jest-dom": "^5.14.1",
|
||||
"@testing-library/react": "^12.1.2",
|
||||
"@testing-library/user-event": "^13.5.0",
|
||||
@ -17,6 +18,7 @@
|
||||
"@types/react": "^17.0.30",
|
||||
"@types/react-dom": "^17.0.9",
|
||||
"cross-env": "7.x",
|
||||
"nanoid": "^4.0.0",
|
||||
"npm-run-all": "4.x",
|
||||
"react": "^17.0.2",
|
||||
"react-dom": "^17.0.2",
|
||||
|
@ -1,6 +1,7 @@
|
||||
import React, { useEffect } from 'react'
|
||||
import React, { useEffect, useMemo } from 'react'
|
||||
import { useKeyPressEvent } from 'react-use'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { nanoid } from 'nanoid'
|
||||
import useInputImage from './hooks/useInputImage'
|
||||
import LandingPage from './components/LandingPage/LandingPage'
|
||||
import { themeState } from './components/Header/ThemeChanger'
|
||||
@ -33,10 +34,14 @@ function App() {
|
||||
document.body.setAttribute('data-theme', theme)
|
||||
}, [theme])
|
||||
|
||||
const workspaceId = useMemo(() => {
|
||||
return nanoid()
|
||||
}, [file])
|
||||
|
||||
return (
|
||||
<div className="lama-cleaner">
|
||||
<Header />
|
||||
{file ? <Workspace file={file} /> : <LandingPage />}
|
||||
{file ? <Workspace file={file} key={workspaceId} /> : <LandingPage />}
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
@ -35,7 +35,6 @@ export default async function inpaint(
|
||||
method: 'POST',
|
||||
body: fd,
|
||||
}).then(async r => {
|
||||
console.log(r)
|
||||
if (r.ok) {
|
||||
return r.blob()
|
||||
}
|
||||
|
@ -26,6 +26,7 @@ import {
|
||||
isMidClick,
|
||||
isRightClick,
|
||||
loadImage,
|
||||
srcToFile,
|
||||
useImage,
|
||||
} from '../../utils'
|
||||
import { settingState, toastState } from '../../store/Atoms'
|
||||
@ -105,6 +106,11 @@ export default function Editor(props: EditorProps) {
|
||||
|
||||
const [sliderPos, setSliderPos] = useState<number>(0)
|
||||
|
||||
// redo 相关
|
||||
const [redoRenders, setRedoRenders] = useState<HTMLImageElement[]>([])
|
||||
const [redoCurLines, setRedoCurLines] = useState<Line[]>([])
|
||||
const [redoLineGroups, setRedoLineGroups] = useState<LineGroup[]>([])
|
||||
|
||||
const draw = useCallback(
|
||||
(render: HTMLImageElement, lineGroup: LineGroup) => {
|
||||
if (!context) {
|
||||
@ -123,7 +129,7 @@ export default function Editor(props: EditorProps) {
|
||||
[context, original]
|
||||
)
|
||||
|
||||
const drawAllLinesOnMask = (_lineGroups: LineGroup[]) => {
|
||||
const drawLinesOnMask = (_lineGroups: LineGroup[]) => {
|
||||
if (!context?.canvas.width || !context?.canvas.height) {
|
||||
throw new Error('canvas has invalid size')
|
||||
}
|
||||
@ -148,11 +154,22 @@ export default function Editor(props: EditorProps) {
|
||||
setCurLineGroup([])
|
||||
setIsDraging(false)
|
||||
setIsInpaintingLoading(true)
|
||||
drawAllLinesOnMask(newLineGroups)
|
||||
if (settings.graduallyInpainting) {
|
||||
drawLinesOnMask([curLineGroup])
|
||||
} else {
|
||||
drawLinesOnMask(newLineGroups)
|
||||
}
|
||||
|
||||
let targetFile = file
|
||||
if (settings.graduallyInpainting === true && renders.length > 0) {
|
||||
console.info('gradually inpainting on last result')
|
||||
const lastRender = renders[renders.length - 1]
|
||||
targetFile = await srcToFile(lastRender.currentSrc, file.name, file.type)
|
||||
}
|
||||
|
||||
try {
|
||||
const res = await inpaint(
|
||||
file,
|
||||
targetFile,
|
||||
maskCanvas.toDataURL(),
|
||||
settings,
|
||||
sizeLimit.toString()
|
||||
@ -167,6 +184,9 @@ export default function Editor(props: EditorProps) {
|
||||
draw(newRender, [])
|
||||
// Only append new LineGroup after inpainting success
|
||||
setLineGroups(newLineGroups)
|
||||
|
||||
// clear redo stack
|
||||
resetRedoState()
|
||||
} catch (e: any) {
|
||||
setToastState({
|
||||
open: true,
|
||||
@ -284,15 +304,29 @@ export default function Editor(props: EditorProps) {
|
||||
}
|
||||
const viewport = viewportRef.current
|
||||
if (!viewport) {
|
||||
throw new Error('no viewport')
|
||||
return
|
||||
}
|
||||
const offsetX = (windowSize.width - original.width * minScale) / 2
|
||||
const offsetY = (windowSize.height - original.height * minScale) / 2
|
||||
viewport.setTransform(offsetX, offsetY, minScale, 200, 'easeOutQuad')
|
||||
viewport.state.scale = minScale
|
||||
|
||||
setScale(minScale)
|
||||
setPanned(false)
|
||||
}, [viewportRef, minScale, original, windowSize])
|
||||
}, [
|
||||
viewportRef,
|
||||
windowSize,
|
||||
original,
|
||||
original.width,
|
||||
windowSize.height,
|
||||
minScale,
|
||||
])
|
||||
|
||||
const resetRedoState = () => {
|
||||
setRedoCurLines([])
|
||||
setRedoLineGroups([])
|
||||
setRedoRenders([])
|
||||
}
|
||||
|
||||
useEffect(() => {
|
||||
window.addEventListener('resize', () => {
|
||||
@ -427,28 +461,43 @@ export default function Editor(props: EditorProps) {
|
||||
if (curLineGroup.length === 0) {
|
||||
return
|
||||
}
|
||||
const newLineGroup = curLineGroup.slice(0, curLineGroup.length - 1)
|
||||
|
||||
const lastLine = curLineGroup.pop()!
|
||||
const newRedoCurLines = [...redoCurLines, lastLine]
|
||||
setRedoCurLines(newRedoCurLines)
|
||||
|
||||
const newLineGroup = [...curLineGroup]
|
||||
setCurLineGroup(newLineGroup)
|
||||
drawOnCurrentRender(newLineGroup)
|
||||
}, [curLineGroup, drawOnCurrentRender])
|
||||
}, [curLineGroup, redoCurLines, drawOnCurrentRender])
|
||||
|
||||
const undoRender = useCallback(() => {
|
||||
if (!renders.length) {
|
||||
return
|
||||
}
|
||||
|
||||
const groups = lineGroups.slice(0, lineGroups.length - 1)
|
||||
setLineGroups(groups)
|
||||
// save line Group
|
||||
const lastLineGroup = lineGroups.pop()!
|
||||
setRedoLineGroups([...redoLineGroups, lastLineGroup])
|
||||
// If render is undo, clear strokes
|
||||
setRedoCurLines([])
|
||||
|
||||
setLineGroups([...lineGroups])
|
||||
setCurLineGroup([])
|
||||
setIsDraging(false)
|
||||
const newRenders = renders.slice(0, renders.length - 1)
|
||||
|
||||
// save render
|
||||
const lastRender = renders.pop()!
|
||||
setRedoRenders([...redoRenders, lastRender])
|
||||
|
||||
const newRenders = [...renders]
|
||||
setRenders(newRenders)
|
||||
if (newRenders.length === 0) {
|
||||
draw(original, [])
|
||||
} else {
|
||||
draw(newRenders[newRenders.length - 1], [])
|
||||
}
|
||||
}, [draw, renders, lineGroups, original])
|
||||
}, [draw, renders, redoRenders, redoLineGroups, lineGroups, original])
|
||||
|
||||
const undo = () => {
|
||||
if (settings.runInpaintingManually && curLineGroup.length !== 0) {
|
||||
@ -460,13 +509,15 @@ export default function Editor(props: EditorProps) {
|
||||
|
||||
// Handle Cmd+Z
|
||||
const undoPredicate = (event: KeyboardEvent) => {
|
||||
const isCmdZ = (event.metaKey || event.ctrlKey) && event.key === 'z'
|
||||
const isCmdZ =
|
||||
(event.metaKey || event.ctrlKey) && !event.shiftKey && event.key === 'z'
|
||||
// Handle tab switch
|
||||
if (event.key === 'Tab') {
|
||||
event.preventDefault()
|
||||
}
|
||||
if (isCmdZ) {
|
||||
event.preventDefault()
|
||||
console.log('undo')
|
||||
return true
|
||||
}
|
||||
return false
|
||||
@ -475,6 +526,9 @@ export default function Editor(props: EditorProps) {
|
||||
useKey(undoPredicate, undo, undefined, [undoStroke, undoRender])
|
||||
|
||||
const disableUndo = () => {
|
||||
if (isInpaintingLoading) {
|
||||
return true
|
||||
}
|
||||
if (renders.length > 0) {
|
||||
return false
|
||||
}
|
||||
@ -490,6 +544,80 @@ export default function Editor(props: EditorProps) {
|
||||
return false
|
||||
}
|
||||
|
||||
const redoStroke = useCallback(() => {
|
||||
if (redoCurLines.length === 0) {
|
||||
return
|
||||
}
|
||||
const line = redoCurLines.pop()!
|
||||
setRedoCurLines([...redoCurLines])
|
||||
|
||||
const newLineGroup = [...curLineGroup, line]
|
||||
setCurLineGroup(newLineGroup)
|
||||
drawOnCurrentRender(newLineGroup)
|
||||
}, [curLineGroup, redoCurLines, drawOnCurrentRender])
|
||||
|
||||
const redoRender = useCallback(() => {
|
||||
if (redoRenders.length === 0) {
|
||||
return
|
||||
}
|
||||
const lineGroup = redoLineGroups.pop()!
|
||||
setRedoLineGroups([...redoLineGroups])
|
||||
|
||||
setLineGroups([...lineGroups, lineGroup])
|
||||
setCurLineGroup([])
|
||||
setIsDraging(false)
|
||||
|
||||
const render = redoRenders.pop()!
|
||||
const newRenders = [...renders, render]
|
||||
setRenders(newRenders)
|
||||
draw(newRenders[newRenders.length - 1], [])
|
||||
}, [draw, renders, redoRenders, redoLineGroups, lineGroups, original])
|
||||
|
||||
const redo = () => {
|
||||
if (settings.runInpaintingManually && redoCurLines.length !== 0) {
|
||||
redoStroke()
|
||||
} else {
|
||||
redoRender()
|
||||
}
|
||||
}
|
||||
|
||||
// Handle Cmd+shift+Z
|
||||
const redoPredicate = (event: KeyboardEvent) => {
|
||||
const isCmdZ =
|
||||
(event.metaKey || event.ctrlKey) && event.shiftKey && event.key === 'z'
|
||||
// Handle tab switch
|
||||
if (event.key === 'Tab') {
|
||||
event.preventDefault()
|
||||
}
|
||||
if (isCmdZ) {
|
||||
event.preventDefault()
|
||||
console.log('redo')
|
||||
return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
useKey(redoPredicate, redo, undefined, [redoStroke, redoRender])
|
||||
|
||||
const disableRedo = () => {
|
||||
if (isInpaintingLoading) {
|
||||
return true
|
||||
}
|
||||
if (redoRenders.length > 0) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (settings.runInpaintingManually) {
|
||||
if (redoCurLines.length === 0) {
|
||||
return true
|
||||
}
|
||||
} else if (redoRenders.length === 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
useKeyPressEvent(
|
||||
'Tab',
|
||||
ev => {
|
||||
@ -763,6 +891,27 @@ export default function Editor(props: EditorProps) {
|
||||
onClick={undo}
|
||||
disabled={disableUndo()}
|
||||
/>
|
||||
<Button
|
||||
toolTip="Redo"
|
||||
tooltipPosition="top"
|
||||
icon={
|
||||
<svg
|
||||
width="19"
|
||||
height="9"
|
||||
viewBox="0 0 19 9"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
transform="scale(-1,1)"
|
||||
>
|
||||
<path
|
||||
d="M2 1C2 0.447715 1.55228 0 1 0C0.447715 0 0 0.447715 0 1H2ZM1 8H0V9H1V8ZM8 9C8.55228 9 9 8.55229 9 8C9 7.44771 8.55228 7 8 7V9ZM16.5963 7.42809C16.8327 7.92721 17.429 8.14016 17.9281 7.90374C18.4272 7.66731 18.6402 7.07103 18.4037 6.57191L16.5963 7.42809ZM16.9468 5.83205L17.8505 5.40396L16.9468 5.83205ZM0 1V8H2V1H0ZM1 9H8V7H1V9ZM1.66896 8.74329L6.66896 4.24329L5.33104 2.75671L0.331035 7.25671L1.66896 8.74329ZM16.043 6.26014L16.5963 7.42809L18.4037 6.57191L17.8505 5.40396L16.043 6.26014ZM6.65079 4.25926C9.67554 1.66661 14.3376 2.65979 16.043 6.26014L17.8505 5.40396C15.5805 0.61182 9.37523 -0.710131 5.34921 2.74074L6.65079 4.25926Z"
|
||||
fill="currentColor"
|
||||
/>
|
||||
</svg>
|
||||
}
|
||||
onClick={redo}
|
||||
disabled={disableRedo()}
|
||||
/>
|
||||
<Button
|
||||
toolTip="Show Original"
|
||||
tooltipPosition="top"
|
||||
|
@ -1,4 +1,4 @@
|
||||
import React, { useCallback, useState } from 'react'
|
||||
import React, { useCallback, useEffect, useState } from 'react'
|
||||
import Selector from '../shared/Selector'
|
||||
|
||||
const sizes = ['720', '1080', '2000', 'Original']
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { ArrowLeftIcon } from '@heroicons/react/outline'
|
||||
import React from 'react'
|
||||
import { ArrowLeftIcon, UploadIcon } from '@heroicons/react/outline'
|
||||
import React, { useState } from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { fileState } from '../../store/Atoms'
|
||||
import Button from '../shared/Button'
|
||||
@ -11,20 +11,30 @@ import SettingIcon from '../Settings/SettingIcon'
|
||||
const Header = () => {
|
||||
const [file, setFile] = useRecoilState(fileState)
|
||||
const resolution = useResolution()
|
||||
const [uploadElemId] = useState(`file-upload-${Math.random().toString()}`)
|
||||
|
||||
const renderHeader = () => {
|
||||
return (
|
||||
<header>
|
||||
<div style={{ visibility: file ? 'visible' : 'hidden' }}>
|
||||
<Button
|
||||
icon={<ArrowLeftIcon />}
|
||||
onClick={() => {
|
||||
setFile(undefined)
|
||||
}}
|
||||
style={{ border: 0 }}
|
||||
>
|
||||
{resolution === 'desktop' ? 'Start New' : undefined}
|
||||
</Button>
|
||||
<label htmlFor={uploadElemId}>
|
||||
<Button icon={<UploadIcon />} style={{ border: 0 }}>
|
||||
<input
|
||||
style={{ display: 'none' }}
|
||||
id={uploadElemId}
|
||||
name={uploadElemId}
|
||||
type="file"
|
||||
onChange={ev => {
|
||||
const newFile = ev.currentTarget.files?.[0]
|
||||
if (newFile) {
|
||||
setFile(newFile)
|
||||
}
|
||||
}}
|
||||
accept="image/png, image/jpeg"
|
||||
/>
|
||||
{resolution === 'desktop' ? 'Upload New' : undefined}
|
||||
</Button>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div className="header-icons-wrapper">
|
||||
|
@ -0,0 +1,32 @@
|
||||
import React from 'react'
|
||||
import { useRecoilState } from 'recoil'
|
||||
import { settingState } from '../../store/Atoms'
|
||||
import { Switch, SwitchThumb } from '../shared/Switch'
|
||||
import SettingBlock from './SettingBlock'
|
||||
|
||||
const GraduallyInpaintingSettingBlock: React.FC = () => {
|
||||
const [setting, setSettingState] = useRecoilState(settingState)
|
||||
|
||||
const onCheckChange = (checked: boolean) => {
|
||||
setSettingState(old => {
|
||||
return { ...old, graduallyInpainting: checked }
|
||||
})
|
||||
}
|
||||
|
||||
return (
|
||||
<SettingBlock
|
||||
title="Gradually Inpainting"
|
||||
desc="If checked, perform inpainting on the last result, otherwise, always run the model on the initial image."
|
||||
input={
|
||||
<Switch
|
||||
checked={setting.graduallyInpainting}
|
||||
onCheckedChange={onCheckChange}
|
||||
>
|
||||
<SwitchThumb />
|
||||
</Switch>
|
||||
}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
export default GraduallyInpaintingSettingBlock
|
@ -25,8 +25,10 @@
|
||||
|
||||
.setting-block-content-title {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: space-between;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.setting-block-desc {
|
||||
|
@ -1,4 +1,5 @@
|
||||
import React, { ReactNode } from 'react'
|
||||
import Tooltip from '../shared/Tooltip'
|
||||
|
||||
interface SettingBlockProps {
|
||||
title: string
|
||||
@ -15,7 +16,24 @@ function SettingBlock(props: SettingBlockProps) {
|
||||
<div className="setting-block-content">
|
||||
<div className="setting-block-content-title">
|
||||
<span>{title}</span>
|
||||
{desc && <span className="setting-block-desc">{desc}</span>}
|
||||
{desc && (
|
||||
<Tooltip content={<div style={{ width: 400 }}>{desc}</div>}>
|
||||
<svg
|
||||
width="18"
|
||||
height="18"
|
||||
viewBox="0 0 15 15"
|
||||
fill="none"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<path
|
||||
d="M0.877075 7.49972C0.877075 3.84204 3.84222 0.876892 7.49991 0.876892C11.1576 0.876892 14.1227 3.84204 14.1227 7.49972C14.1227 11.1574 11.1576 14.1226 7.49991 14.1226C3.84222 14.1226 0.877075 11.1574 0.877075 7.49972ZM7.49991 1.82689C4.36689 1.82689 1.82708 4.36671 1.82708 7.49972C1.82708 10.6327 4.36689 13.1726 7.49991 13.1726C10.6329 13.1726 13.1727 10.6327 13.1727 7.49972C13.1727 4.36671 10.6329 1.82689 7.49991 1.82689ZM8.24993 10.5C8.24993 10.9142 7.91414 11.25 7.49993 11.25C7.08571 11.25 6.74993 10.9142 6.74993 10.5C6.74993 10.0858 7.08571 9.75 7.49993 9.75C7.91414 9.75 8.24993 10.0858 8.24993 10.5ZM6.05003 6.25C6.05003 5.57211 6.63511 4.925 7.50003 4.925C8.36496 4.925 8.95003 5.57211 8.95003 6.25C8.95003 6.74118 8.68002 6.99212 8.21447 7.27494C8.16251 7.30651 8.10258 7.34131 8.03847 7.37854L8.03841 7.37858C7.85521 7.48497 7.63788 7.61119 7.47449 7.73849C7.23214 7.92732 6.95003 8.23198 6.95003 8.7C6.95004 9.00376 7.19628 9.25 7.50004 9.25C7.8024 9.25 8.04778 9.00601 8.05002 8.70417L8.05056 8.7033C8.05924 8.6896 8.08493 8.65735 8.15058 8.6062C8.25207 8.52712 8.36508 8.46163 8.51567 8.37436L8.51571 8.37433C8.59422 8.32883 8.68296 8.27741 8.78559 8.21506C9.32004 7.89038 10.05 7.35382 10.05 6.25C10.05 4.92789 8.93511 3.825 7.50003 3.825C6.06496 3.825 4.95003 4.92789 4.95003 6.25C4.95003 6.55376 5.19628 6.8 5.50003 6.8C5.80379 6.8 6.05003 6.55376 6.05003 6.25Z"
|
||||
fill="currentColor"
|
||||
fillRule="evenodd"
|
||||
clipRule="evenodd"
|
||||
/>
|
||||
</svg>
|
||||
</Tooltip>
|
||||
)}
|
||||
</div>
|
||||
{input}
|
||||
</div>
|
||||
|
@ -6,6 +6,7 @@ import Modal from '../shared/Modal'
|
||||
import ManualRunInpaintingSettingBlock from './ManualRunInpaintingSettingBlock'
|
||||
import HDSettingBlock from './HDSettingBlock'
|
||||
import ModelSettingBlock from './ModelSettingBlock'
|
||||
import GraduallyInpaintingSettingBlock from './GraduallyInpaintingSettingBlock'
|
||||
|
||||
interface SettingModalProps {
|
||||
onClose: () => void
|
||||
@ -29,6 +30,7 @@ export default function SettingModal(props: SettingModalProps) {
|
||||
show={setting.show}
|
||||
>
|
||||
<ManualRunInpaintingSettingBlock />
|
||||
<GraduallyInpaintingSettingBlock />
|
||||
<ModelSettingBlock />
|
||||
<HDSettingBlock />
|
||||
</Modal>
|
||||
|
@ -31,3 +31,40 @@ $tooltip-margin: 1.5rem;
|
||||
margin-top: $tooltip-margin;
|
||||
}
|
||||
}
|
||||
|
||||
// radix-ui
|
||||
.tooltip-trigger {
|
||||
all: unset;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tooltip-content {
|
||||
color: var(--tooltip-text-color);
|
||||
background-color: var(--tooltip-bg);
|
||||
padding: 10px 15px;
|
||||
border-radius: 4px;
|
||||
box-shadow: hsl(206 22% 7% / 35%) 0px 10px 38px -10px,
|
||||
hsl(206 22% 7% / 20%) 0px 10px 20px -15px;
|
||||
|
||||
@media (prefers-reduced-motion: no-preference) {
|
||||
animation-duration: 400ms;
|
||||
animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
|
||||
animation-fill-mode: forwards;
|
||||
will-change: transform, opacity;
|
||||
|
||||
&[data-state='delayed-open'] {
|
||||
&[data-side='top'] {
|
||||
animation-name: slideDownAndFade;
|
||||
}
|
||||
&[data-side='bottom'] {
|
||||
animation-name: slideUpAndFade;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.tooltip-arrow {
|
||||
fill: var(--tooltip-bg);
|
||||
}
|
||||
|
29
lama_cleaner/app/src/components/shared/Tooltip.tsx
Normal file
29
lama_cleaner/app/src/components/shared/Tooltip.tsx
Normal file
@ -0,0 +1,29 @@
|
||||
import React, { ReactNode } from 'react'
|
||||
import * as TooltipPrimitive from '@radix-ui/react-tooltip'
|
||||
import { TooltipProps } from '@radix-ui/react-tooltip'
|
||||
|
||||
interface MyTooltipProps extends TooltipProps {
|
||||
content: string | ReactNode
|
||||
children: ReactNode
|
||||
}
|
||||
|
||||
const Tooltip = (props: MyTooltipProps) => {
|
||||
const { content, children } = props
|
||||
|
||||
return (
|
||||
<TooltipPrimitive.Root>
|
||||
<TooltipPrimitive.Provider>
|
||||
<TooltipPrimitive.Trigger className="tooltip-trigger">
|
||||
{children}
|
||||
</TooltipPrimitive.Trigger>
|
||||
|
||||
<TooltipPrimitive.Content className="tooltip-content">
|
||||
{content}
|
||||
<TooltipPrimitive.Arrow className="tooltip-arrow" />
|
||||
</TooltipPrimitive.Content>
|
||||
</TooltipPrimitive.Provider>
|
||||
</TooltipPrimitive.Root>
|
||||
)
|
||||
}
|
||||
|
||||
export default Tooltip
|
@ -32,6 +32,7 @@ export const shortcutsState = atom<boolean>({
|
||||
|
||||
export interface Settings {
|
||||
show: boolean
|
||||
graduallyInpainting: boolean
|
||||
runInpaintingManually: boolean
|
||||
model: AIModel
|
||||
|
||||
@ -48,6 +49,7 @@ export interface Settings {
|
||||
|
||||
export const settingStateDefault = {
|
||||
show: false,
|
||||
graduallyInpainting: true,
|
||||
runInpaintingManually: false,
|
||||
model: AIModel.LAMA,
|
||||
ldmSteps: 50,
|
||||
@ -65,7 +67,7 @@ const localStorageEffect =
|
||||
if (savedValue != null) {
|
||||
const storageSettings = JSON.parse(savedValue)
|
||||
storageSettings.show = false
|
||||
setSelf(storageSettings)
|
||||
setSelf({ ...settingStateDefault, ...storageSettings })
|
||||
}
|
||||
|
||||
onSet((newValue: Settings, _: string, isReset: boolean) =>
|
||||
|
@ -55,3 +55,25 @@
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideUpAndFade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(2px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes slideDownAndFade {
|
||||
0% {
|
||||
opacity: 0;
|
||||
transform: translateY(-2px);
|
||||
}
|
||||
100% {
|
||||
opacity: 1;
|
||||
transform: translateY(0);
|
||||
}
|
||||
}
|
||||
|
@ -10,7 +10,7 @@
|
||||
--border-color: rgb(100, 100, 120);
|
||||
--border-color-light: rgba(100, 100, 120, 0.5);
|
||||
--tooltip-bg: rgb(230, 230, 234);
|
||||
--tooltip-text-color: rgb(0, 0,0);
|
||||
--tooltip-text-color: rgb(0, 0, 0);
|
||||
|
||||
--error-color: rgb(239, 68, 68);
|
||||
--success-color: rgb(16, 185, 129);
|
||||
@ -44,4 +44,7 @@
|
||||
--switch-root-background-color: rgb(223, 225, 228);
|
||||
--switch-thumb-color: var(--page-bg);
|
||||
--switch-thumb-checked-color: var(--page-bg);
|
||||
|
||||
// tooltip
|
||||
--tooltip-bg: var(--page-bg);
|
||||
}
|
||||
|
@ -42,4 +42,7 @@
|
||||
--switch-root-background-color: rgb(60, 63, 68);
|
||||
--switch-thumb-color: rgb(31, 32, 35);
|
||||
--switch-thumb-checked-color: white;
|
||||
|
||||
// tooltip
|
||||
--tooltip-bg: hsl(197 6.8% 13.6%);
|
||||
}
|
||||
|
@ -192,3 +192,13 @@ export function isMidClick(ev: SyntheticEvent) {
|
||||
const mouseEvent = ev.nativeEvent as MouseEvent
|
||||
return mouseEvent.button === 1
|
||||
}
|
||||
|
||||
export function srcToFile(src: string, fileName: string, mimeType: string) {
|
||||
return fetch(src)
|
||||
.then(function (res) {
|
||||
return res.arrayBuffer()
|
||||
})
|
||||
.then(function (buf) {
|
||||
return new File([buf], fileName, { type: mimeType })
|
||||
})
|
||||
}
|
||||
|
@ -1551,6 +1551,14 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/popper@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/popper/-/popper-0.1.0.tgz#c387a38f31b7799e1ea0d2bb1ca0c91c2931b063"
|
||||
integrity sha512-uzYeElL3w7SeNMuQpXiFlBhTT+JyaNMCwDfjKkrzugEcYrf5n52PHqncNdQPUtR42hJh8V9FsqyEDbDxkeNjJQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
csstype "^3.0.4"
|
||||
|
||||
"@radix-ui/primitive@0.1.0":
|
||||
version "0.1.0"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/primitive/-/primitive-0.1.0.tgz#6206b97d379994f0d1929809db035733b337e543"
|
||||
@ -1558,6 +1566,14 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-arrow@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/react-arrow/-/react-arrow-0.1.4.tgz#a871448a418cd3507d83840fdd47558cb961672b"
|
||||
integrity sha512-BB6XzAb7Ml7+wwpFdYVtZpK1BlMgqyafSQNGzhIpSZ4uXvXOHPlR5GP8M449JkeQzgQjv9Mp1AsJxFC0KuOtuA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "0.1.4"
|
||||
|
||||
"@radix-ui/react-collection@0.1.5-rc.18":
|
||||
version "0.1.5-rc.18"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/react-collection/-/react-collection-0.1.5-rc.18.tgz#4dc03a8f464643748c0dad781b472f149d671d5c"
|
||||
@ -1706,6 +1722,21 @@
|
||||
"@radix-ui/react-id" "0.1.6-rc.18"
|
||||
"@radix-ui/react-primitive" "0.1.5-rc.18"
|
||||
|
||||
"@radix-ui/react-popper@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/react-popper/-/react-popper-0.1.4.tgz#dfc055dcd7dfae6a2eff7a70d333141d15a5d029"
|
||||
integrity sha512-18gDYof97t8UQa7zwklG1Dr8jIdj3u+rVOQLzPi9f5i1YQak/pVGkaqw8aY+iDUknKKuZniTk/7jbAJUYlKyOw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/popper" "0.1.0"
|
||||
"@radix-ui/react-arrow" "0.1.4"
|
||||
"@radix-ui/react-compose-refs" "0.1.0"
|
||||
"@radix-ui/react-context" "0.1.1"
|
||||
"@radix-ui/react-primitive" "0.1.4"
|
||||
"@radix-ui/react-use-rect" "0.1.1"
|
||||
"@radix-ui/react-use-size" "0.1.1"
|
||||
"@radix-ui/rect" "0.1.1"
|
||||
|
||||
"@radix-ui/react-portal@0.1.4":
|
||||
version "0.1.4"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/react-portal/-/react-portal-0.1.4.tgz#17bdce3d7f1a9a0b35cb5e935ab8bc562441a7d2"
|
||||
@ -1833,6 +1864,27 @@
|
||||
"@radix-ui/react-use-layout-effect" "0.1.0"
|
||||
"@radix-ui/react-visually-hidden" "0.1.4"
|
||||
|
||||
"@radix-ui/react-tooltip@^0.1.7":
|
||||
version "0.1.7"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/react-tooltip/-/react-tooltip-0.1.7.tgz#6f8c00d6e489565d14abf209ce0fb8853c8c8ee3"
|
||||
integrity sha512-eiBUsVOHenZ0JR16tl970bB0DafJBz6mFgSGfIGIVpflFj0LIsIDiLMsYyvYdx1KwwsIUDTEZtxcPm/sWjPzqA==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/primitive" "0.1.0"
|
||||
"@radix-ui/react-compose-refs" "0.1.0"
|
||||
"@radix-ui/react-context" "0.1.1"
|
||||
"@radix-ui/react-id" "0.1.5"
|
||||
"@radix-ui/react-popper" "0.1.4"
|
||||
"@radix-ui/react-portal" "0.1.4"
|
||||
"@radix-ui/react-presence" "0.1.2"
|
||||
"@radix-ui/react-primitive" "0.1.4"
|
||||
"@radix-ui/react-slot" "0.1.2"
|
||||
"@radix-ui/react-use-controllable-state" "0.1.0"
|
||||
"@radix-ui/react-use-escape-keydown" "0.1.0"
|
||||
"@radix-ui/react-use-previous" "0.1.1"
|
||||
"@radix-ui/react-use-rect" "0.1.1"
|
||||
"@radix-ui/react-visually-hidden" "0.1.4"
|
||||
|
||||
"@radix-ui/react-use-body-pointer-events@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/react-use-body-pointer-events/-/react-use-body-pointer-events-0.1.1.tgz#63e7fd81ca7ffd30841deb584cd2b7f460df2597"
|
||||
@ -1923,6 +1975,14 @@
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@radix-ui/react-use-rect@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/react-use-rect/-/react-use-rect-0.1.1.tgz#6c15384beee59c086e75b89a7e66f3d2e583a856"
|
||||
integrity sha512-kHNNXAsP3/PeszEmM/nxBBS9Jbo93sO+xuMTcRfwzXsmxT5gDXQzAiKbZQ0EecCPtJIzqvr7dlaQi/aP1PKYqQ==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/rect" "0.1.1"
|
||||
|
||||
"@radix-ui/react-use-size@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/react-use-size/-/react-use-size-0.1.1.tgz#f6b75272a5d41c3089ca78c8a2e48e5f204ef90f"
|
||||
@ -1946,6 +2006,13 @@
|
||||
"@babel/runtime" "^7.13.10"
|
||||
"@radix-ui/react-primitive" "0.1.5-rc.18"
|
||||
|
||||
"@radix-ui/rect@0.1.1":
|
||||
version "0.1.1"
|
||||
resolved "https://registry.npmmirror.com/@radix-ui/rect/-/rect-0.1.1.tgz#95b5ba51f469bea6b1b841e2d427e17e37d38419"
|
||||
integrity sha512-g3hnE/UcOg7REdewduRPAK88EPuLZtaq7sA9ouu8S+YEtnyFRI16jgv6GZYe3VMoQLL1T171ebmEPtDjyxWLzw==
|
||||
dependencies:
|
||||
"@babel/runtime" "^7.13.10"
|
||||
|
||||
"@rollup/plugin-node-resolve@^7.1.1":
|
||||
version "7.1.3"
|
||||
resolved "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-7.1.3.tgz"
|
||||
@ -4496,6 +4563,11 @@ csstype@^3.0.2, csstype@^3.0.6:
|
||||
resolved "https://registry.npmjs.org/csstype/-/csstype-3.0.9.tgz"
|
||||
integrity sha512-rpw6JPxK6Rfg1zLOYCSwle2GFOOsnjmDYDaBwEcwoOg4qlsIVCN789VkBZDJAGi4T07gI4YSutR43t9Zz4Lzuw==
|
||||
|
||||
csstype@^3.0.4:
|
||||
version "3.1.0"
|
||||
resolved "https://registry.npmmirror.com/csstype/-/csstype-3.1.0.tgz#4ddcac3718d787cf9df0d1b7d15033925c8f29f2"
|
||||
integrity sha512-uX1KG+x9h5hIJsaKR9xHUeUraxf8IODOwq9JLNPq6BwB04a/xgpq3rcx47l5BZu5zBPlgD342tdke3Hom/nJRA==
|
||||
|
||||
cyclist@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz"
|
||||
@ -8102,6 +8174,11 @@ nanoid@^3.1.28:
|
||||
resolved "https://registry.npmjs.org/nanoid/-/nanoid-3.1.30.tgz"
|
||||
integrity sha512-zJpuPDwOv8D2zq2WRoMe1HsfZthVewpel9CAvTfc/2mBD1uUT/agc5f7GHGWXlYkFvi1mVxe4IjvP2HNrop7nQ==
|
||||
|
||||
nanoid@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.npmmirror.com/nanoid/-/nanoid-4.0.0.tgz#6e144dee117609232c3f415c34b0e550e64999a5"
|
||||
integrity sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==
|
||||
|
||||
nanomatch@^1.2.9:
|
||||
version "1.2.13"
|
||||
resolved "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz"
|
||||
|
2
setup.py
2
setup.py
@ -21,7 +21,7 @@ def load_requirements():
|
||||
# https://setuptools.readthedocs.io/en/latest/setuptools.html#including-data-files
|
||||
setuptools.setup(
|
||||
name="lama-cleaner",
|
||||
version="0.13.0",
|
||||
version="0.14.0",
|
||||
author="PanicByte",
|
||||
author_email="cwq1913@gmail.com",
|
||||
description="Image inpainting tool powered by SOTA AI Model",
|
||||
|
Loading…
Reference in New Issue
Block a user