From f97e17a593cec6cef396226b84797947e14ea361 Mon Sep 17 00:00:00 2001 From: Sanster Date: Sat, 23 Apr 2022 20:21:34 +0800 Subject: [PATCH] add manual run mode --- .../app/src/components/Editor/Editor.tsx | 219 ++++++++++-------- ...sx => ManualRunInpaintingSettingBlock.tsx} | 12 +- .../src/components/Settings/SettingsModal.tsx | 5 +- lama_cleaner/app/src/store/Atoms.tsx | 4 +- 4 files changed, 127 insertions(+), 113 deletions(-) rename lama_cleaner/app/src/components/Settings/{SavePathSettingBlock.tsx => ManualRunInpaintingSettingBlock.tsx} (65%) diff --git a/lama_cleaner/app/src/components/Editor/Editor.tsx b/lama_cleaner/app/src/components/Editor/Editor.tsx index 9db800c..437c6f3 100644 --- a/lama_cleaner/app/src/components/Editor/Editor.tsx +++ b/lama_cleaner/app/src/components/Editor/Editor.tsx @@ -36,9 +36,11 @@ interface Line { pts: { x: number; y: number }[] } +type LineGroup = Array + function drawLines( ctx: CanvasRenderingContext2D, - lines: Line[], + lines: LineGroup, color = BRUSH_COLOR ) { ctx.strokeStyle = color @@ -57,6 +59,11 @@ function drawLines( }) } +function mouseXY(ev: SyntheticEvent) { + const mouseEvent = ev.nativeEvent as MouseEvent + return { x: mouseEvent.offsetX, y: mouseEvent.offsetY } +} + export default function Editor(props: EditorProps) { const { file } = props const settings = useRecoilValue(settingState) @@ -67,9 +74,8 @@ export default function Editor(props: EditorProps) { const [maskCanvas] = useState(() => { return document.createElement('canvas') }) - const [lines, setLines] = useState([{ pts: [] }]) - const [lines4Show, setLines4Show] = useState([{ pts: [] }]) - const [historyLineCount, setHistoryLineCount] = useState([]) + const [lineGroups, setLineGroups] = useState([]) + const [curLineGroup, setCurLineGroup] = useState([]) const [{ x, y }, setCoords] = useState({ x: -1, y: -1 }) const [showBrush, setShowBrush] = useState(false) const [isPanning, setIsPanning] = useState(false) @@ -88,27 +94,22 @@ export default function Editor(props: EditorProps) { const [sliderPos, setSliderPos] = useState(0) - const draw = useCallback(() => { + const draw = (render: HTMLImageElement, lineGroup: LineGroup) => { if (!context) { return } context.clearRect(0, 0, context.canvas.width, context.canvas.height) - const currRender = renders[renders.length - 1] - if (currRender?.src) { - context.drawImage( - currRender, - 0, - 0, - original.naturalWidth, - original.naturalHeight - ) - } else { - context.drawImage(original, 0, 0) - } - drawLines(context, lines4Show) - }, [context, lines4Show, original, renders]) + context.drawImage( + render, + 0, + 0, + original.naturalWidth, + original.naturalHeight + ) + drawLines(context, lineGroup) + } - const refreshCanvasMask = useCallback(() => { + const drawAllLinesOnMask = (_lineGroups: LineGroup[]) => { if (!context?.canvas.width || !context?.canvas.height) { throw new Error('canvas has invalid size') } @@ -119,12 +120,23 @@ export default function Editor(props: EditorProps) { throw new Error('could not retrieve mask canvas') } - drawLines(ctx, lines, 'white') - }, [context?.canvas.height, context?.canvas.width, lines, maskCanvas]) + _lineGroups.forEach(lineGroup => { + drawLines(ctx, lineGroup, 'white') + }) + } - const runInpainting = useCallback(async () => { + const runInpainting = async () => { + if (!hadDrawSomething()) { + return + } + + const newLineGroups = [...lineGroups, curLineGroup] + setLineGroups(newLineGroups) + setCurLineGroup([]) + setIsDraging(false) setIsInpaintingLoading(true) - refreshCanvasMask() + + drawAllLinesOnMask(newLineGroups) try { const res = await inpaint( file, @@ -137,46 +149,35 @@ export default function Editor(props: EditorProps) { } const newRender = new Image() await loadImage(newRender, res) - renders.push(newRender) - lines.push({ pts: [] } as Line) - setRenders([...renders]) - setLines([...lines]) - - historyLineCount.push(lines4Show.length) - setHistoryLineCount(historyLineCount) - lines4Show.length = 0 - setLines4Show([{ pts: [] } as Line]) + const newRenders = [...renders, newRender] + setRenders(newRenders) + draw(newRender, []) } catch (e: any) { // eslint-disable-next-line alert(e.message ? e.message : e.toString()) } setIsInpaintingLoading(false) - draw() - }, [ - draw, - file, - lines, - lines4Show, - maskCanvas, - refreshCanvasMask, - renders, - sizeLimit, - historyLineCount, - settings, - ]) + } const hadDrawSomething = () => { - return lines4Show.length !== 0 && lines4Show[0].pts.length !== 0 + return curLineGroup.length !== 0 } const hadRunInpainting = () => { return renders.length !== 0 } + const drawOnCurrentRender = (lineGroup: LineGroup) => { + if (renders.length === 0) { + draw(original, lineGroup) + } else { + draw(renders[renders.length - 1], lineGroup) + } + } + const clearDrawing = () => { setIsDraging(false) - lines4Show.length = 0 - setLines4Show([{ pts: [] } as Line]) + setCurLineGroup([]) } const handleMultiStrokeKeyDown = () => { @@ -195,7 +196,8 @@ export default function Editor(props: EditorProps) { } setIsMultiStrokeKeyPressed(false) - if (hadDrawSomething()) { + + if (!settings.runInpaintingManually) { runInpainting() } } @@ -241,17 +243,22 @@ export default function Editor(props: EditorProps) { if (context?.canvas) { context.canvas.width = original.naturalWidth context.canvas.height = original.naturalHeight + + context.drawImage( + original, + 0, + 0, + original.naturalWidth, + original.naturalHeight + ) } if (!initialCentered) { viewportRef.current?.centerView(s, 1) setInitialCentered(true) } - - draw() }, [ context?.canvas, - draw, viewportRef, original, isOriginalLoaded, @@ -312,16 +319,6 @@ export default function Editor(props: EditorProps) { ] ) - const onPaint = (px: number, py: number) => { - const currShowLine = lines4Show[lines4Show.length - 1] - currShowLine.pts.push({ x: px, y: py }) - - const currLine = lines[lines.length - 1] - currLine.pts.push({ x: px, y: py }) - - draw() - } - const onMouseMove = (ev: SyntheticEvent) => { const mouseEvent = ev.nativeEvent as MouseEvent setCoords({ x: mouseEvent.pageX, y: mouseEvent.pageY }) @@ -334,10 +331,13 @@ export default function Editor(props: EditorProps) { if (!isDraging) { return } - const mouseEvent = ev.nativeEvent as MouseEvent - const px = mouseEvent.offsetX - const py = mouseEvent.offsetY - onPaint(px, py) + if (curLineGroup.length === 0) { + return + } + const lineGroup = [...curLineGroup] + lineGroup[lineGroup.length - 1].pts.push(mouseXY(ev)) + setCurLineGroup(lineGroup) + drawOnCurrentRender(lineGroup) } const onPointerUp = () => { @@ -357,17 +357,15 @@ export default function Editor(props: EditorProps) { if (!isDraging) { return } - setIsDraging(false) - if (isMultiStrokeKeyPressed) { - lines.push({ pts: [] } as Line) - setLines([...lines]) - lines4Show.push({ pts: [] } as Line) - setLines4Show([...lines4Show]) + if (isMultiStrokeKeyPressed) { + setIsDraging(false) return } - if (lines4Show.length !== 0 && lines4Show[0].pts.length !== 0) { + if (settings.runInpaintingManually) { + setIsDraging(false) + } else { runInpainting() } } @@ -387,36 +385,32 @@ export default function Editor(props: EditorProps) { return } setIsDraging(true) - const currLine4Show = lines4Show[lines4Show.length - 1] - currLine4Show.size = brushSize - const currLine = lines[lines.length - 1] - currLine.size = brushSize - const mouseEvent = ev.nativeEvent as MouseEvent - onPaint(mouseEvent.offsetX, mouseEvent.offsetY) + let lineGroup: LineGroup = [] + if (isMultiStrokeKeyPressed || settings.runInpaintingManually) { + lineGroup = [...curLineGroup] + } + lineGroup.push({ size: brushSize, pts: [mouseXY(ev)] }) + setCurLineGroup(lineGroup) + drawOnCurrentRender(lineGroup) } const undo = () => { if (!renders.length) { return } - if (!historyLineCount.length) { - return + + const groups = lineGroups.slice(0, lineGroups.length - 1) + setLineGroups(groups) + setCurLineGroup([]) + setIsDraging(false) + const newRenders = renders.slice(0, renders.length - 1) + setRenders(newRenders) + if (newRenders.length === 0) { + draw(original, []) + } else { + draw(newRenders[newRenders.length - 1], []) } - - const l = lines - const count = historyLineCount[historyLineCount.length - 1] - for (let i = 0; i <= count; i += 1) { - l.pop() - } - - setLines([...l, { pts: [] }]) - historyLineCount.pop() - setHistoryLineCount(historyLineCount) - - const r = renders - r.pop() - setRenders([...r]) } // Handle Cmd+Z @@ -688,16 +682,37 @@ export default function Editor(props: EditorProps) { }, 350) }} disabled={renders.length === 0} - > - {undefined} - + /> + /> + + {settings.runInpaintingManually && ( +