From 780517b91abe2e8c484d15f6755013b81a3abd92 Mon Sep 17 00:00:00 2001 From: Qing Date: Fri, 27 Jan 2023 20:12:04 +0800 Subject: [PATCH] add generate gif button --- lama_cleaner/app/src/adapters/inpainting.ts | 33 ++++- .../src/components/CoffeeIcon/CoffeeIcon.tsx | 1 - .../app/src/components/Editor/Editor.scss | 6 +- .../app/src/components/Editor/Editor.tsx | 12 +- .../app/src/components/Editor/MakeGIF.tsx | 114 ++++++++++++++++++ .../src/components/Settings/SettingIcon.tsx | 25 +--- .../app/src/components/shared/Toast.tsx | 2 +- lama_cleaner/app/src/store/Atoms.tsx | 14 +++ lama_cleaner/make_gif.py | 2 + lama_cleaner/server.py | 21 ++++ 10 files changed, 196 insertions(+), 34 deletions(-) create mode 100644 lama_cleaner/app/src/components/Editor/MakeGIF.tsx diff --git a/lama_cleaner/app/src/adapters/inpainting.ts b/lama_cleaner/app/src/adapters/inpainting.ts index 74d0656..b94aa17 100644 --- a/lama_cleaner/app/src/adapters/inpainting.ts +++ b/lama_cleaner/app/src/adapters/inpainting.ts @@ -1,5 +1,5 @@ import { Rect, Settings } from '../store/Atoms' -import { dataURItoBlob, srcToFile } from '../utils' +import { dataURItoBlob, loadImage, srcToFile } from '../utils' export const API_ENDPOINT = `${process.env.REACT_APP_INPAINTING_URL}` @@ -223,3 +223,34 @@ export async function downloadToOutput( throw new Error(`Something went wrong: ${error}`) } } + +export async function makeGif( + originFile: File, + cleanImage: HTMLImageElement, + filename: string, + mimeType: string +) { + const cleanFile = await srcToFile(cleanImage.src, filename, mimeType) + const fd = new FormData() + fd.append('origin_img', originFile) + fd.append('clean_img', cleanFile) + fd.append('filename', filename) + + try { + const res = await fetch(`${API_ENDPOINT}/make_gif`, { + method: 'POST', + body: fd, + }) + if (!res.ok) { + const errMsg = await res.text() + throw new Error(errMsg) + } + + const blob = await res.blob() + const newImage = new Image() + await loadImage(newImage, URL.createObjectURL(blob)) + return newImage + } catch (error) { + throw new Error(`Something went wrong: ${error}`) + } +} diff --git a/lama_cleaner/app/src/components/CoffeeIcon/CoffeeIcon.tsx b/lama_cleaner/app/src/components/CoffeeIcon/CoffeeIcon.tsx index 9f48437..ecc6d2d 100644 --- a/lama_cleaner/app/src/components/CoffeeIcon/CoffeeIcon.tsx +++ b/lama_cleaner/app/src/components/CoffeeIcon/CoffeeIcon.tsx @@ -70,7 +70,6 @@ const CoffeeIcon = () => { }} > Sure - diff --git a/lama_cleaner/app/src/components/Editor/Editor.scss b/lama_cleaner/app/src/components/Editor/Editor.scss index cc33847..89ce2ed 100644 --- a/lama_cleaner/app/src/components/Editor/Editor.scss +++ b/lama_cleaner/app/src/components/Editor/Editor.scss @@ -95,10 +95,8 @@ } .editor-toolkit-btns { - grid-area: toolkit-btns; - display: grid; - grid-auto-flow: column; - column-gap: 1rem; + display: flex; + gap: 12px; } .brush-shape { diff --git a/lama_cleaner/app/src/components/Editor/Editor.tsx b/lama_cleaner/app/src/components/Editor/Editor.tsx index e23b1db..4b34819 100644 --- a/lama_cleaner/app/src/components/Editor/Editor.tsx +++ b/lama_cleaner/app/src/components/Editor/Editor.tsx @@ -16,10 +16,11 @@ import { TransformComponent, TransformWrapper, } from 'react-zoom-pan-pinch' -import { useRecoilState, useRecoilValue } from 'recoil' +import { useRecoilState, useRecoilValue, useSetRecoilState } from 'recoil' import { useWindowSize, useKey, useKeyPressEvent } from 'react-use' import inpaint, { downloadToOutput, + makeGif, postInteractiveSeg, } from '../../adapters/inpainting' import Button from '../shared/Button' @@ -40,6 +41,7 @@ import { croperState, enableFileManagerState, fileState, + gifImageState, imageHeightState, imageWidthState, interactiveSegClicksState, @@ -66,6 +68,7 @@ import FileSelect from '../FileSelect/FileSelect' import InteractiveSeg from '../InteractiveSeg/InteractiveSeg' import InteractiveSegConfirmActions from '../InteractiveSeg/ConfirmActions' import InteractiveSegReplaceModal from '../InteractiveSeg/ReplaceModal' +import MakeGIF from './MakeGIF' const TOOLBAR_SIZE = 200 const MIN_BRUSH_SIZE = 10 @@ -112,7 +115,7 @@ export default function Editor() { const settings = useRecoilValue(settingState) const [seedVal, setSeed] = useRecoilState(seedState) const croperRect = useRecoilValue(croperState) - const [toastVal, setToastState] = useRecoilState(toastState) + const setToastState = useSetRecoilState(toastState) const [isInpainting, setIsInpainting] = useRecoilState(isInpaintingState) const runMannually = useRecoilValue(runManuallyState) const isSD = useRecoilValue(isSDState) @@ -181,8 +184,8 @@ export default function Editor() { const [redoLineGroups, setRedoLineGroups] = useState([]) const enableFileManager = useRecoilValue(enableFileManagerState) - const [imageWidth, setImageWidth] = useRecoilState(imageWidthState) - const [imageHeight, setImageHeight] = useRecoilState(imageHeightState) + const setImageWidth = useSetRecoilState(imageWidthState) + const setImageHeight = useSetRecoilState(imageHeightState) const app = useRecoilValue(appState) const draw = useCallback( @@ -1534,6 +1537,7 @@ export default function Editor() { }} disabled={renders.length === 0} /> + + + )} + + + + ) +} + +export default MakeGIF diff --git a/lama_cleaner/app/src/components/Settings/SettingIcon.tsx b/lama_cleaner/app/src/components/Settings/SettingIcon.tsx index 70b80cf..20cf4af 100644 --- a/lama_cleaner/app/src/components/Settings/SettingIcon.tsx +++ b/lama_cleaner/app/src/components/Settings/SettingIcon.tsx @@ -1,5 +1,6 @@ import React from 'react' import { useRecoilState } from 'recoil' +import { Cog6ToothIcon } from '@heroicons/react/24/outline' import { settingState } from '../../store/Atoms' import Button from '../shared/Button' @@ -16,29 +17,7 @@ const SettingIcon = () => { onClick={onClick} toolTip="Settings" style={{ border: 0 }} - icon={ - - - - - } + icon={} /> ) diff --git a/lama_cleaner/app/src/components/shared/Toast.tsx b/lama_cleaner/app/src/components/shared/Toast.tsx index e12d928..6d5f313 100644 --- a/lama_cleaner/app/src/components/shared/Toast.tsx +++ b/lama_cleaner/app/src/components/shared/Toast.tsx @@ -3,7 +3,7 @@ import * as ToastPrimitive from '@radix-ui/react-toast' import { ToastProps } from '@radix-ui/react-toast' import { CheckIcon, ExclamationCircleIcon } from '@heroicons/react/24/outline' -const LoadingIcon = () => { +export const LoadingIcon = () => { return ( ({ @@ -61,6 +62,7 @@ export const appState = atom({ interactiveSegClicks: [], showFileManager: false, enableFileManager: false, + gifImage: undefined, }, }) @@ -134,6 +136,18 @@ export const enableFileManagerState = selector({ }, }) +export const gifImageState = selector({ + key: 'gifImageState', + get: ({ get }) => { + const app = get(appState) + return app.gifImage + }, + set: ({ get, set }, newValue: any) => { + const app = get(appState) + set(appState, { ...app, gifImage: newValue }) + }, +}) + export const fileState = selector({ key: 'fileState', get: ({ get }) => { diff --git a/lama_cleaner/make_gif.py b/lama_cleaner/make_gif.py index 64d345a..342a1af 100644 --- a/lama_cleaner/make_gif.py +++ b/lama_cleaner/make_gif.py @@ -69,6 +69,8 @@ def make_compare_gif( cubic_bezier_points = cubic_bezier((0.33, 0), (0.66, 1), 1, num_frames) cubic_bezier_points.reverse() + max_side_length = min(max_side_length, max(clean_img.size)) + src_img = keep_ratio_resize(src_img, max_side_length) clean_img = keep_ratio_resize(clean_img, max_side_length) width, height = src_img.size diff --git a/lama_cleaner/server.py b/lama_cleaner/server.py index 5a3e3b0..2f7be75 100644 --- a/lama_cleaner/server.py +++ b/lama_cleaner/server.py @@ -19,6 +19,7 @@ from loguru import logger from watchdog.events import FileSystemEventHandler from lama_cleaner.interactive_seg import InteractiveSeg, Click +from lama_cleaner.make_gif import make_compare_gif from lama_cleaner.model_manager import ModelManager from lama_cleaner.schema import Config from lama_cleaner.file_manager import FileManager @@ -93,6 +94,26 @@ def diffuser_callback(i, t, latents): # socketio.emit('diffusion_step', {'diffusion_step': step}) +@app.route("/make_gif", methods=["POST"]) +def make_gif(): + input = request.files + filename = request.form["filename"] + origin_image_bytes = input["origin_img"].read() + clean_image_bytes = input["clean_img"].read() + origin_image, _ = load_img(origin_image_bytes) + clean_image, _ = load_img(clean_image_bytes) + gif_bytes = make_compare_gif( + Image.fromarray(origin_image), + Image.fromarray(clean_image) + ) + return send_file( + io.BytesIO(gif_bytes), + mimetype='image/gif', + as_attachment=True, + attachment_filename=filename + ) + + @app.route("/save_image", methods=["POST"]) def save_image(): # all image in output directory