Gradio 4 + WebUI 1.10

This commit is contained in:
layerdiffusion
2024-07-26 08:51:34 -07:00
parent e95333c556
commit e26abf87ec
201 changed files with 7562 additions and 4834 deletions

View File

@@ -0,0 +1,159 @@
.forge-container {
width: 100%;
height: 512px;
position: relative;
overflow: hidden;
}
.forge-image-container {
width: 100%;
height: calc(100% - 6px);
position: relative;
overflow: hidden;
background-color: #cccccc;
background-image: linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee),
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 20px 20px;
background-position: 0 0, 10px 10px;
}
.forge-image {
position: absolute;
top: 0;
left: 0;
background-size: contain;
background-repeat: no-repeat;
cursor: grab;
max-width: unset !important;
max-height: unset !important;
}
.forge-image:active {
cursor: grabbing;
}
.forge-file-upload {
display: none;
}
.forge-resize-line {
width: 100%;
height: 6px;
background-image: linear-gradient(to bottom, grey 50%, darkgrey 50%);
background-size: 4px 4px;
background-repeat: repeat;
cursor: ns-resize;
position: absolute;
bottom: 0;
left: 0;
}
.forge-toolbar {
position: absolute;
top: 0px;
left: 0px;
z-index: 10;
background: rgba(47, 47, 47, 0.8);
padding: 6px 10px;
opacity: 0;
transition: opacity 0.3s ease;
}
.forge-toolbar .forge-btn {
padding: 2px 6px;
border: none;
background-color: #4a4a4a;
color: white;
font-size: 14px;
cursor: pointer;
transition: background-color 0.3s ease;
}
.forge-toolbar .forge-btn:hover {
background-color: #5e5e5e;
}
.forge-toolbar .forge-btn:active {
background-color: #3e3e3e;
}
.forge-toolbar-box-a {
flex-wrap: wrap;
}
.forge-toolbar-box-b {
display: flex;
flex-wrap: wrap;
align-items: center;
justify-content: space-between;
gap: 4px;
}
.forge-color-picker-block {
display: flex;
align-items: center;
}
.forge-range-row {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.forge-toolbar-color {
border: none;
background: none;
padding: 3px;
border-radius: 50%;
width: 20px;
height: 20px;
-webkit-appearance: none;
appearance: none;
cursor: pointer;
}
.forge-toolbar-color::-webkit-color-swatch-wrapper {
padding: 0;
border-radius: 50%;
}
.forge-toolbar-color::-webkit-color-swatch {
border: none;
border-radius: 50%;
background: none;
}
.forge-toolbar-label {
color: white !important;
padding: 0 4px;
display: flex;
align-items: center;
margin-bottom: 4px; /* Adjust margin as needed */
}
.forge-toolbar-range {
}
.forge-scribble-indicator {
position: relative;
border-radius: 50%;
border: 1px solid;
pointer-events: none;
display: none;
width: 80px;
height: 80px;
}
.forge-no-select {
user-select: none;
}
.forge-upload-hint {
position: absolute;
top: 50%;
left: 50%;
width: 30%;
height: 30%;
transform: translate(-50%, -50%);
}

View File

@@ -0,0 +1,63 @@
<div class="forge-container" id="container_forge_mixin">
<input type="file" id="imageInput_forge_mixin" class="forge-file-upload">
<div id="imageContainer_forge_mixin" class="forge-image-container">
<div id="uploadHint_forge_mixin">
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="none"
stroke="white"
stroke-width="4"
stroke-linecap="round"
stroke-linejoin="round"
class="forge-upload-hint">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="17 8 12 3 7 8"></polyline>
<line x1="12" y1="3" x2="12" y2="15"></line>
</svg>
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24" fill="none"
stroke="grey"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="forge-upload-hint">
<path d="M21 15v4a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2v-4"></path>
<polyline points="17 8 12 3 7 8"></polyline>
<line x1="12" y1="3" x2="12" y2="15"></line>
</svg>
</div>
<img id="image_forge_mixin" class="forge-image forge-no-select">
<canvas id="drawingCanvas_forge_mixin" class="forge-drawing-canvas"
style="position:absolute;top:0;left:0;" width="1" height="1"></canvas>
<div class="forge-toolbar" id="toolbar_forge_mixin">
<div class="forge-toolbar-box-a">
<button id="maxButton_forge_mixin" class="forge-btn forge-no-select" title="Maximize"></button>
<button id="minButton_forge_mixin" class="forge-btn forge-no-select" title="Minimize" style="display: none;"></button>
<button id="uploadButton_forge_mixin" class="forge-btn forge-no-select" title="Upload">📂</button>
<button id="removeButton_forge_mixin" class="forge-btn forge-no-select" title="Remove">🗑️</button>
<button id="centerButton_forge_mixin" class="forge-btn forge-no-select" title="Center Position"></button>
<button id="resetButton_forge_mixin" class="forge-btn forge-no-select" title="Reset">🔄</button>
<button id="undoButton_forge_mixin" class="forge-btn forge-no-select" title="Undo">↩️</button>
<button id="redoButton_forge_mixin" class="forge-btn forge-no-select" title="Redo">↪️</button>
</div>
<div class="forge-toolbar-box-b">
<div class="forge-color-picker-block" id="scribbleColorBlock_forge_mixin">
<input type="color" id="scribbleColor_forge_mixin" class="forge-toolbar-color" value="#000000">
</div>
<div class="forge-range-row" id="scribbleWidthBlock_forge_mixin">
<div id="widthLabel_forge_mixin" class="forge-toolbar-label">brush width</div>
<input type="range" id="scribbleWidth_forge_mixin" class="forge-toolbar-range" min="1" max="20" value="4">
</div>
<div class="forge-range-row" id="scribbleAlphaBlock_forge_mixin">
<div id="alphaLabel_forge_mixin" class="forge-toolbar-label">brush opacity</div>
<input type="range" id="scribbleAlpha_forge_mixin" class="forge-toolbar-range" min="0" max="100" value="100">
</div>
<div class="forge-range-row" id="scribbleSoftnessBlock_forge_mixin">
<div id="softnessLabel_forge_mixin" class="forge-toolbar-label">brush softness</div>
<input type="range" id="scribbleSoftness_forge_mixin" class="forge-toolbar-range" min="0" max="100" value="0">
</div>
</div>
</div>
<div id="scribbleIndicator_forge_mixin" class="forge-scribble-indicator"></div>
</div>
<div class="forge-resize-line" id="resizeLine_forge_mixin"></div>
</div>

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,120 @@
# Forge Canvas
# AGPL V3
# by lllyasviel
# Commercial Use is not allowed. (Contact us for commercial use.)
import os
import uuid
import base64
import gradio as gr
import numpy as np
from PIL import Image
from io import BytesIO
from gradio.context import Context
from functools import wraps
from modules.ui_components import FormComponent
canvas_js_root_path = os.path.dirname(__file__)
def web_js(file_name):
full_path = os.path.join(canvas_js_root_path, file_name)
return f'<script src="file={full_path}?{os.path.getmtime(full_path)}"></script>\n'
def web_css(file_name):
full_path = os.path.join(canvas_js_root_path, file_name)
return f'<link rel="stylesheet" href="file={full_path}?{os.path.getmtime(full_path)}">\n'
DEBUG_MODE = False
canvas_html = open(os.path.join(canvas_js_root_path, 'canvas.html'), encoding='utf-8').read()
canvas_head = ''
canvas_head += web_css('canvas.css')
canvas_head += web_js('canvas.min.js')
def image_to_base64(image_array, numpy=True):
image = Image.fromarray(image_array) if numpy else image_array
image = image.convert("RGBA")
buffered = BytesIO()
image.save(buffered, format="PNG")
image_base64 = base64.b64encode(buffered.getvalue()).decode('utf-8')
return f"data:image/png;base64,{image_base64}"
def base64_to_image(base64_str, numpy=True):
if base64_str.startswith("data:image/png;base64,"):
base64_str = base64_str.replace("data:image/png;base64,", "")
image_data = base64.b64decode(base64_str)
image = Image.open(BytesIO(image_data))
image = image.convert("RGBA")
image_array = np.array(image) if numpy else image
return image_array
class LogicalImage(gr.Textbox, FormComponent):
@wraps(gr.Textbox.__init__)
def __init__(self, *args, numpy=True, **kwargs):
self.numpy = numpy
if 'value' in kwargs:
initial_value = kwargs['value']
if initial_value is not None:
kwargs['value'] = self.image_to_base64(initial_value)
else:
del kwargs['value']
super().__init__(*args, **kwargs)
def preprocess(self, payload):
if not isinstance(payload, str):
return None
if not payload.startswith("data:image/png;base64,"):
return None
return base64_to_image(payload, numpy=self.numpy)
def postprocess(self, value):
if value is None:
return None
return image_to_base64(value, numpy=self.numpy)
def get_block_name(self):
return "textbox"
class ForgeCanvas:
def __init__(
self,
no_upload=False,
no_scribbles=False,
contrast_scribbles=False,
height=512,
scribble_color='#000000',
scribble_color_fixed=False,
scribble_width=4,
scribble_width_fixed=False,
scribble_alpha=100,
scribble_alpha_fixed=False,
scribble_softness=0,
scribble_softness_fixed=False,
visible=True,
numpy=False,
initial_image=None,
elem_id=None,
elem_classes=None
):
self.uuid = 'uuid_' + uuid.uuid4().hex
self.block = gr.HTML(canvas_html.replace('forge_mixin', self.uuid), visible=visible, elem_id=elem_id, elem_classes=elem_classes)
self.foreground = LogicalImage(visible=DEBUG_MODE, label='foreground', numpy=numpy, elem_id=self.uuid, elem_classes=['logical_image_foreground'])
self.background = LogicalImage(visible=DEBUG_MODE, label='background', numpy=numpy, value=initial_image, elem_id=self.uuid, elem_classes=['logical_image_background'])
Context.root_block.load(None, js=f'async ()=>{{new ForgeCanvas("{self.uuid}", {no_upload}, {no_scribbles}, {contrast_scribbles}, {height}, '
f"'{scribble_color}', {scribble_color_fixed}, {scribble_width}, {scribble_width_fixed}, "
f'{scribble_alpha}, {scribble_alpha_fixed}, {scribble_softness}, {scribble_softness_fixed});}}')