mirror of
https://github.com/easydiffusion/easydiffusion.git
synced 2025-03-30 00:56:06 +01:00
Inpainting editor
This commit is contained in:
parent
5fed14cb78
commit
ef1bbda49c
153
ui/index.html
153
ui/index.html
@ -27,7 +27,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
.image_preview_container {
|
.image_preview_container {
|
||||||
display: none;
|
/* display: none; */
|
||||||
margin-top: 10pt;
|
margin-top: 10pt;
|
||||||
}
|
}
|
||||||
.image_clear_btn {
|
.image_clear_btn {
|
||||||
@ -274,7 +274,24 @@
|
|||||||
height: 23px;
|
height: 23px;
|
||||||
transform: translateY(25%);
|
transform: translateY(25%);
|
||||||
}
|
}
|
||||||
|
#inpaintingEditor {
|
||||||
|
width: 300pt;
|
||||||
|
height: 300pt;
|
||||||
|
margin-top: 5pt;
|
||||||
|
}
|
||||||
|
.drawing-board-canvas-wrapper {
|
||||||
|
background-size: 100% 100%;
|
||||||
|
}
|
||||||
|
#inpaintingEditor canvas {
|
||||||
|
opacity: 0.6;
|
||||||
|
}
|
||||||
|
#enable_mask {
|
||||||
|
margin-top: 8pt;
|
||||||
|
}
|
||||||
</style>
|
</style>
|
||||||
|
<link rel="stylesheet" href="/media/drawingboard.min.css">
|
||||||
|
<script src="/media/jquery-3.6.1.min.js"></script>
|
||||||
|
<script src="/media/drawingboard.min.js"></script>
|
||||||
</html>
|
</html>
|
||||||
<body>
|
<body>
|
||||||
<div id="container">
|
<div id="container">
|
||||||
@ -295,17 +312,14 @@
|
|||||||
|
|
||||||
<div id="editor-inputs-init-image" class="row">
|
<div id="editor-inputs-init-image" class="row">
|
||||||
<label for="init_image"><b>Initial Image:</b> (optional) </label> <input id="init_image" name="init_image" type="file" /><br/>
|
<label for="init_image"><b>Initial Image:</b> (optional) </label> <input id="init_image" name="init_image" type="file" /><br/>
|
||||||
|
|
||||||
<div id="init_image_preview_container" class="image_preview_container">
|
<div id="init_image_preview_container" class="image_preview_container">
|
||||||
<img id="init_image_preview" src="" width="100" height="100" />
|
<img id="init_image_preview" src="" width="100" height="100" />
|
||||||
<button id="init_image_clear" class="image_clear_btn">X</button>
|
<button class="init_image_clear image_clear_btn">X</button>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div id="editor-inputs-mask_setting">
|
<br/>
|
||||||
<label for="mask"><b>Image Mask:</b> (optional) </label> <input id="mask" name="mask" type="file" /><br/>
|
<input id="enable_mask" name="enable_mask" type="checkbox"> <label for="enable_mask">In-Painting (select the area which the AI will paint into)</label>
|
||||||
<div id="mask_preview_container" class="image_preview_container">
|
<div id="inpaintingEditor"></div>
|
||||||
<img id="mask_preview" src="" width="100" height="100" />
|
|
||||||
<button id="mask_clear" class="image_clear_btn">X</button>
|
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
@ -484,12 +498,13 @@ let stopImageBtn = document.querySelector('#stopImage')
|
|||||||
|
|
||||||
let imagesContainer = document.querySelector('#current-images')
|
let imagesContainer = document.querySelector('#current-images')
|
||||||
let initImagePreviewContainer = document.querySelector('#init_image_preview_container')
|
let initImagePreviewContainer = document.querySelector('#init_image_preview_container')
|
||||||
let initImageClearBtn = document.querySelector('#init_image_clear')
|
let initImageClearBtn = document.querySelector('.init_image_clear')
|
||||||
let promptStrengthContainer = document.querySelector('#prompt_strength_container')
|
let promptStrengthContainer = document.querySelector('#prompt_strength_container')
|
||||||
|
|
||||||
let maskSetting = document.querySelector('#editor-inputs-mask_setting')
|
// let maskSetting = document.querySelector('#editor-inputs-mask_setting')
|
||||||
let maskImagePreviewContainer = document.querySelector('#mask_preview_container')
|
// let maskImagePreviewContainer = document.querySelector('#mask_preview_container')
|
||||||
let maskImageClearBtn = document.querySelector('#mask_clear')
|
// let maskImageClearBtn = document.querySelector('#mask_clear')
|
||||||
|
let maskSetting = document.querySelector('#enable_mask')
|
||||||
|
|
||||||
let editorModifierEntries = document.querySelector('#editor-modifiers-entries')
|
let editorModifierEntries = document.querySelector('#editor-modifiers-entries')
|
||||||
let editorModifierTagsList = document.querySelector('#editor-inputs-tags-list')
|
let editorModifierTagsList = document.querySelector('#editor-inputs-tags-list')
|
||||||
@ -509,6 +524,29 @@ let serverStatusMsg = document.querySelector('#server-status-msg')
|
|||||||
|
|
||||||
let advancedPanelHandle = document.querySelector("#editor-settings .collapsible")
|
let advancedPanelHandle = document.querySelector("#editor-settings .collapsible")
|
||||||
let modifiersPanelHandle = document.querySelector("#editor-modifiers .collapsible")
|
let modifiersPanelHandle = document.querySelector("#editor-modifiers .collapsible")
|
||||||
|
let inpaintingEditorContainer = document.querySelector('#inpaintingEditor')
|
||||||
|
let inpaintingEditor = new DrawingBoard.Board('inpaintingEditor', {
|
||||||
|
color: "#ffffff",
|
||||||
|
background: false,
|
||||||
|
size: 30,
|
||||||
|
webStorage: false,
|
||||||
|
controls: [{'DrawingMode': {'filler': false}}, 'Size', 'Navigation']
|
||||||
|
})
|
||||||
|
let inpaintingEditorCanvasBackground = document.querySelector('.drawing-board-canvas-wrapper')
|
||||||
|
// let inpaintingEditorControls = document.querySelector('.drawing-board-controls')
|
||||||
|
|
||||||
|
// let inpaintingEditorMetaControl = document.createElement('div')
|
||||||
|
// inpaintingEditorMetaControl.className = 'drawing-board-control'
|
||||||
|
// let initImageClearBtnToolbar = document.createElement('button')
|
||||||
|
// initImageClearBtnToolbar.className = 'init_image_clear'
|
||||||
|
// initImageClearBtnToolbar.innerHTML = 'Remove Image'
|
||||||
|
// inpaintingEditorMetaControl.appendChild(initImageClearBtnToolbar)
|
||||||
|
// inpaintingEditorControls.appendChild(inpaintingEditorMetaControl)
|
||||||
|
|
||||||
|
let maskResetButton = document.querySelector('.drawing-board-control-navigation-reset')
|
||||||
|
maskResetButton.innerHTML = 'Clear'
|
||||||
|
maskResetButton.style.fontWeight = 'normal'
|
||||||
|
maskResetButton.style.fontSize = '10pt'
|
||||||
|
|
||||||
let serverStatus = 'offline'
|
let serverStatus = 'offline'
|
||||||
let activeTags = []
|
let activeTags = []
|
||||||
@ -850,9 +888,11 @@ async function doMakeImage(reqBody, batchCount) {
|
|||||||
initImagePreview.src = imgBody
|
initImagePreview.src = imgBody
|
||||||
|
|
||||||
initImagePreviewContainer.style.display = 'block'
|
initImagePreviewContainer.style.display = 'block'
|
||||||
|
inpaintingEditorContainer.style.display = 'none'
|
||||||
promptStrengthContainer.style.display = 'block'
|
promptStrengthContainer.style.display = 'block'
|
||||||
|
maskSetting.checked = false
|
||||||
|
|
||||||
maskSetting.style.display = 'block'
|
// maskSetting.style.display = 'block'
|
||||||
|
|
||||||
randomSeedField.checked = false
|
randomSeedField.checked = false
|
||||||
seedField.value = seed
|
seedField.value = seed
|
||||||
@ -957,8 +997,11 @@ async function makeImage() {
|
|||||||
reqBody['init_image'] = initImagePreview.src
|
reqBody['init_image'] = initImagePreview.src
|
||||||
reqBody['prompt_strength'] = promptStrengthField.value
|
reqBody['prompt_strength'] = promptStrengthField.value
|
||||||
|
|
||||||
if (IMAGE_REGEX.test(maskImagePreview.src)) {
|
// if (IMAGE_REGEX.test(maskImagePreview.src)) {
|
||||||
reqBody['mask'] = maskImagePreview.src
|
// reqBody['mask'] = maskImagePreview.src
|
||||||
|
// }
|
||||||
|
if (maskSetting.checked) {
|
||||||
|
reqBody['mask'] = inpaintingEditor.getImg()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1217,8 +1260,9 @@ checkRandomSeed()
|
|||||||
function showInitImagePreview() {
|
function showInitImagePreview() {
|
||||||
if (initImageSelector.files.length === 0) {
|
if (initImageSelector.files.length === 0) {
|
||||||
initImagePreviewContainer.style.display = 'none'
|
initImagePreviewContainer.style.display = 'none'
|
||||||
|
// inpaintingEditorContainer.style.display = 'none'
|
||||||
promptStrengthContainer.style.display = 'none'
|
promptStrengthContainer.style.display = 'none'
|
||||||
maskSetting.style.display = 'none'
|
// maskSetting.style.display = 'none'
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1229,9 +1273,9 @@ function showInitImagePreview() {
|
|||||||
// console.log(file.name, reader.result)
|
// console.log(file.name, reader.result)
|
||||||
initImagePreview.src = reader.result
|
initImagePreview.src = reader.result
|
||||||
initImagePreviewContainer.style.display = 'block'
|
initImagePreviewContainer.style.display = 'block'
|
||||||
|
inpaintingEditorContainer.style.display = 'none'
|
||||||
promptStrengthContainer.style.display = 'block'
|
promptStrengthContainer.style.display = 'block'
|
||||||
|
// maskSetting.checked = false
|
||||||
maskSetting.style.display = 'block'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
if (file) {
|
if (file) {
|
||||||
@ -1241,48 +1285,60 @@ function showInitImagePreview() {
|
|||||||
initImageSelector.addEventListener('change', showInitImagePreview)
|
initImageSelector.addEventListener('change', showInitImagePreview)
|
||||||
showInitImagePreview()
|
showInitImagePreview()
|
||||||
|
|
||||||
|
initImagePreview.addEventListener('load', function() {
|
||||||
|
inpaintingEditorCanvasBackground.style.backgroundImage = "url('" + this.src + "')"
|
||||||
|
// maskSetting.style.display = 'block'
|
||||||
|
// inpaintingEditorContainer.style.display = 'block'
|
||||||
|
})
|
||||||
|
|
||||||
initImageClearBtn.addEventListener('click', function() {
|
initImageClearBtn.addEventListener('click', function() {
|
||||||
initImageSelector.value = null
|
initImageSelector.value = null
|
||||||
maskImageSelector.value = null
|
// maskImageSelector.value = null
|
||||||
|
|
||||||
initImagePreview.src = ''
|
initImagePreview.src = ''
|
||||||
maskImagePreview.src = ''
|
// maskImagePreview.src = ''
|
||||||
|
maskSetting.checked = false
|
||||||
|
|
||||||
initImagePreviewContainer.style.display = 'none'
|
initImagePreviewContainer.style.display = 'none'
|
||||||
maskImagePreviewContainer.style.display = 'none'
|
// inpaintingEditorContainer.style.display = 'none'
|
||||||
|
// maskImagePreviewContainer.style.display = 'none'
|
||||||
|
|
||||||
maskSetting.style.display = 'none'
|
// maskSetting.style.display = 'none'
|
||||||
|
|
||||||
promptStrengthContainer.style.display = 'none'
|
promptStrengthContainer.style.display = 'none'
|
||||||
})
|
})
|
||||||
|
|
||||||
function showMaskImagePreview() {
|
maskSetting.addEventListener('click', function() {
|
||||||
if (maskImageSelector.files.length === 0) {
|
inpaintingEditorContainer.style.display = (this.checked ? 'block' : 'none')
|
||||||
maskImagePreviewContainer.style.display = 'none'
|
|
||||||
return
|
|
||||||
}
|
|
||||||
|
|
||||||
let reader = new FileReader()
|
|
||||||
let file = maskImageSelector.files[0]
|
|
||||||
|
|
||||||
reader.addEventListener('load', function() {
|
|
||||||
maskImagePreview.src = reader.result
|
|
||||||
maskImagePreviewContainer.style.display = 'block'
|
|
||||||
})
|
|
||||||
|
|
||||||
if (file) {
|
|
||||||
reader.readAsDataURL(file)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
maskImageSelector.addEventListener('change', showMaskImagePreview)
|
|
||||||
showMaskImagePreview()
|
|
||||||
|
|
||||||
maskImageClearBtn.addEventListener('click', function() {
|
|
||||||
maskImageSelector.value = null
|
|
||||||
maskImagePreview.src = ''
|
|
||||||
maskImagePreviewContainer.style.display = 'none'
|
|
||||||
})
|
})
|
||||||
|
|
||||||
|
// function showMaskImagePreview() {
|
||||||
|
// if (maskImageSelector.files.length === 0) {
|
||||||
|
// // maskImagePreviewContainer.style.display = 'none'
|
||||||
|
// return
|
||||||
|
// }
|
||||||
|
|
||||||
|
// let reader = new FileReader()
|
||||||
|
// let file = maskImageSelector.files[0]
|
||||||
|
|
||||||
|
// reader.addEventListener('load', function() {
|
||||||
|
// // maskImagePreview.src = reader.result
|
||||||
|
// // maskImagePreviewContainer.style.display = 'block'
|
||||||
|
// })
|
||||||
|
|
||||||
|
// if (file) {
|
||||||
|
// reader.readAsDataURL(file)
|
||||||
|
// }
|
||||||
|
// }
|
||||||
|
// maskImageSelector.addEventListener('change', showMaskImagePreview)
|
||||||
|
// showMaskImagePreview()
|
||||||
|
|
||||||
|
// maskImageClearBtn.addEventListener('click', function() {
|
||||||
|
// maskImageSelector.value = null
|
||||||
|
// maskImagePreview.src = ''
|
||||||
|
// // maskImagePreviewContainer.style.display = 'none'
|
||||||
|
// })
|
||||||
|
|
||||||
// https://stackoverflow.com/a/8212878
|
// https://stackoverflow.com/a/8212878
|
||||||
function millisecondsToStr(milliseconds) {
|
function millisecondsToStr(milliseconds) {
|
||||||
function numberEnding (number) {
|
function numberEnding (number) {
|
||||||
@ -1464,5 +1520,4 @@ async function init() {
|
|||||||
|
|
||||||
init()
|
init()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
</html>
|
</html>
|
||||||
|
5
ui/media/drawingboard.min.css
vendored
Normal file
5
ui/media/drawingboard.min.css
vendored
Normal file
File diff suppressed because one or more lines are too long
4
ui/media/drawingboard.min.js
vendored
Normal file
4
ui/media/drawingboard.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
2
ui/media/jquery-3.6.1.min.js
vendored
Normal file
2
ui/media/jquery-3.6.1.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
11
ui/server.py
11
ui/server.py
@ -15,6 +15,7 @@ CONFIG_DIR = os.path.join(SD_UI_DIR, '..', 'scripts')
|
|||||||
OUTPUT_DIRNAME = "Stable Diffusion UI" # in the user's home folder
|
OUTPUT_DIRNAME = "Stable Diffusion UI" # in the user's home folder
|
||||||
|
|
||||||
from fastapi import FastAPI, HTTPException
|
from fastapi import FastAPI, HTTPException
|
||||||
|
from fastapi.staticfiles import StaticFiles
|
||||||
from starlette.responses import FileResponse, StreamingResponse
|
from starlette.responses import FileResponse, StreamingResponse
|
||||||
from pydantic import BaseModel
|
from pydantic import BaseModel
|
||||||
import logging
|
import logging
|
||||||
@ -57,6 +58,8 @@ class ImageRequest(BaseModel):
|
|||||||
class SetAppConfigRequest(BaseModel):
|
class SetAppConfigRequest(BaseModel):
|
||||||
update_branch: str = "main"
|
update_branch: str = "main"
|
||||||
|
|
||||||
|
app.mount('/media', StaticFiles(directory=os.path.join(SD_UI_DIR, 'media/')), name="media")
|
||||||
|
|
||||||
@app.get('/')
|
@app.get('/')
|
||||||
def read_root():
|
def read_root():
|
||||||
headers = {"Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0"}
|
headers = {"Cache-Control": "no-cache, no-store, must-revalidate", "Pragma": "no-cache", "Expires": "0"}
|
||||||
@ -191,14 +194,6 @@ def getAppConfig():
|
|||||||
print(traceback.format_exc())
|
print(traceback.format_exc())
|
||||||
return HTTPException(status_code=500, detail=str(e))
|
return HTTPException(status_code=500, detail=str(e))
|
||||||
|
|
||||||
@app.get('/media/ding.mp3')
|
|
||||||
def read_ding():
|
|
||||||
return FileResponse(os.path.join(SD_UI_DIR, 'media/ding.mp3'))
|
|
||||||
|
|
||||||
@app.get('/media/kofi.png')
|
|
||||||
def read_modifiers():
|
|
||||||
return FileResponse(os.path.join(SD_UI_DIR, 'media/kofi.png'))
|
|
||||||
|
|
||||||
@app.get('/modifiers.json')
|
@app.get('/modifiers.json')
|
||||||
def read_modifiers():
|
def read_modifiers():
|
||||||
return FileResponse(os.path.join(SD_UI_DIR, 'modifiers.json'))
|
return FileResponse(os.path.join(SD_UI_DIR, 'modifiers.json'))
|
||||||
|
Loading…
Reference in New Issue
Block a user