This commit is contained in:
Haoming 2025-07-28 15:09:29 +08:00
parent 32a5b53ad6
commit 900de67eb8
3 changed files with 56 additions and 75 deletions

View File

@ -22,7 +22,7 @@
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);
linear-gradient(45deg, #eee 25%, transparent 25%, transparent 75%, #eee 75%, #eee);
background-size: 20px 20px;
background-position: 0 0, 10px 10px;
}
@ -149,10 +149,7 @@
padding: 0 4px;
display: flex;
align-items: center;
margin-bottom: 4px; /* Adjust margin as needed */
}
.forge-toolbar-range {
margin-bottom: 4px;
}
.forge-scribble-indicator {
@ -176,4 +173,4 @@
width: 30%;
height: 30%;
transform: translate(-50%, -50%);
}
}

View File

@ -2,39 +2,31 @@
<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">
<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">
<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>
<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="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="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>
@ -45,15 +37,18 @@
</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">
<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">
<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">
<input type="range" id="scribbleSoftness_forge_mixin" class="forge-toolbar-range" min="0" max="100"
value="0">
</div>
</div>
</div>

View File

@ -1,7 +1,17 @@
# Forge Canvas
# AGPL V3
# by lllyasviel
# Commercial Use is not allowed. (Contact us for commercial use.)
"""
Forge Canvas
Copyright (C) 2024 lllyasviel
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
"""
import gradio.component_meta
@ -11,10 +21,10 @@ create_or_modify_pyi_org = gradio.component_meta.create_or_modify_pyi
def create_or_modify_pyi_org_patched(component_class, class_name, events):
try:
if component_class.__name__ == 'LogicalImage':
if component_class.__name__ == "LogicalImage":
return
return create_or_modify_pyi_org(component_class, class_name, events)
except:
except Exception:
return
@ -49,10 +59,10 @@ def web_css(file_name):
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')
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):
@ -60,7 +70,7 @@ def image_to_base64(image_array, numpy=True):
image = image.convert("RGBA")
buffered = BytesIO()
image.save(buffered, format="PNG")
image_base64 = base64.b64encode(buffered.getvalue()).decode('utf-8')
image_base64 = base64.b64encode(buffered.getvalue()).decode("utf-8")
return f"data:image/png;base64,{image_base64}"
@ -80,12 +90,12 @@ class LogicalImage(gr.Textbox):
self.numpy = numpy
self.infotext = dict()
if 'value' in kwargs:
initial_value = kwargs['value']
if "value" in kwargs:
initial_value = kwargs["value"]
if initial_value is not None:
kwargs['value'] = self.image_to_base64(initial_value)
kwargs["value"] = self.image_to_base64(initial_value)
else:
del kwargs['value']
del kwargs["value"]
super().__init__(*args, **kwargs)
@ -97,16 +107,16 @@ class LogicalImage(gr.Textbox):
return None
image = base64_to_image(payload, numpy=self.numpy)
if hasattr(image, 'info'):
if hasattr(image, "info"):
image.info = self.infotext
return image
def postprocess(self, value):
if value is None:
return None
if hasattr(value, 'info'):
if hasattr(value, "info"):
self.infotext = value.info
return image_to_base64(value, numpy=self.numpy)
@ -116,38 +126,17 @@ class LogicalImage(gr.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
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
canvas_html_uuid = canvas_html.replace('forge_mixin', self.uuid)
canvas_html_uuid = canvas_html.replace("forge_mixin", self.uuid)
if opts.forge_canvas_plain:
canvas_html_uuid = canvas_html_uuid.replace('class="forge-image-container"', 'class="forge-image-container-plain"').replace('stroke="white"', 'stroke=#444')
canvas_html_uuid = canvas_html_uuid.replace('class="forge-image-container"', 'class="forge-image-container-plain"').replace('stroke="white"', "stroke=#444")
if opts.forge_canvas_toolbar_always:
canvas_html_uuid = canvas_html_uuid.replace('class="forge-toolbar"', 'class="forge-toolbar-static"')
self.block = gr.HTML(canvas_html_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});}}')
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});}}")