Spaces:
Runtime error
Runtime error
jiangchen16
commited on
Commit
·
3c3804b
1
Parent(s):
0cb5e75
initial commit
Browse filesThis view is limited to 50 files because it contains too many changes.
See raw diff
- .gitattributes +1 -0
- README.md +4 -5
- app.py +261 -0
- css/style.css +157 -0
- font/Alice.ttf +3 -0
- font/Aoyagireisyosimo.ttf +3 -0
- font/Automatons.ttf +3 -0
- font/BebasNeue.ttf +3 -0
- font/Caveat.ttf +3 -0
- font/ChosunGs.ttf +3 -0
- font/Dongle.ttf +3 -0
- font/Filthyrich.ttf +3 -0
- font/GlTsukiji.ttf +3 -0
- font/Gloock.ttf +3 -0
- font/GodoMaum.ttf +3 -0
- font/KouzanMouhitu.ttf +3 -0
- font/Lemon.ttf +3 -0
- font/MKyrill.ttf +3 -0
- font/Nextstep.ttf +3 -0
- font/Okesip.ttf +3 -0
- font/Otomanopee.ttf +3 -0
- font/Playwrite.ttf +3 -0
- font/Shrikhand.ttf +3 -0
- font/UnDotum.ttf +3 -0
- font/华文新魏.ttf +3 -0
- font/华文行楷.ttf +3 -0
- font/宅家麦克笔.ttf +3 -0
- font/巴蜀墨迹.ttf +3 -0
- font/斑马字类.ttf +3 -0
- font/清松手写体.ttf +3 -0
- font/演示夏行楷.ttf +3 -0
- font/辰宇落雁体.ttf +3 -0
- font/雷盖体.ttf +3 -0
- font/青柳隶书.ttf +3 -0
- font/鸿雷板书简体.ttf +3 -0
- functions.py +522 -0
- javascript/bboxHint.js +550 -0
- requirements.txt +160 -0
- templates/1.json +1 -0
- templates/1.png +0 -0
- templates/2.json +1 -0
- templates/2.png +0 -0
- templates/3.json +1 -0
- templates/3.png +0 -0
- templates/4.json +1 -0
- templates/4.png +0 -0
- templates/5.json +1 -0
- templates/5.png +0 -0
- templates/6.json +1 -0
- templates/6.png +0 -0
.gitattributes
CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
|
|
|
33 |
*.zip filter=lfs diff=lfs merge=lfs -text
|
34 |
*.zst filter=lfs diff=lfs merge=lfs -text
|
35 |
*tfevents* filter=lfs diff=lfs merge=lfs -text
|
36 |
+
font/*.ttf filter=lfs diff=lfs merge=lfs -text
|
README.md
CHANGED
@@ -1,13 +1,12 @@
|
|
1 |
---
|
2 |
title: JoyType
|
3 |
-
emoji:
|
4 |
-
colorFrom:
|
5 |
colorTo: blue
|
6 |
sdk: gradio
|
7 |
-
sdk_version:
|
8 |
app_file: app.py
|
9 |
pinned: false
|
10 |
-
license: apache-2.0
|
11 |
---
|
12 |
|
13 |
-
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
|
|
1 |
---
|
2 |
title: JoyType
|
3 |
+
emoji: 🔥
|
4 |
+
colorFrom: green
|
5 |
colorTo: blue
|
6 |
sdk: gradio
|
7 |
+
sdk_version: 3.50.0
|
8 |
app_file: app.py
|
9 |
pinned: false
|
|
|
10 |
---
|
11 |
|
12 |
+
Check out the configuration reference at https://huggingface.co/docs/hub/spaces-config-reference
|
app.py
ADDED
@@ -0,0 +1,261 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
# encoding=utf8
|
2 |
+
|
3 |
+
|
4 |
+
import os
|
5 |
+
import cv2
|
6 |
+
import gradio as gr
|
7 |
+
import numpy as np
|
8 |
+
import re
|
9 |
+
import json
|
10 |
+
|
11 |
+
from huggingface_hub import login
|
12 |
+
from functions import *
|
13 |
+
from gradio.components import Component
|
14 |
+
|
15 |
+
login(token=os.getenv('LOGIN_TOKEN'))
|
16 |
+
css = './css/style.css'
|
17 |
+
|
18 |
+
# Initial a Gradio Block with specific theme
|
19 |
+
block = gr.Blocks(
|
20 |
+
theme=gr.themes.Base(),
|
21 |
+
css=css
|
22 |
+
).queue()
|
23 |
+
|
24 |
+
# Load javascript plugin
|
25 |
+
with open('javascript/bboxHint.js', 'r', encoding="utf-8") as file:
|
26 |
+
value = file.read()
|
27 |
+
escaped_value = json.dumps(value)
|
28 |
+
|
29 |
+
with block:
|
30 |
+
block.load(
|
31 |
+
fn=None,
|
32 |
+
_js=f"""() => {{
|
33 |
+
const script = document.createElement("script");
|
34 |
+
const text = document.createTextNode({escaped_value});
|
35 |
+
script.appendChild(text);
|
36 |
+
document.head.appendChild(script);
|
37 |
+
}}"""
|
38 |
+
)
|
39 |
+
gr.HTML(
|
40 |
+
'<div style="text-align: center; margin: 20px auto;"> \
|
41 |
+
<h1 style="font-size:5em">JoyType</h1> \
|
42 |
+
<h1 style="font-size:2.5em">A Robust Design for Multilingual Visual Text Creation</h1> \
|
43 |
+
</div>'
|
44 |
+
)
|
45 |
+
with gr.Row():
|
46 |
+
with gr.Column(scale=3):
|
47 |
+
with gr.Accordion('Basic Settings(基础设置)', open=True):
|
48 |
+
with gr.Row(variant='compact'):
|
49 |
+
usr_prompt = gr.Textbox(label='Prompt(提示词)', elem_id='usr_prompt')
|
50 |
+
with gr.Row(variant='compact'):
|
51 |
+
base_model = gr.Dropdown(
|
52 |
+
value='JoyType.v1.0', choices=model_list,
|
53 |
+
label='Base Model(基模型)', elem_id='base_model', allow_custom_value=False
|
54 |
+
)
|
55 |
+
|
56 |
+
with gr.Accordion('Advanced Settings(高级设置)', open=False):
|
57 |
+
with gr.Row(variant='compact'):
|
58 |
+
image_width = gr.Slider(label='Image Width(宽度)', minimum=256, maximum=768, value=512, step=32)
|
59 |
+
image_height = gr.Slider(label='Image Height(高度)', minimum=256, maximum=768, value=512, step=32)
|
60 |
+
with gr.Row(variant='compact'):
|
61 |
+
num_samples = gr.Slider(label='Samples(生成数量)', minimum=1, maximum=4, value=2, step=1)
|
62 |
+
inference_steps = gr.Slider(label='Steps(推理步数)', minimum=10, maximum=50, value=20, step=1)
|
63 |
+
with gr.Row(variant='compact'):
|
64 |
+
conditioning_scale = gr.Slider(label='Text Strength(文字强度)', minimum=0.1, maximum=2., value=1., step=0.1)
|
65 |
+
cfg_scale = gr.Slider(label='CFG Scale(CFG制强度)', minimum=1, maximum=20, value=7.5, step=0.5)
|
66 |
+
with gr.Row(variant='compact'):
|
67 |
+
seed = gr.Slider(label='Seed(随机种子)', minimum=-1, maximum=2147483647, value=-1, step=1)
|
68 |
+
scheduler_name = gr.Dropdown(
|
69 |
+
value='PNDM', choices=[
|
70 |
+
'PNDM', 'LMS', 'Euler', 'DPM', 'DDIM', 'Heun', 'Euler-Ancestral'
|
71 |
+
],
|
72 |
+
label='Scheduler(采样器)', allow_custom_value=False
|
73 |
+
)
|
74 |
+
with gr.Row(variant='compact'):
|
75 |
+
a_prompt = gr.Textbox(
|
76 |
+
label='Added Prompt(附加提示词)', max_lines=2,
|
77 |
+
value='best quality, extremely detailed, supper legible text, '
|
78 |
+
'clear text edges, clear strokes, neat writing, no watermarks'
|
79 |
+
)
|
80 |
+
with gr.Row(variant='compact'):
|
81 |
+
n_prompt = gr.Textbox(
|
82 |
+
label='Negative Prompt(负向提示词)', max_lines=2,
|
83 |
+
value='low-res, bad anatomy, extra digit, fewer digits, cropped, worst quality, '
|
84 |
+
'low quality, watermark, unreadable text, messy words, distorted text, '
|
85 |
+
'disorganized writing, advertising picture'
|
86 |
+
)
|
87 |
+
|
88 |
+
base_model.change(
|
89 |
+
fn=change_settings,
|
90 |
+
inputs=base_model,
|
91 |
+
outputs=[inference_steps, cfg_scale, scheduler_name]
|
92 |
+
)
|
93 |
+
|
94 |
+
with gr.Row():
|
95 |
+
with gr.Tab('Text Editing(文字编辑)', elem_id='MD-tab-t2i'):
|
96 |
+
with gr.Row(variant='compact'):
|
97 |
+
choice = gr.Slider(
|
98 |
+
label=f'Text Boxes(可编辑文字框)',
|
99 |
+
minimum=0, maximum=8, step=1, value=BBOX_INI_NUM
|
100 |
+
)
|
101 |
+
|
102 |
+
with gr.Row():
|
103 |
+
with gr.Column(scale=2):
|
104 |
+
rect_img = gr.Image(
|
105 |
+
value=create_canvas(), label='Rect Position',
|
106 |
+
elem_id='MD-bbox-rect-t2i', show_label=False, visible=True,
|
107 |
+
height=300
|
108 |
+
)
|
109 |
+
with gr.Column(scale=3):
|
110 |
+
rect_cb_list: list[Component] = []
|
111 |
+
rect_box_list: list[Component] = []
|
112 |
+
rect_font_name_list: list[Component] = []
|
113 |
+
rect_usr_text_list: list[Component] = []
|
114 |
+
|
115 |
+
with gr.Column():
|
116 |
+
with gr.Row(elem_id='row_show'):
|
117 |
+
with gr.Column(scale=1, min_width=20):
|
118 |
+
gr.Markdown('<p align="center">Font(字体)</p>', elem_id='markdown_1')
|
119 |
+
with gr.Column(scale=2, min_width=20):
|
120 |
+
gr.Markdown('<p align="center">Text(文字内容)</p>', elem_id='markdown_2')
|
121 |
+
|
122 |
+
row_layout = [gr.Row() for _ in range(BBOX_MAX_NUM)]
|
123 |
+
for i in range(BBOX_MAX_NUM):
|
124 |
+
visible = True if i < BBOX_INI_NUM else False
|
125 |
+
with row_layout[i]:
|
126 |
+
fn = gr.Dropdown(
|
127 |
+
choices=font_list,
|
128 |
+
label='Font(字体)', value='CHN-华文行楷', visible=visible,
|
129 |
+
show_label=False, scale=1, allow_custom_value=False,
|
130 |
+
min_width=90, elem_id=f'font_input_{i}', container=False
|
131 |
+
)
|
132 |
+
ut = gr.Textbox(
|
133 |
+
label='Text(文字内容)', visible=visible, scale=2,
|
134 |
+
show_label=False, elem_id=f'text_input_{i}', container=False, max_lines=1
|
135 |
+
)
|
136 |
+
e = gr.Checkbox(label=f'{i}', value=visible, visible=False, min_width=10)
|
137 |
+
|
138 |
+
x = gr.Slider(label='x', value=0.4, minimum=0.0, maximum=1.0, step=0.0001,
|
139 |
+
elem_id=f'MD-t2i-{i}-x',
|
140 |
+
visible=False)
|
141 |
+
y = gr.Slider(label='y', value=0.4, minimum=0.0, maximum=1.0, step=0.0001,
|
142 |
+
elem_id=f'MD-t2i-{i}-y',
|
143 |
+
visible=False)
|
144 |
+
w = gr.Slider(label='w', value=0.2, minimum=0.0, maximum=1.0, step=0.0001,
|
145 |
+
elem_id=f'MD-t2i-{i}-w',
|
146 |
+
visible=False)
|
147 |
+
h = gr.Slider(label='h', value=0.2, minimum=0.0, maximum=1.0, step=0.0001,
|
148 |
+
elem_id=f'MD-t2i-{i}-h',
|
149 |
+
visible=False)
|
150 |
+
x.change(fn=None, inputs=x, outputs=x, _js=f'v => onBoxChange({i}, "x", v)',
|
151 |
+
show_progress=False, queue=False)
|
152 |
+
y.change(fn=None, inputs=y, outputs=y, _js=f'v => onBoxChange({i}, "y", v)',
|
153 |
+
show_progress=False, queue=False)
|
154 |
+
w.change(fn=None, inputs=w, outputs=w, _js=f'v => onBoxChange({i}, "w", v)',
|
155 |
+
show_progress=False, queue=False)
|
156 |
+
h.change(fn=None, inputs=h, outputs=h, _js=f'v => onBoxChange({i}, "h", v)',
|
157 |
+
show_progress=False, queue=False)
|
158 |
+
e.change(fn=None, inputs=e, outputs=e, _js=f'e => onBoxEnableClick({i}, e)',
|
159 |
+
queue=False)
|
160 |
+
|
161 |
+
rect_cb_list.extend([e])
|
162 |
+
rect_box_list.extend([x, y, w, h])
|
163 |
+
rect_font_name_list.extend([fn])
|
164 |
+
rect_usr_text_list.extend([ut])
|
165 |
+
|
166 |
+
choice.change(
|
167 |
+
fn=update_box_num,
|
168 |
+
inputs=[choice],
|
169 |
+
outputs=[
|
170 |
+
*rect_cb_list, *rect_font_name_list, *rect_usr_text_list, *rect_box_list
|
171 |
+
]
|
172 |
+
)
|
173 |
+
with gr.Row():
|
174 |
+
gr.Markdown('')
|
175 |
+
run_edit = gr.Button(value='Run(运行)', elem_classes='run', elem_id='run_edit')
|
176 |
+
gr.Markdown('')
|
177 |
+
with gr.Row():
|
178 |
+
with gr.Accordion(label='Examples(示例)', open=True):
|
179 |
+
img_container = gr.Image(visible=False, label='Text Layout(文字布局)')
|
180 |
+
example_id = gr.Textbox(value=-1, visible=False, label='ID(编号)')
|
181 |
+
gen_examples = gr.Examples(
|
182 |
+
[
|
183 |
+
[1, 'templates/1.png', 'landscape, Chinese style, ink peaks, poster', model_list[0], 1648703813, 3, 1],
|
184 |
+
[2, 'templates/2.png', 'a clock and medicine bottle has texts and "time"', model_list[0], 1654615998, 2, 1],
|
185 |
+
[3, 'templates/3.png', '漂亮的风景照,很多山峰,清澈的湖水', model_list[3], 2078698098, 3, 1],
|
186 |
+
[4, 'templates/4.png', 'a vodka, on the bar, dim background', model_list[2], 443791646, 3, 1],
|
187 |
+
[5, 'templates/5.png', '画有玫瑰的卡片,明亮的背景', model_list[4], 516210890, 2, 1],
|
188 |
+
[6, 'templates/6.png', 'posters on the table, with pens, clear background, starry sky, moon', model_list[1], 228167646, 4, 1],
|
189 |
+
[7, 'templates/7.png', 'snowy landscape, domed cabin, winter scene, cozy atmosphere, soft lighting', model_list[5], 695897181, 3, 1],
|
190 |
+
[8, 'templates/8.png', '一张关于健康教育的卡片,上面有一些文字,有一些食物图标,背景里有一些水果喝饮料的图标,且背景是模糊的', model_list[1], 936188591, 6, 1],
|
191 |
+
],
|
192 |
+
[example_id, img_container, usr_prompt, base_model, seed, choice, num_samples],
|
193 |
+
examples_per_page=5,
|
194 |
+
label=''
|
195 |
+
)
|
196 |
+
|
197 |
+
example_id.change(
|
198 |
+
fn=load_box_list,
|
199 |
+
inputs=[example_id, choice],
|
200 |
+
outputs=[
|
201 |
+
*rect_cb_list, *rect_font_name_list, *rect_usr_text_list, *rect_box_list, example_id
|
202 |
+
]
|
203 |
+
)
|
204 |
+
|
205 |
+
rect_img.clear(re_edit, None, [*rect_box_list, rect_img, image_width, image_height])
|
206 |
+
image_width.release(resize_w, [image_width, rect_img], rect_img)
|
207 |
+
image_height.release(resize_h, [image_height, rect_img], rect_img)
|
208 |
+
|
209 |
+
with gr.Column(scale=2):
|
210 |
+
with gr.Row():
|
211 |
+
result_gallery = gr.Gallery(
|
212 |
+
label='Result(结果)', show_label=True, preview=True, columns=8,
|
213 |
+
allow_preview=True, elem_id='gallery'
|
214 |
+
)
|
215 |
+
with gr.Row():
|
216 |
+
with gr.Tab("Introduction"):
|
217 |
+
gr.Markdown('<span style="color:#3B5998;font-size:20px">What we can do</span>')
|
218 |
+
gr.Markdown(
|
219 |
+
'<span style="color:black;font-size:15px">Generating images with accurately represented text in multi-language.</span>')
|
220 |
+
gr.Markdown('<span style="color:#3B5998;font-size:20px">How to use</span>')
|
221 |
+
gr.Markdown(
|
222 |
+
'<span style="color:black;font-size:15px">Enter a description of the image you want to generate in the "Prompt" text box.</span>')
|
223 |
+
gr.Markdown('<span style="color:#3B5998;font-size:18px">Text Editing</span>')
|
224 |
+
gr.Markdown(
|
225 |
+
'<span style="color:black;font-size:15px">You can drag the "Text Boxes" slider to set the number of text to be laid out, '
|
226 |
+
'and set the corresponding font and text content respectively, Note that there must be no overlap between the text boxes, '
|
227 |
+
'or the model will not generate an image.</span>')
|
228 |
+
gr.Markdown(
|
229 |
+
'<span style="color:black;font-size:15px">Finally, click the Run button to generate a picture!</span>')
|
230 |
+
with gr.Tab("说明"):
|
231 |
+
gr.Markdown('<span style="color:#3B5998;font-size:20px">我们能做什么</span>')
|
232 |
+
gr.Markdown('<span style="color:black;font-size:15px">在多种语言上生成具有准确文本的图像</span>')
|
233 |
+
gr.Markdown('<span style="color:#3B5998;font-size:20px">如何使用</span>')
|
234 |
+
gr.Markdown(
|
235 |
+
'<span style="color:black;font-size:15px">在“提示词”文本框中输入你想要生成的图片所对应的文字描述。</span>')
|
236 |
+
gr.Markdown('<span style="color:#3B5998;font-size:18px">文本编辑</span>')
|
237 |
+
gr.Markdown(
|
238 |
+
'<span style="color:black;font-size:15px">你可以拖动“可编辑文字框”滑块来设置需要布局的文字数量,并分别设置对应的字体和文字内容;'
|
239 |
+
'请注意,文本框之间不能有重叠,否则模型将不会生成图片。</span>')
|
240 |
+
gr.Markdown('<span style="color:black;font-size:15px">最后点击运行按钮,即可生成图片!</span>')
|
241 |
+
with gr.Row():
|
242 |
+
result_info = gr.Markdown('debug', visible=False)
|
243 |
+
|
244 |
+
args = [
|
245 |
+
num_samples, a_prompt, n_prompt,
|
246 |
+
conditioning_scale, cfg_scale, inference_steps, seed, usr_prompt,
|
247 |
+
rect_img, base_model, scheduler_name, gr.State(BBOX_MAX_NUM),
|
248 |
+
*(rect_cb_list + rect_box_list + rect_font_name_list + rect_usr_text_list)
|
249 |
+
]
|
250 |
+
run_edit.click(
|
251 |
+
fn=process,
|
252 |
+
inputs=args,
|
253 |
+
outputs=[result_gallery, result_info]
|
254 |
+
)
|
255 |
+
|
256 |
+
|
257 |
+
if __name__ == "__main__":
|
258 |
+
block.launch(
|
259 |
+
server_name='0.0.0.0',
|
260 |
+
share=True,
|
261 |
+
)
|
css/style.css
ADDED
@@ -0,0 +1,157 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
body, html {
|
2 |
+
height: 100%;
|
3 |
+
margin: 0;
|
4 |
+
}
|
5 |
+
.gradio_container {
|
6 |
+
height: 100%;
|
7 |
+
}
|
8 |
+
|
9 |
+
/**gallery**/
|
10 |
+
#gallery {
|
11 |
+
height: 400px;
|
12 |
+
width: 100%;
|
13 |
+
}
|
14 |
+
|
15 |
+
/**every font dropdown in editing**/
|
16 |
+
#font_input_0 input {
|
17 |
+
color: #ff0000;
|
18 |
+
font-size: 15px;
|
19 |
+
}
|
20 |
+
#font_input_1 input {
|
21 |
+
color: #ff9900;
|
22 |
+
font-size: 15px;
|
23 |
+
}
|
24 |
+
#font_input_2 input {
|
25 |
+
color: #996633;
|
26 |
+
font-size: 15px;
|
27 |
+
}
|
28 |
+
#font_input_3 input {
|
29 |
+
color: #33cc33;
|
30 |
+
font-size: 15px;
|
31 |
+
}
|
32 |
+
#font_input_4 input {
|
33 |
+
color: #33cccc;
|
34 |
+
font-size: 15px;
|
35 |
+
}
|
36 |
+
#font_input_5 input {
|
37 |
+
color: #0066ff;
|
38 |
+
font-size: 15px;
|
39 |
+
}
|
40 |
+
#font_input_6 input {
|
41 |
+
color: #ff3399;
|
42 |
+
font-size: 15px;
|
43 |
+
}
|
44 |
+
#font_input_7 input {
|
45 |
+
color: #cc00cc;
|
46 |
+
font-size: 15px;
|
47 |
+
}
|
48 |
+
#font_input_0.block.svelte-90oupt {
|
49 |
+
height: 30px;
|
50 |
+
}
|
51 |
+
#font_input_1.block.svelte-90oupt {
|
52 |
+
height: 30px;
|
53 |
+
}
|
54 |
+
#font_input_2.block.svelte-90oupt {
|
55 |
+
height: 30px;
|
56 |
+
}
|
57 |
+
#font_input_3.block.svelte-90oupt {
|
58 |
+
height: 30px;
|
59 |
+
}
|
60 |
+
#font_input_4.block.svelte-90oupt {
|
61 |
+
height: 30px;
|
62 |
+
}
|
63 |
+
#font_input_5.block.svelte-90oupt {
|
64 |
+
height: 30px;
|
65 |
+
}
|
66 |
+
#font_input_6.block.svelte-90oupt {
|
67 |
+
height: 30px;
|
68 |
+
}
|
69 |
+
#font_input_7.block.svelte-90oupt {
|
70 |
+
height: 30px;
|
71 |
+
}
|
72 |
+
|
73 |
+
/**every text box in editing**/
|
74 |
+
#text_input_0 input {
|
75 |
+
font-size: 15px;
|
76 |
+
}
|
77 |
+
#text_input_1 input {
|
78 |
+
font-size: 15px;
|
79 |
+
}
|
80 |
+
#text_input_2 input {
|
81 |
+
font-size: 15px;
|
82 |
+
}
|
83 |
+
#text_input_3 input {
|
84 |
+
font-size: 15px;
|
85 |
+
}
|
86 |
+
#text_input_4 input {
|
87 |
+
font-size: 15px;
|
88 |
+
}
|
89 |
+
#text_input_5 input {
|
90 |
+
font-size: 15px;
|
91 |
+
}
|
92 |
+
#text_input_6 input {
|
93 |
+
font-size: 15px;
|
94 |
+
}
|
95 |
+
#text_input_7 input {
|
96 |
+
font-size: 15px;
|
97 |
+
}
|
98 |
+
#text_input_0.block.svelte-90oupt {
|
99 |
+
height: 30px;
|
100 |
+
}
|
101 |
+
#text_input_1.block.svelte-90oupt {
|
102 |
+
height: 30px;
|
103 |
+
}
|
104 |
+
#text_input_2.block.svelte-90oupt {
|
105 |
+
height: 30px;
|
106 |
+
}
|
107 |
+
#text_input_3.block.svelte-90oupt {
|
108 |
+
height: 30px;
|
109 |
+
}
|
110 |
+
#text_input_4.block.svelte-90oupt {
|
111 |
+
height: 30px;
|
112 |
+
}
|
113 |
+
#text_input_5.block.svelte-90oupt {
|
114 |
+
height: 30px;
|
115 |
+
}
|
116 |
+
#text_input_6.block.svelte-90oupt {
|
117 |
+
height: 30px;
|
118 |
+
}
|
119 |
+
#text_input_7.block.svelte-90oupt {
|
120 |
+
height: 30px;
|
121 |
+
}
|
122 |
+
|
123 |
+
#row_show {
|
124 |
+
display: block
|
125 |
+
height: 25px
|
126 |
+
}
|
127 |
+
#markdown_1 {
|
128 |
+
display: block;
|
129 |
+
height: 25px;
|
130 |
+
}
|
131 |
+
#markdown_2 {
|
132 |
+
display: block;
|
133 |
+
height: 25px;
|
134 |
+
}
|
135 |
+
#markdown_1 span {
|
136 |
+
display: block;
|
137 |
+
height: 25px;
|
138 |
+
}
|
139 |
+
#markdown_2 span {
|
140 |
+
display: block;
|
141 |
+
height: 25px;
|
142 |
+
}
|
143 |
+
|
144 |
+
#run_edit {
|
145 |
+
background-color: #ff4500;
|
146 |
+
color: white;
|
147 |
+
}
|
148 |
+
#run_upload {
|
149 |
+
background-color: #ff4500;
|
150 |
+
color: white;
|
151 |
+
}
|
152 |
+
|
153 |
+
/**************************************
|
154 |
+
footer.svelte-1ax1toq {
|
155 |
+
display: none !important;
|
156 |
+
}
|
157 |
+
/**************************************/
|
font/Alice.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3b7ea628cb473d4b4737c4ffcd3f760bf6ca325d1344a134579ca636e33d9917
|
3 |
+
size 128720
|
font/Aoyagireisyosimo.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:a4c55ad5f72e65a482931d967725e97ff206eb3019c87281d9e5514a63bb8db9
|
3 |
+
size 4412684
|
font/Automatons.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:951850cc3b0839d886fcb773accca92c22f6eda0178b76a72c81377978100408
|
3 |
+
size 6784
|
font/BebasNeue.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:830ea186acffc2316ed1a4e42319246ba3b46b04e33a211079249bf901193f04
|
3 |
+
size 57676
|
font/Caveat.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:263493f012c8ffbf3a69a38d43ce494c42d1cb2d44b7cb9eff10095f08fce719
|
3 |
+
size 391068
|
font/ChosunGs.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:4e191bc30d23ce34797dcaf7a0965dedd67a2d85cc5dd87325ee96626cba7bea
|
3 |
+
size 9260104
|
font/Dongle.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:010703af6b86a860847eea86823387e05669faa75e81e6a0040398906a0f1fe7
|
3 |
+
size 4458436
|
font/Filthyrich.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6eb72bd16d5613612734a103a9cd9a7ffba83857675c8b53891eb2c3b8a3e582
|
3 |
+
size 125132
|
font/GlTsukiji.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6907481e7548bc723ef312e7508b21ea2e4b30313a13e7e2042ef4ad0953f7c3
|
3 |
+
size 334440
|
font/Gloock.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:39e2af503dfb3d1e093f0178863e2b163c59cdc4f4c5d152d50f51da19baf8fa
|
3 |
+
size 94940
|
font/GodoMaum.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:3ea6333b8a9b875d778598debd260695770a813fdbdd0d233845329151e43ffd
|
3 |
+
size 2760760
|
font/KouzanMouhitu.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:582f269574e71336f1ee8318664ff6cfafd84293b3267ddf39410015713c951e
|
3 |
+
size 8238216
|
font/Lemon.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:664fb2be44c5a08ba5ec89d06c3d523e0c2650a18922e667b8d9573a88ec37c4
|
3 |
+
size 73592
|
font/MKyrill.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:da5256add8bb73db799e2f354ea9e4bf2fd893c2d3af583021b09a67f892962f
|
3 |
+
size 81868
|
font/Nextstep.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:eae79e803499e66a6f15a8fab6e19bccbeeb2fe3b51722894ff2f1584fb9cafa
|
3 |
+
size 19952
|
font/Okesip.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:ea383c52f8fe1d4473d1a0d8d5cca42fda375d9f317bf42a0bd21251a8976e28
|
3 |
+
size 74056
|
font/Otomanopee.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:cb4bbcf825544a5102991f5118bbaa2440977ea1f4d5446c22963d70fd435602
|
3 |
+
size 366684
|
font/Playwrite.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:17810b62177426ffbe7b661598f8d1a67254daad70aac6a375c6ee1863a3c711
|
3 |
+
size 344044
|
font/Shrikhand.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:00269b4efb014de272c9313e16b7e166617c6fdac819a2bb063ef1e371b5801b
|
3 |
+
size 213868
|
font/UnDotum.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:5b8373e126bb61f59105cf7f54a47eb1b089c2b0aacb70c6cd688bd8ea76cdc9
|
3 |
+
size 3656228
|
font/华文新魏.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:361dc6d522d417fc5705948e65d191f7826147d390980f4cbdcfbca4a0200290
|
3 |
+
size 4044420
|
font/华文行楷.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:6e893a5a618b39f317362efd77f3c6aeb16149328cb66872c9db8cb457a71d32
|
3 |
+
size 4009504
|
font/宅家麦克笔.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:15cec9ab9565e0851e144144f7023c4c59f4fcdea96710a75cf668049f79b3df
|
3 |
+
size 17093408
|
font/巴蜀墨迹.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:d81299f3ed474a0a9ed80db21410c604c1ca561f9d36b8ff62ce4137d91c0cc8
|
3 |
+
size 7171284
|
font/斑马字类.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:93a253e524b7951e2394e1ac2bf981aa268ce0ae4b11934682de6c42f19354e1
|
3 |
+
size 2719964
|
font/清松手写体.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:ddd51d365ff4b1b5c58e2cc722226cd3109e9b33fcd6538b6599cf308dbc90e3
|
3 |
+
size 6348828
|
font/演示夏行楷.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:fac1f0ec044b63aa45c0775c17a2f03cbf6427b4bd7b93da87dde9e7e2020cfc
|
3 |
+
size 10073644
|
font/辰宇落雁体.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:1f04002cc0906d2bda376fb133d4a8160805db0113e92baf6da54aeafde88bd7
|
3 |
+
size 4511804
|
font/雷盖体.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:33fd784e6aa6b2f8e8e6064280ea6fc473246b6371884155d75c55577e6db4c2
|
3 |
+
size 4336920
|
font/青柳隶书.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:a4c55ad5f72e65a482931d967725e97ff206eb3019c87281d9e5514a63bb8db9
|
3 |
+
size 4412684
|
font/鸿雷板书简体.ttf
ADDED
@@ -0,0 +1,3 @@
|
|
|
|
|
|
|
|
|
1 |
+
version https://git-lfs.github.com/spec/v1
|
2 |
+
oid sha256:30a8a257480dbe55fd872722fb6ec52a7939ea0d34ddfcedbdf3595430d62d6b
|
3 |
+
size 11651532
|
functions.py
ADDED
@@ -0,0 +1,522 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import json
|
2 |
+
import os
|
3 |
+
import cv2
|
4 |
+
import random
|
5 |
+
import numpy as np
|
6 |
+
import gradio as gr
|
7 |
+
import torch
|
8 |
+
|
9 |
+
from zhipuai import ZhipuAI
|
10 |
+
from pytorch_lightning import seed_everything
|
11 |
+
from pprint import pprint
|
12 |
+
from PIL import Image, ImageDraw, ImageFont
|
13 |
+
from diffusers import (
|
14 |
+
ControlNetModel,
|
15 |
+
StableDiffusionControlNetPipeline,
|
16 |
+
)
|
17 |
+
from diffusers import (
|
18 |
+
DDIMScheduler,
|
19 |
+
PNDMScheduler,
|
20 |
+
EulerAncestralDiscreteScheduler,
|
21 |
+
DPMSolverMultistepScheduler,
|
22 |
+
EulerDiscreteScheduler,
|
23 |
+
LMSDiscreteScheduler,
|
24 |
+
HeunDiscreteScheduler
|
25 |
+
)
|
26 |
+
from controlnet_aux import (
|
27 |
+
PidiNetDetector,
|
28 |
+
HEDdetector
|
29 |
+
)
|
30 |
+
|
31 |
+
|
32 |
+
BBOX_MAX_NUM = 8
|
33 |
+
BBOX_INI_NUM = 0
|
34 |
+
MAX_LENGTH = 20
|
35 |
+
device = 'cuda'
|
36 |
+
pipeline = None
|
37 |
+
pre_pipeline = None
|
38 |
+
model_root = os.getenv('REPO_ROOT')
|
39 |
+
scheduler_root = f'{model_root}/Scheduler'
|
40 |
+
model_list =[
|
41 |
+
'JoyType.v1.0', 'RevAnimated-animation-动漫', 'GhostMix-animation-动漫',
|
42 |
+
'rpg.v5-fantasy_realism-奇幻写实', 'midjourneyPapercut-origami-折纸版画',
|
43 |
+
'dvarchExterior-architecture-建筑', 'awpainting.v13-portrait-人物肖像'
|
44 |
+
]
|
45 |
+
chn_example_dict = {
|
46 |
+
'漂亮的风景照,很多山峰,清澈的湖水': 'beautiful landscape, many peaks, clear lake',
|
47 |
+
'画有玫瑰的卡片,明亮的背景': 'a card with roses, bright background',
|
48 |
+
'一张关于健康教育的卡片,上面有一些文字,有一些食物图标,背景里有一些水果喝饮料的图标,且背景是模糊的': \
|
49 |
+
'a card for health education, with some writings on it, '
|
50 |
+
'food icons on the card, some fruits and drinking in the background, blur background '
|
51 |
+
}
|
52 |
+
match_dict = {
|
53 |
+
'JoyType.v1.0': 'JoyType-v1-1M',
|
54 |
+
'RevAnimated-animation-动漫': 'rev-animated-v1-2-2',
|
55 |
+
'GhostMix-animation-动漫': 'GhostMix_V2.0',
|
56 |
+
'rpg.v5-fantasy_realism-奇幻写实': 'rpg_v5',
|
57 |
+
'midjourneyPapercut-origami-折纸版画': 'midjourneyPapercut_v1',
|
58 |
+
'dvarchExterior-architecture-建筑': 'dvarchExterior',
|
59 |
+
'awpainting.v13-portrait-人物肖像': 'awpainting_v13'
|
60 |
+
}
|
61 |
+
font_list = [
|
62 |
+
'CHN-华文行楷',
|
63 |
+
'CHN-华文新魏',
|
64 |
+
'CHN-清松手写体',
|
65 |
+
'CHN-巴蜀墨迹',
|
66 |
+
'CHN-雷盖体',
|
67 |
+
'CHN-演示夏行楷',
|
68 |
+
'CHN-鸿雷板书简体',
|
69 |
+
'CHN-斑马字类',
|
70 |
+
'CHN-青柳隶书',
|
71 |
+
'CHN-辰宇落雁体',
|
72 |
+
'CHN-宅家麦克笔',
|
73 |
+
'ENG-Playwrite',
|
74 |
+
'ENG-Okesip',
|
75 |
+
'ENG-Shrikhand',
|
76 |
+
'ENG-Nextstep',
|
77 |
+
'ENG-Filthyrich',
|
78 |
+
'ENG-BebasNeue',
|
79 |
+
'ENG-Gloock',
|
80 |
+
'ENG-Lemon',
|
81 |
+
'RUS-Automatons',
|
82 |
+
'RUS-MKyrill',
|
83 |
+
'RUS-Alice',
|
84 |
+
'RUS-Caveat',
|
85 |
+
'KOR-ChosunGs',
|
86 |
+
'KOR-Dongle',
|
87 |
+
'KOR-GodoMaum',
|
88 |
+
'KOR-UnDotum',
|
89 |
+
'JPN-GlTsukiji',
|
90 |
+
'JPN-Aoyagireisyosimo',
|
91 |
+
'JPN-KouzanMouhitu',
|
92 |
+
'JPN-Otomanopee'
|
93 |
+
]
|
94 |
+
|
95 |
+
|
96 |
+
def change_settings(base_model):
|
97 |
+
if base_model == model_list[0]:
|
98 |
+
return gr.update(value=20), gr.update(value=7.5), gr.update(value='PNDM')
|
99 |
+
elif base_model == model_list[1]:
|
100 |
+
return gr.update(value=30), gr.update(value=8.5), gr.update(value='Euler')
|
101 |
+
elif base_model == model_list[2]:
|
102 |
+
return gr.update(value=32), gr.update(value=8.5), gr.update(value='Euler')
|
103 |
+
elif base_model == model_list[3]:
|
104 |
+
return gr.update(value=20), gr.update(value=7.5), gr.update(value='DPM')
|
105 |
+
elif base_model == model_list[4]:
|
106 |
+
return gr.update(value=25), gr.update(value=6.5), gr.update(value='Euler')
|
107 |
+
elif base_model == model_list[5]:
|
108 |
+
return gr.update(value=25), gr.update(value=8.5), gr.update(value='Euler')
|
109 |
+
elif base_model == model_list[6]:
|
110 |
+
return gr.update(value=25), gr.update(value=7), gr.update(value='DPM')
|
111 |
+
else:
|
112 |
+
pass
|
113 |
+
|
114 |
+
|
115 |
+
def update_box_num(choice):
|
116 |
+
update_list_1 = [] # checkbox
|
117 |
+
update_list_2 = [] # font
|
118 |
+
update_list_3 = [] # text
|
119 |
+
update_list_4 = [] # bounding box
|
120 |
+
for i in range(BBOX_MAX_NUM):
|
121 |
+
if i < choice:
|
122 |
+
update_list_1.append(gr.update(value=True))
|
123 |
+
update_list_2.append(gr.update(visible=True))
|
124 |
+
update_list_3.append(gr.update(visible=True))
|
125 |
+
update_list_4.extend([gr.update(visible=False) for _ in range(4)])
|
126 |
+
else:
|
127 |
+
update_list_1.append(gr.update(value=False))
|
128 |
+
update_list_2.append(gr.update(visible=False, value='CHN-华文行楷'))
|
129 |
+
update_list_3.append(gr.update(visible=False, value=''))
|
130 |
+
update_list_4.extend([
|
131 |
+
gr.update(visible=False, value=0.4),
|
132 |
+
gr.update(visible=False, value=0.4),
|
133 |
+
gr.update(visible=False, value=0.2),
|
134 |
+
gr.update(visible=False, value=0.2)
|
135 |
+
])
|
136 |
+
|
137 |
+
return *update_list_1, *update_list_2, *update_list_3, *update_list_4
|
138 |
+
|
139 |
+
|
140 |
+
def load_box_list(example_id, choice):
|
141 |
+
with open(f'templates/{example_id}.json', 'r') as f:
|
142 |
+
info = json.load(f)
|
143 |
+
update_list1 = []
|
144 |
+
update_list2 = []
|
145 |
+
update_list3 = []
|
146 |
+
update_list4 = []
|
147 |
+
|
148 |
+
for i in range(BBOX_MAX_NUM):
|
149 |
+
visible = info['visible'][i]
|
150 |
+
pos = info['pos'][i * 4: (i + 1) * 4]
|
151 |
+
update_list1.append(gr.update(value=visible))
|
152 |
+
update_list2.append(gr.update(value=info['font'][i], visible=visible))
|
153 |
+
update_list3.append(gr.update(value=info['text'][i], visible=visible))
|
154 |
+
update_list4.extend([
|
155 |
+
gr.update(value=pos[0]),
|
156 |
+
gr.update(value=pos[1]),
|
157 |
+
gr.update(value=pos[2]),
|
158 |
+
gr.update(value=pos[3])
|
159 |
+
])
|
160 |
+
|
161 |
+
return *update_list1, *update_list2, \
|
162 |
+
*update_list3, *update_list4, gr.update(value=-1)
|
163 |
+
|
164 |
+
|
165 |
+
def re_edit():
|
166 |
+
global BBOX_MAX_NUM
|
167 |
+
update_list = []
|
168 |
+
for i in range(BBOX_MAX_NUM):
|
169 |
+
update_list.extend([gr.update(value=0.4), gr.update(value=0.4), gr.update(value=0.2),
|
170 |
+
gr.update(value=0.2)])
|
171 |
+
return *update_list, \
|
172 |
+
gr.Image(
|
173 |
+
value=create_canvas(),
|
174 |
+
label='Rect Position', elem_id='MD-bbox-rect-t2i',
|
175 |
+
show_label=False, visible=True
|
176 |
+
), \
|
177 |
+
gr.Slider(value=512), gr.Slider(value=512)
|
178 |
+
|
179 |
+
|
180 |
+
def resize_w(w, img):
|
181 |
+
return cv2.resize(img, (w, img.shape[0]))
|
182 |
+
|
183 |
+
|
184 |
+
def resize_h(h, img):
|
185 |
+
return cv2.resize(img, (img.shape[1], h))
|
186 |
+
|
187 |
+
|
188 |
+
def create_canvas(w=512, h=512, c=3, line=5):
|
189 |
+
image = np.full((h, w, c), 200, dtype=np.uint8)
|
190 |
+
for i in range(h):
|
191 |
+
if i % (w // line) == 0:
|
192 |
+
image[i, :, :] = 150
|
193 |
+
for j in range(w):
|
194 |
+
if j % (w // line) == 0:
|
195 |
+
image[:, j, :] = 150
|
196 |
+
image[h // 2 - 8:h // 2 + 8, w // 2 - 8:w // 2 + 8, :] = [200, 0, 0]
|
197 |
+
return image
|
198 |
+
|
199 |
+
|
200 |
+
def canny(img):
|
201 |
+
low_threshold = 64
|
202 |
+
high_threshold = 100
|
203 |
+
|
204 |
+
img = cv2.Canny(img, low_threshold, high_threshold)
|
205 |
+
img = img[:, :, None]
|
206 |
+
img = np.concatenate([img, img, img], axis=2)
|
207 |
+
return Image.fromarray(img)
|
208 |
+
|
209 |
+
|
210 |
+
def judge_overlap(coord_list1, coord_list2):
|
211 |
+
judge = coord_list1[0] < coord_list2[2] and coord_list1[2] > coord_list2[0] \
|
212 |
+
and coord_list1[1] < coord_list2[3] and coord_list1[3] > coord_list2[1]
|
213 |
+
return judge
|
214 |
+
|
215 |
+
|
216 |
+
def parse_render_list(box_list, shape, box_num):
|
217 |
+
width = shape[0]
|
218 |
+
height = shape[1]
|
219 |
+
polygons = []
|
220 |
+
font_names = []
|
221 |
+
texts = []
|
222 |
+
valid_list = box_list[:box_num]
|
223 |
+
pos_list = box_list[box_num: 5 * box_num]
|
224 |
+
font_name_list = box_list[5 * box_num: 6 * box_num]
|
225 |
+
text_list = box_list[6 * box_num: 7 * box_num]
|
226 |
+
empty_flag = False
|
227 |
+
|
228 |
+
print(font_name_list, text_list)
|
229 |
+
|
230 |
+
for i, valid in enumerate(valid_list):
|
231 |
+
if valid:
|
232 |
+
pos = pos_list[i * 4: (i + 1) * 4]
|
233 |
+
top_left_x = int(pos[0] * width)
|
234 |
+
top_left_y = int(pos[1] * height)
|
235 |
+
w = int(pos[2] * width)
|
236 |
+
h = int(pos[3] * height)
|
237 |
+
font_name = str(font_name_list[i])
|
238 |
+
text = str(text_list[i])
|
239 |
+
if text == '':
|
240 |
+
empty_flag = True
|
241 |
+
text = 'JoyType'
|
242 |
+
if w <= 0 or h <= 0:
|
243 |
+
gr.Warning(f'Area of the box{i + 1} cannot be zero!')
|
244 |
+
return [], False
|
245 |
+
polygon = [
|
246 |
+
top_left_x,
|
247 |
+
top_left_y,
|
248 |
+
w, h
|
249 |
+
]
|
250 |
+
try:
|
251 |
+
assert font_name in font_list
|
252 |
+
font_name = font_name.split('-')[-1]
|
253 |
+
except Exception as e:
|
254 |
+
gr.Warning('Please choose a correct font!')
|
255 |
+
return [], False
|
256 |
+
|
257 |
+
polygons.append(polygon)
|
258 |
+
font_names.append(font_name.split('-')[-1])
|
259 |
+
texts.append(text)
|
260 |
+
|
261 |
+
if empty_flag:
|
262 |
+
gr.Warning('Null strings will be filled automatically!')
|
263 |
+
|
264 |
+
for i in range(len(polygons)):
|
265 |
+
for j in range(i + 1, len(polygons)):
|
266 |
+
if judge_overlap(
|
267 |
+
[polygons[i][0], polygons[i][1], polygons[i][0] + polygons[i][2], polygons[i][1] + polygons[i][3]],
|
268 |
+
[polygons[j][0], polygons[j][1], polygons[j][0] + polygons[j][2], polygons[j][1] + polygons[j][3]]
|
269 |
+
):
|
270 |
+
gr.Warning('Find overlapping boxes!')
|
271 |
+
return [], False
|
272 |
+
|
273 |
+
render_list = []
|
274 |
+
for i in range(len(polygons)):
|
275 |
+
text_dict = {}
|
276 |
+
text_dict['text'] = texts[i]
|
277 |
+
text_dict['polygon'] = polygons[i]
|
278 |
+
text_dict['font_name'] = font_names[i]
|
279 |
+
render_list.append(text_dict)
|
280 |
+
|
281 |
+
return render_list, True
|
282 |
+
|
283 |
+
|
284 |
+
def render_all_text(render_list, shape, threshold=512):
|
285 |
+
width = shape[0]
|
286 |
+
height = shape[1]
|
287 |
+
board = Image.new('RGB', (width, height), 'black')
|
288 |
+
|
289 |
+
for text_dict in render_list:
|
290 |
+
text = text_dict['text']
|
291 |
+
polygon = text_dict['polygon']
|
292 |
+
font_name = text_dict['font_name']
|
293 |
+
if len(text) > MAX_LENGTH:
|
294 |
+
text = text[:MAX_LENGTH]
|
295 |
+
gr.Warning(f'{text}... exceeds the maximum length {MAX_LENGTH} and has been cropped.')
|
296 |
+
|
297 |
+
w, h = polygon[2:]
|
298 |
+
vert = True if w < h else False
|
299 |
+
image4ratio = Image.new('RGB', (1024, 1024), 'black')
|
300 |
+
draw = ImageDraw.Draw(image4ratio)
|
301 |
+
|
302 |
+
try:
|
303 |
+
font = ImageFont.truetype(f'./font/{font_name}.ttf', encoding='utf-8', size=50)
|
304 |
+
except FileNotFoundError:
|
305 |
+
font = ImageFont.truetype(f'./font/{font_name}.otf', encoding='utf-8', size=50)
|
306 |
+
|
307 |
+
if not vert:
|
308 |
+
draw.text(xy=(0, 0), text=text, font=font, fill='white')
|
309 |
+
_, _, _tw, _th = draw.textbbox(xy=(0, 0), text=text, font=font)
|
310 |
+
_th += 1
|
311 |
+
else:
|
312 |
+
_tw, y_c = 0, 0
|
313 |
+
for c in text:
|
314 |
+
draw.text(xy=(0, y_c), text=c, font=font, fill='white')
|
315 |
+
_l, _t, _r, _b = font.getbbox(c)
|
316 |
+
_tw = max(_tw, _r - _l)
|
317 |
+
y_c += _b
|
318 |
+
_th = y_c + 1
|
319 |
+
|
320 |
+
ratio = (_th * w) / (_tw * h)
|
321 |
+
text_img = image4ratio.crop((0, 0, _tw, _th))
|
322 |
+
x_offset, y_offset = 0, 0
|
323 |
+
if 0.8 <= ratio <= 1.2:
|
324 |
+
text_img = text_img.resize((w, h))
|
325 |
+
elif ratio < 0.75:
|
326 |
+
resize_h = int(_th * (w / _tw))
|
327 |
+
text_img = text_img.resize((w, resize_h))
|
328 |
+
y_offset = (h - resize_h) // 2
|
329 |
+
else:
|
330 |
+
resize_w = int(_tw * (h / _th))
|
331 |
+
text_img = text_img.resize((resize_w, h))
|
332 |
+
x_offset = (w - resize_w) // 2
|
333 |
+
|
334 |
+
board.paste(text_img, (polygon[0] + x_offset, polygon[1] + y_offset))
|
335 |
+
|
336 |
+
return board
|
337 |
+
|
338 |
+
|
339 |
+
def load_pipeline(model_name, scheduler_name):
|
340 |
+
controlnet_path = os.path.join(model_root, f'{match_dict["JoyType.v1.0"]}')
|
341 |
+
model_path = os.path.join(model_root, model_name)
|
342 |
+
scheduler_name = scheduler_name.lower()
|
343 |
+
|
344 |
+
if scheduler_name == 'pndm':
|
345 |
+
scheduler = PNDMScheduler.from_pretrained(scheduler_root, subfolder='pndm')
|
346 |
+
if scheduler_name == 'lms':
|
347 |
+
scheduler = LMSDiscreteScheduler.from_pretrained(scheduler_root, subfolder='lms')
|
348 |
+
if scheduler_name == 'euler':
|
349 |
+
scheduler = EulerDiscreteScheduler.from_pretrained(scheduler_root, subfolder='euler')
|
350 |
+
if scheduler_name == 'dpm':
|
351 |
+
scheduler = DPMSolverMultistepScheduler.from_pretrained(scheduler_root, subfolder='dpm')
|
352 |
+
if scheduler_name == 'ddim':
|
353 |
+
scheduler = DDIMScheduler.from_pretrained(scheduler_root, subfolder='ddim')
|
354 |
+
if scheduler_name == 'heun':
|
355 |
+
scheduler = HeunDiscreteScheduler.from_pretrained(scheduler_root, subfolder='heun')
|
356 |
+
if scheduler_name == 'euler-ancestral':
|
357 |
+
scheduler = EulerAncestralDiscreteScheduler.from_pretrained(scheduler_root, subfolder='euler-ancestral')
|
358 |
+
|
359 |
+
controlnet = ControlNetModel.from_pretrained(
|
360 |
+
controlnet_path,
|
361 |
+
subfolder='controlnet',
|
362 |
+
torch_dtype=torch.float32
|
363 |
+
)
|
364 |
+
pipeline = StableDiffusionControlNetPipeline.from_pretrained(
|
365 |
+
model_path,
|
366 |
+
scheduler=scheduler,
|
367 |
+
controlnet=controlnet,
|
368 |
+
torch_dtype=torch.float32,
|
369 |
+
).to(device)
|
370 |
+
|
371 |
+
return pipeline
|
372 |
+
|
373 |
+
|
374 |
+
def preprocess_prompt(prompt):
|
375 |
+
client = ZhipuAI(api_key=os.getenv('ZHIPU_API_KEY'))
|
376 |
+
response = client.chat.completions.create(
|
377 |
+
model="glm-4-0520",
|
378 |
+
messages=[
|
379 |
+
{
|
380 |
+
'role': 'system',
|
381 |
+
'content': '''
|
382 |
+
Stable Diffusion是一款利用深度学习的文生图模型,支持通过使用提示词来产生新的图像,描述要包含或省略的元素。
|
383 |
+
我在这里引入Stable Diffusion算法中的Prompt概念,又被称为提示符。这里的Prompt通常可以用来描述图像,
|
384 |
+
他由普通常见的单词构成,最好是可以在数据集来源站点找到的著名标签(比如Ddanbooru)。
|
385 |
+
下面我将说明Prompt的生出步骤,这里的Prompt主要用于描述人物。在Prompt的生成中,你需要通过提示词来描述 人物属性,主题,外表,情绪,衣服,姿势,视角,动作,背景。
|
386 |
+
用英语单词或短语甚至自然语言的标签来描述,并不局限于我给你的单词。然后将你想要的相似的提示词组合在一起,请使用英文半角,做分隔符,每个提示词不要带引号,并将这些按从最重要到最不重要的顺序 排列。
|
387 |
+
另外请您注意,永远在每个 Prompt的前面加上引号里的内容,
|
388 |
+
“(((best quality))),(((ultra detailed))),(((masterpiece))),illustration,” 这是高质量的标志。
|
389 |
+
人物属性中,1girl表示你生成了一个女孩,2girls表示生成了两个女孩,一次。另外再注意,Prompt中不能带有-和_。
|
390 |
+
可以有空格和自然语言,但不要太多,单词不能重复。只返回Prompt。
|
391 |
+
'''
|
392 |
+
},
|
393 |
+
{
|
394 |
+
'role': 'user',
|
395 |
+
'content': prompt
|
396 |
+
}
|
397 |
+
],
|
398 |
+
temperature=0.5,
|
399 |
+
max_tokens=2048,
|
400 |
+
top_p=1,
|
401 |
+
stream=False,
|
402 |
+
)
|
403 |
+
|
404 |
+
if response:
|
405 |
+
glm = []
|
406 |
+
glm_return_list = response.choices
|
407 |
+
for item in glm_return_list:
|
408 |
+
glm.append(item.message.content)
|
409 |
+
|
410 |
+
return {'flag': 1, 'data': glm}
|
411 |
+
else:
|
412 |
+
return {'flag': 0, 'data': {}}
|
413 |
+
|
414 |
+
|
415 |
+
def process(
|
416 |
+
num_samples,
|
417 |
+
a_prompt,
|
418 |
+
n_prompt,
|
419 |
+
conditioning_scale,
|
420 |
+
cfg_scale,
|
421 |
+
inference_steps,
|
422 |
+
seed,
|
423 |
+
usr_prompt,
|
424 |
+
rect_img,
|
425 |
+
base_model,
|
426 |
+
scheduler_name,
|
427 |
+
box_num,
|
428 |
+
*box_list
|
429 |
+
):
|
430 |
+
if usr_prompt == '':
|
431 |
+
gr.Warning('Must input a prompt!')
|
432 |
+
return None, gr.Markdown('error')
|
433 |
+
|
434 |
+
if seed == -1:
|
435 |
+
seed = random.randint(0, 2147483647)
|
436 |
+
seed_everything(seed)
|
437 |
+
|
438 |
+
# Support Chinese Input
|
439 |
+
if usr_prompt in chn_example_dict.keys():
|
440 |
+
usr_prompt = chn_example_dict[usr_prompt]
|
441 |
+
else:
|
442 |
+
for ch in usr_prompt:
|
443 |
+
if '\u4e00' <= ch <= '\u9fff':
|
444 |
+
data = preprocess_prompt(usr_prompt)
|
445 |
+
if data['flag'] == 1:
|
446 |
+
usr_prompt = data['data'][0][1: -1]
|
447 |
+
else:
|
448 |
+
gr.Warning('Something went wrong while translating your prompt, please try again.')
|
449 |
+
return None, gr.Markdown('error')
|
450 |
+
break
|
451 |
+
|
452 |
+
shape = (rect_img.shape[1], rect_img.shape[0])
|
453 |
+
render_list, flag = parse_render_list(box_list, shape, box_num)
|
454 |
+
if flag:
|
455 |
+
render_img = render_all_text(render_list, shape)
|
456 |
+
else:
|
457 |
+
return None, gr.Markdown('error')
|
458 |
+
|
459 |
+
model_name = match_dict[base_model]
|
460 |
+
render_img = canny(np.array(render_img))
|
461 |
+
|
462 |
+
w, h = render_img.size
|
463 |
+
global pipeline, pre_pipeline
|
464 |
+
|
465 |
+
if pre_pipeline != model_name or pipeline is None:
|
466 |
+
pre_pipeline = model_name
|
467 |
+
pipeline = load_pipeline(model_name, scheduler_name)
|
468 |
+
|
469 |
+
batch_render_img = [render_img for _ in range(num_samples)]
|
470 |
+
batch_prompt = [f'{usr_prompt}, {a_prompt}' for _ in range(num_samples)]
|
471 |
+
batch_n_prompt = [n_prompt for _ in range(num_samples)]
|
472 |
+
|
473 |
+
images = pipeline(
|
474 |
+
batch_prompt,
|
475 |
+
negative_prompt=batch_n_prompt,
|
476 |
+
image=batch_render_img,
|
477 |
+
controlnet_conditioning_scale=float(conditioning_scale),
|
478 |
+
guidance_scale=float(cfg_scale),
|
479 |
+
width=w,
|
480 |
+
height=h,
|
481 |
+
num_inference_steps=int(inference_steps),
|
482 |
+
).images
|
483 |
+
|
484 |
+
return images, gr.Markdown(f'{seed}, {usr_prompt}, {box_list}')
|
485 |
+
|
486 |
+
|
487 |
+
def draw_example(box_list, color, id):
|
488 |
+
board = Image.fromarray(create_canvas())
|
489 |
+
|
490 |
+
w, h = board.size
|
491 |
+
|
492 |
+
draw = ImageDraw.Draw(board, mode='RGBA')
|
493 |
+
visible = box_list[:BBOX_MAX_NUM]
|
494 |
+
pos = box_list[BBOX_MAX_NUM: 5 * BBOX_MAX_NUM]
|
495 |
+
font = box_list[5 * BBOX_MAX_NUM: 6 * BBOX_MAX_NUM]
|
496 |
+
text = box_list[6 * BBOX_MAX_NUM:]
|
497 |
+
|
498 |
+
info = {
|
499 |
+
'visible': list(visible),
|
500 |
+
'pos': list(pos),
|
501 |
+
'font': list(font),
|
502 |
+
'text': list(text)
|
503 |
+
}
|
504 |
+
|
505 |
+
with open(f'templates/{id}.json', 'w') as f:
|
506 |
+
json.dump(info, f)
|
507 |
+
|
508 |
+
for i in range(BBOX_MAX_NUM):
|
509 |
+
if visible[i] is True:
|
510 |
+
polygon = pos[i * 4: (i + 1) * 4]
|
511 |
+
print(polygon)
|
512 |
+
left = w * polygon[0]
|
513 |
+
top = h * polygon[1]
|
514 |
+
right = left + w * polygon[2]
|
515 |
+
bottom = top + h * polygon[3]
|
516 |
+
draw.rectangle([left, top, right, bottom], outline=color[i][0], fill=color[i][1], width=3)
|
517 |
+
|
518 |
+
board.save(f'./examples/{id}.png')
|
519 |
+
|
520 |
+
|
521 |
+
if __name__ == '__main__':
|
522 |
+
pass
|
javascript/bboxHint.js
ADDED
@@ -0,0 +1,550 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
/*
|
2 |
+
Part of the implementation is borrowed and modified from multidiffusion-upscaler-for-automatic1111,
|
3 |
+
publicly available at https://github.com/pkuliyi2015/multidiffusion-upscaler-for-automatic1111
|
4 |
+
*/
|
5 |
+
|
6 |
+
const BBOX_MAX_NUM = 16;
|
7 |
+
const BBOX_WARNING_SIZE = 1280;
|
8 |
+
const DEFAULT_X = 0.4;
|
9 |
+
const DEFAULT_Y = 0.4;
|
10 |
+
const DEFAULT_H = 0.2;
|
11 |
+
const DEFAULT_W = 0.2;
|
12 |
+
|
13 |
+
// ref: https://html-color.codes/
|
14 |
+
// 每个框对应的颜色
|
15 |
+
const COLOR_MAP = [
|
16 |
+
['#ff0000', 'rgba(255, 0, 0, 0.3)'], // red
|
17 |
+
['#ff9900', 'rgba(255, 153, 0, 0.3)'], // orange
|
18 |
+
['#996633', 'rgba(153, 102, 51, 0.3)'], // brown
|
19 |
+
['#33cc33', 'rgba(51, 204, 51, 0.3)'], // green
|
20 |
+
['#33cccc', 'rgba(51, 204, 204, 0.3)'], // indigo
|
21 |
+
['#0066ff', 'rgba(0, 102, 255, 0.3)'], // blue
|
22 |
+
['#ff3399', 'rgba(255, 51, 153, 0.3)'], // hot pink
|
23 |
+
['#cc00cc', 'rgba(204, 0, 204, 0.3)'], // dark pink
|
24 |
+
['#ff6666', 'rgba(255, 102, 102, 0.3)'], // light red
|
25 |
+
['#ffcc66', 'rgba(255, 204, 102, 0.3)'], // light orange
|
26 |
+
['#99cc00', 'rgba(153, 204, 0, 0.3)'], // lime green
|
27 |
+
['#ffff00', 'rgba(255, 255, 0, 0.3)'], // yellow
|
28 |
+
['#0099cc', 'rgba(0, 153, 204, 0.3)'], // steel blue
|
29 |
+
['#00cc99', 'rgba(0, 204, 153, 0.3)'], // teal
|
30 |
+
['#ff3399', 'rgba(255, 51, 153, 0.3)'], // hot pink
|
31 |
+
['#9933cc', 'rgba(153, 51, 204, 0.3)'], // lavender
|
32 |
+
['#6600ff', 'rgba(102, 0, 255, 0.3)'], // purple
|
33 |
+
];
|
34 |
+
|
35 |
+
const RESIZE_BORDER = 5;
|
36 |
+
const ROTATE_BORDER = 8;
|
37 |
+
const MOVE_BORDER = 5;
|
38 |
+
|
39 |
+
const t2i_bboxes = new Array(BBOX_MAX_NUM).fill(null);
|
40 |
+
|
41 |
+
function gradioApp() {
|
42 |
+
const elems = document.getElementsByTagName('gradio-app')
|
43 |
+
const gradioShadowRoot = elems.length == 0 ? null : elems[0].shadowRoot
|
44 |
+
return !!gradioShadowRoot ? gradioShadowRoot : document;
|
45 |
+
}
|
46 |
+
|
47 |
+
// ↓↓↓ called from gradio ↓↓↓
|
48 |
+
function onCreateT2IRefClick(overwrite) {
|
49 |
+
let width, height;
|
50 |
+
if (overwrite) {
|
51 |
+
const overwriteInputs = gradioApp().querySelectorAll('#MD-overwrite-width-t2i input, #MD-overwrite-height-t2i input');
|
52 |
+
width = parseInt(overwriteInputs[0].value);
|
53 |
+
height = parseInt(overwriteInputs[2].value);
|
54 |
+
} else {
|
55 |
+
const sizeInputs = gradioApp().querySelectorAll('#txt2img_width input, #txt2img_height input');
|
56 |
+
width = parseInt(sizeInputs[0].value);
|
57 |
+
height = parseInt(sizeInputs[2].value);
|
58 |
+
}
|
59 |
+
|
60 |
+
if (isNaN(width)) width = 512;
|
61 |
+
if (isNaN(height)) height = 512;
|
62 |
+
|
63 |
+
// Concat it to string to bypass the gradio bug
|
64 |
+
// 向黑恶势力低头
|
65 |
+
return width.toString() + 'x' + height.toString();
|
66 |
+
}
|
67 |
+
|
68 |
+
function onBoxEnableClick(idx, enable) {
|
69 |
+
let canvas = null;
|
70 |
+
let bboxes = null;
|
71 |
+
let locator = null;
|
72 |
+
|
73 |
+
// locator = () => gradioApp().querySelector('#MD-bbox-ref-t2i');
|
74 |
+
locator = () => gradioApp().querySelector('#MD-bbox-rect-t2i');
|
75 |
+
bboxes = t2i_bboxes;
|
76 |
+
|
77 |
+
ref_div = locator();
|
78 |
+
canvas = ref_div.querySelector('img');
|
79 |
+
if (!canvas) { return false; }
|
80 |
+
|
81 |
+
if (enable) {
|
82 |
+
// Check if the bounding box already exists
|
83 |
+
if (!bboxes[idx]) {
|
84 |
+
// Initialize bounding box
|
85 |
+
const bbox = [DEFAULT_X, DEFAULT_Y, DEFAULT_W, DEFAULT_H];
|
86 |
+
const colorMap = COLOR_MAP[idx % COLOR_MAP.length];
|
87 |
+
const div = document.createElement('div');
|
88 |
+
div.id = 'MD-bbox-t2i' + idx;
|
89 |
+
div.style.left = '0px';
|
90 |
+
div.style.top = '0px';
|
91 |
+
div.style.width = '0px';
|
92 |
+
div.style.height = '0px';
|
93 |
+
div.style.position = 'absolute';
|
94 |
+
div.style.border = '2px solid ' + colorMap[0];
|
95 |
+
div.style.background = colorMap[1];
|
96 |
+
div.style.zIndex = '900';
|
97 |
+
div.style.display = 'none';
|
98 |
+
// A text tip to warn the user if bbox is too large
|
99 |
+
const tip = document.createElement('span');
|
100 |
+
tip.id = 'MD-tip-t2i' + idx;
|
101 |
+
tip.style.left = '50%';
|
102 |
+
tip.style.top = '50%';
|
103 |
+
tip.style.position = 'absolute';
|
104 |
+
tip.style.transform = 'translate(-50%, -50%)';
|
105 |
+
tip.style.fontSize = '12px';
|
106 |
+
tip.style.fontWeight = 'bold';
|
107 |
+
tip.style.textAlign = 'center';
|
108 |
+
tip.style.color = colorMap[0];
|
109 |
+
tip.style.zIndex = '901';
|
110 |
+
tip.style.display = 'none';
|
111 |
+
tip.innerHTML = 'Warning: Region very large!<br>Take care of VRAM usage!';
|
112 |
+
div.appendChild(tip);
|
113 |
+
div.addEventListener('mousedown', function (e) {
|
114 |
+
if (e.button === 0) { onBoxMouseDown(e, idx); }
|
115 |
+
});
|
116 |
+
div.addEventListener('mousemove', function (e) {
|
117 |
+
updateCursorStyle(e, idx);
|
118 |
+
});
|
119 |
+
|
120 |
+
const shower = function() { // insert to DOM if necessary
|
121 |
+
if (!gradioApp().querySelector('#' + div.id)) {
|
122 |
+
locator().appendChild(div);
|
123 |
+
}
|
124 |
+
}
|
125 |
+
bboxes[idx] = [div, bbox, shower];
|
126 |
+
}
|
127 |
+
|
128 |
+
// Show the bounding box
|
129 |
+
console.log('Here')
|
130 |
+
console.log(canvas)
|
131 |
+
console.log
|
132 |
+
displayBox(canvas, bboxes[idx]);
|
133 |
+
return true;
|
134 |
+
} else {
|
135 |
+
if (!bboxes[idx]) { return false; }
|
136 |
+
const [div, bbox, shower] = bboxes[idx];
|
137 |
+
div.style.display = 'none';
|
138 |
+
}
|
139 |
+
return false;
|
140 |
+
}
|
141 |
+
|
142 |
+
function onBoxChange(idx, what, v) {
|
143 |
+
// This function handles all the changes of the bounding box
|
144 |
+
// Including the rendering and python slider update
|
145 |
+
let bboxes = null;
|
146 |
+
let canvas = null;
|
147 |
+
|
148 |
+
bboxes = t2i_bboxes;
|
149 |
+
canvas = gradioApp().querySelector('#MD-bbox-rect-t2i img');
|
150 |
+
|
151 |
+
if (!bboxes[idx] || !canvas) {
|
152 |
+
switch (what) {
|
153 |
+
case 'x': return DEFAULT_X;
|
154 |
+
case 'y': return DEFAULT_Y;
|
155 |
+
case 'w': return DEFAULT_W;
|
156 |
+
case 'h': return DEFAULT_H;
|
157 |
+
}
|
158 |
+
}
|
159 |
+
const [div, bbox, shower] = bboxes[idx];
|
160 |
+
if (div.style.display === 'none') { return v; }
|
161 |
+
|
162 |
+
// parse trigger
|
163 |
+
switch (what) {
|
164 |
+
case 'x': bbox[0] = v; break;
|
165 |
+
case 'y': bbox[1] = v; break;
|
166 |
+
case 'w': bbox[2] = v; break;
|
167 |
+
case 'h': bbox[3] = v; break;
|
168 |
+
}
|
169 |
+
displayBox(canvas, bboxes[idx]);
|
170 |
+
return v;
|
171 |
+
}
|
172 |
+
|
173 |
+
// ↓↓↓ called from js ↓↓↓
|
174 |
+
function getSeedInfo(id, current_seed) {
|
175 |
+
const info_id = '#html_info_txt2img';
|
176 |
+
const info_div = gradioApp().querySelector(info_id);
|
177 |
+
try{
|
178 |
+
current_seed = parseInt(current_seed);
|
179 |
+
} catch(e) {
|
180 |
+
current_seed = -1;
|
181 |
+
}
|
182 |
+
if (!info_div) return current_seed;
|
183 |
+
let info = info_div.innerHTML;
|
184 |
+
if (!info) return current_seed;
|
185 |
+
// remove all html tags
|
186 |
+
info = info.replace(/<[^>]*>/g, '');
|
187 |
+
// Find a json string 'region control:' in the info
|
188 |
+
// get its index
|
189 |
+
idx = info.indexOf('Region control');
|
190 |
+
if (idx == -1) return current_seed;
|
191 |
+
// get the json string (detect the bracket)
|
192 |
+
// find the first '{'
|
193 |
+
let start_idx = info.indexOf('{', idx);
|
194 |
+
let bracket = 1;
|
195 |
+
let end_idx = start_idx + 1;
|
196 |
+
while (bracket > 0 && end_idx < info.length) {
|
197 |
+
if (info[end_idx] == '{') bracket++;
|
198 |
+
if (info[end_idx] == '}') bracket--;
|
199 |
+
end_idx++;
|
200 |
+
}
|
201 |
+
if (bracket > 0) {
|
202 |
+
return current_seed;
|
203 |
+
}
|
204 |
+
// get the json string
|
205 |
+
let json_str = info.substring(start_idx, end_idx);
|
206 |
+
// replace the single quote to double quote
|
207 |
+
json_str = json_str.replace(/'/g, '"');
|
208 |
+
// replace python True to javascript true, False to false
|
209 |
+
json_str = json_str.replace(/True/g, 'true');
|
210 |
+
// parse the json string
|
211 |
+
let json = JSON.parse(json_str);
|
212 |
+
// get the seed if the region id is in the json
|
213 |
+
const region_id = 'Region ' + id.toString();
|
214 |
+
if (!(region_id in json)) return current_seed;
|
215 |
+
const region = json[region_id];
|
216 |
+
if (!('seed' in region)) return current_seed;
|
217 |
+
let seed = region['seed'];
|
218 |
+
try{
|
219 |
+
seed = parseInt(seed);
|
220 |
+
} catch(e) {
|
221 |
+
return current_seed;
|
222 |
+
}
|
223 |
+
return seed;
|
224 |
+
}
|
225 |
+
|
226 |
+
function displayBox(canvas, bbox_info) {
|
227 |
+
// check null input
|
228 |
+
const [div, bbox, shower] = bbox_info;
|
229 |
+
const [x, y, w, h] = bbox;
|
230 |
+
if (!canvas || !div || x == null || y == null || w == null || h == null) { return; }
|
231 |
+
|
232 |
+
// client: canvas widget display size
|
233 |
+
// natural: content image real size
|
234 |
+
let vpScale = Math.min(canvas.clientWidth / canvas.naturalWidth, canvas.clientHeight / canvas.naturalHeight);
|
235 |
+
let canvasCenterX = canvas.clientWidth / 2;
|
236 |
+
let canvasCenterY = canvas.clientHeight / 2;
|
237 |
+
let scaledX = canvas.naturalWidth * vpScale;
|
238 |
+
let scaledY = canvas.naturalHeight * vpScale;
|
239 |
+
let viewRectLeft = canvasCenterX - scaledX / 2;
|
240 |
+
let viewRectRight = canvasCenterX + scaledX / 2;
|
241 |
+
let viewRectTop = canvasCenterY - scaledY / 2;
|
242 |
+
let viewRectDown = canvasCenterY + scaledY / 2;
|
243 |
+
|
244 |
+
let xDiv = viewRectLeft + scaledX * x;
|
245 |
+
let yDiv = viewRectTop + scaledY * y;
|
246 |
+
let wDiv = Math.min(scaledX * w, viewRectRight - xDiv);
|
247 |
+
let hDiv = Math.min(scaledY * h, viewRectDown - yDiv);
|
248 |
+
|
249 |
+
// Calculate warning bbox size
|
250 |
+
let upscalerFactor = 1.0;
|
251 |
+
let maxSize = BBOX_WARNING_SIZE / upscalerFactor * vpScale;
|
252 |
+
let maxW = maxSize / scaledX;
|
253 |
+
let maxH = maxSize / scaledY;
|
254 |
+
if (w > maxW || h > maxH) {
|
255 |
+
div.querySelector('span').style.display = 'block';
|
256 |
+
} else {
|
257 |
+
div.querySelector('span').style.display = 'none';
|
258 |
+
}
|
259 |
+
|
260 |
+
// update <div> when not equal
|
261 |
+
div.style.left = xDiv + 'px';
|
262 |
+
div.style.top = yDiv + 'px';
|
263 |
+
div.style.width = wDiv + 'px';
|
264 |
+
div.style.height = hDiv + 'px';
|
265 |
+
div.style.display = 'block';
|
266 |
+
|
267 |
+
// insert it to DOM if not appear
|
268 |
+
shower();
|
269 |
+
}
|
270 |
+
|
271 |
+
function onBoxMouseDown(e, idx) {
|
272 |
+
let bboxes = null;
|
273 |
+
let canvas = null;
|
274 |
+
|
275 |
+
bboxes = t2i_bboxes;
|
276 |
+
canvas = gradioApp().querySelector('#MD-bbox-rect-t2i img');
|
277 |
+
|
278 |
+
// Get the bounding box
|
279 |
+
if (!canvas || !bboxes[idx]) { return; }
|
280 |
+
const [div, bbox, shower] = bboxes[idx];
|
281 |
+
|
282 |
+
// Check if the click is inside the bounding box
|
283 |
+
const boxRect = div.getBoundingClientRect();
|
284 |
+
let mouseX = e.clientX;
|
285 |
+
let mouseY = e.clientY;
|
286 |
+
|
287 |
+
const resizeLeft = mouseX >= boxRect.left && mouseX <= boxRect.left + RESIZE_BORDER;
|
288 |
+
const resizeRight = mouseX >= boxRect.right - RESIZE_BORDER && mouseX <= boxRect.right;
|
289 |
+
const resizeTop = mouseY >= boxRect.top && mouseY <= boxRect.top + RESIZE_BORDER;
|
290 |
+
const resizeBottom = mouseY >= boxRect.bottom - RESIZE_BORDER && mouseY <= boxRect.bottom;
|
291 |
+
|
292 |
+
const moveHorizontal = mouseX >= boxRect.left + MOVE_BORDER && mouseX <= boxRect.right - MOVE_BORDER;
|
293 |
+
const moveVertical = mouseY >= boxRect.top + MOVE_BORDER && mouseY <= boxRect.bottom - MOVE_BORDER;
|
294 |
+
|
295 |
+
if (!resizeLeft && !resizeRight && !resizeTop && !resizeBottom && !moveHorizontal && !moveVertical) { return; }
|
296 |
+
|
297 |
+
const horizontalPivot = resizeLeft ? bbox[0] + bbox[2] : bbox[0];
|
298 |
+
const verticalPivot = resizeTop ? bbox[1] + bbox[3] : bbox[1];
|
299 |
+
|
300 |
+
// Canvas can be regarded as invariant during the drag operation
|
301 |
+
// Calculate in advance to reduce overhead
|
302 |
+
|
303 |
+
// Calculate viewport scale based on the current canvas size and the natural image size
|
304 |
+
let vpScale = Math.min(canvas.clientWidth / canvas.naturalWidth, canvas.clientHeight / canvas.naturalHeight);
|
305 |
+
let vpOffset = canvas.getBoundingClientRect();
|
306 |
+
|
307 |
+
// Calculate scaled dimensions of the canvas
|
308 |
+
let scaledX = canvas.naturalWidth * vpScale;
|
309 |
+
let scaledY = canvas.naturalHeight * vpScale;
|
310 |
+
|
311 |
+
// Calculate the canvas center and view rectangle coordinates
|
312 |
+
let canvasCenterX = (vpOffset.left + window.scrollX) + canvas.clientWidth / 2;
|
313 |
+
let canvasCenterY = (vpOffset.top + window.scrollY) + canvas.clientHeight / 2;
|
314 |
+
let viewRectLeft = canvasCenterX - scaledX / 2 - window.scrollX;
|
315 |
+
let viewRectRight = canvasCenterX + scaledX / 2 - window.scrollX;
|
316 |
+
let viewRectTop = canvasCenterY - scaledY / 2 - window.scrollY;
|
317 |
+
let viewRectDown = canvasCenterY + scaledY / 2 - window.scrollY;
|
318 |
+
|
319 |
+
mouseX = Math.min(Math.max(mouseX, viewRectLeft), viewRectRight);
|
320 |
+
mouseY = Math.min(Math.max(mouseY, viewRectTop), viewRectDown);
|
321 |
+
|
322 |
+
const accordion = gradioApp().querySelector('#MD-tab-t2i');
|
323 |
+
|
324 |
+
// Move or resize the bounding box on mousemove
|
325 |
+
function onMouseMove(e) {
|
326 |
+
// Prevent selecting anything irrelevant
|
327 |
+
e.preventDefault();
|
328 |
+
|
329 |
+
// Get the new mouse position
|
330 |
+
let newMouseX = e.clientX;
|
331 |
+
let newMouseY = e.clientY;
|
332 |
+
|
333 |
+
// clamp the mouse position to the view rectangle
|
334 |
+
newMouseX = Math.min(Math.max(newMouseX, viewRectLeft), viewRectRight);
|
335 |
+
newMouseY = Math.min(Math.max(newMouseY, viewRectTop), viewRectDown);
|
336 |
+
|
337 |
+
// Calculate the mouse movement delta
|
338 |
+
const dx = (newMouseX - mouseX) / scaledX;
|
339 |
+
const dy = (newMouseY - mouseY) / scaledY;
|
340 |
+
|
341 |
+
// Update the mouse position
|
342 |
+
mouseX = newMouseX;
|
343 |
+
mouseY = newMouseY;
|
344 |
+
|
345 |
+
// if no move just return
|
346 |
+
if (dx === 0 && dy === 0) { return; }
|
347 |
+
|
348 |
+
// Update the mouse position
|
349 |
+
let [x, y, w, h] = bbox;
|
350 |
+
if (moveHorizontal && moveVertical) {
|
351 |
+
// If moving the bounding box
|
352 |
+
x = Math.min(Math.max(x + dx, 0), 1 - w);
|
353 |
+
y = Math.min(Math.max(y + dy, 0), 1 - h);
|
354 |
+
} else {
|
355 |
+
// If resizing the bounding box
|
356 |
+
if (resizeLeft || resizeRight) {
|
357 |
+
if (x < horizontalPivot) {
|
358 |
+
if (dx <= w) {
|
359 |
+
// If still within the left side of the pivot
|
360 |
+
x = x + dx;
|
361 |
+
w = w - dx;
|
362 |
+
} else {
|
363 |
+
// If crossing the pivot
|
364 |
+
w = dx - w;
|
365 |
+
x = horizontalPivot;
|
366 |
+
}
|
367 |
+
} else {
|
368 |
+
if (w + dx < 0) {
|
369 |
+
// If still within the right side of the pivot
|
370 |
+
x = horizontalPivot + w + dx;
|
371 |
+
w = - dx - w;
|
372 |
+
} else {
|
373 |
+
// If crossing the pivot
|
374 |
+
x = horizontalPivot;
|
375 |
+
w = w + dx;
|
376 |
+
}
|
377 |
+
}
|
378 |
+
|
379 |
+
// Clamp the bounding box to the image
|
380 |
+
if (x < 0) {
|
381 |
+
w = w + x;
|
382 |
+
x = 0;
|
383 |
+
} else if (x + w > 1) {
|
384 |
+
w = 1 - x;
|
385 |
+
}
|
386 |
+
}
|
387 |
+
// Same as above, but for the vertical axis
|
388 |
+
if (resizeTop || resizeBottom) {
|
389 |
+
if (y < verticalPivot) {
|
390 |
+
if (dy <= h) {
|
391 |
+
y = y + dy;
|
392 |
+
h = h - dy;
|
393 |
+
} else {
|
394 |
+
h = dy - h;
|
395 |
+
y = verticalPivot;
|
396 |
+
}
|
397 |
+
} else {
|
398 |
+
if (h + dy < 0) {
|
399 |
+
y = verticalPivot + h + dy;
|
400 |
+
h = - dy - h;
|
401 |
+
} else {
|
402 |
+
y = verticalPivot;
|
403 |
+
h = h + dy;
|
404 |
+
}
|
405 |
+
}
|
406 |
+
if (y < 0) {
|
407 |
+
h = h + y;
|
408 |
+
y = 0;
|
409 |
+
} else if (y + h > 1) {
|
410 |
+
h = 1 - y;
|
411 |
+
}
|
412 |
+
}
|
413 |
+
}
|
414 |
+
const [div, old_bbox, _] = bboxes[idx];
|
415 |
+
|
416 |
+
// If all the values are the same, just return
|
417 |
+
if (old_bbox[0] === x && old_bbox[1] === y && old_bbox[2] === w && old_bbox[3] === h) { return; }
|
418 |
+
// else update the bbox
|
419 |
+
const event = new Event('input');
|
420 |
+
const coords = [x, y, w, h];
|
421 |
+
// <del>The querySelector is not very efficient, so we query it once and reuse it</del>
|
422 |
+
// caching will result gradio bugs that stucks bbox and cannot move & drag
|
423 |
+
const sliderIds = ['x', 'y', 'w', 'h'];
|
424 |
+
// We try to select the input sliders
|
425 |
+
const sliderSelectors = sliderIds.map(id => `#MD-${'t2i'}-${idx}-${id} input`).join(', ');
|
426 |
+
let sliderInputs = accordion.querySelectorAll(sliderSelectors);
|
427 |
+
// alert(sliderInputs.length)
|
428 |
+
if (sliderInputs.length == 0) {
|
429 |
+
// If we failed, the accordion is probably closed and sliders are removed in the dom, so we open it
|
430 |
+
accordion.querySelector('.label-wrap').click();
|
431 |
+
// and try again
|
432 |
+
sliderInputs = accordion.querySelectorAll(sliderSelectors);
|
433 |
+
// If we still failed, we just return
|
434 |
+
if (sliderInputs.length == 0) { return; }
|
435 |
+
}
|
436 |
+
for (let i = 0; i < 4; i++) {
|
437 |
+
if (old_bbox[i] !== coords[i]) {
|
438 |
+
sliderInputs[2*i].value = coords[i];
|
439 |
+
sliderInputs[2*i].dispatchEvent(event);
|
440 |
+
}
|
441 |
+
}
|
442 |
+
}
|
443 |
+
|
444 |
+
// Remove the mousemove and mouseup event listeners
|
445 |
+
function onMouseUp() {
|
446 |
+
document.removeEventListener('mousemove', onMouseMove);
|
447 |
+
document.removeEventListener('mouseup', onMouseUp);
|
448 |
+
}
|
449 |
+
|
450 |
+
// Add the event listeners
|
451 |
+
document.addEventListener('mousemove', onMouseMove);
|
452 |
+
document.addEventListener('mouseup', onMouseUp);
|
453 |
+
}
|
454 |
+
|
455 |
+
function updateCursorStyle(e, idx) {
|
456 |
+
// This function changes the cursor style when hovering over the bounding box
|
457 |
+
const bboxes = t2i_bboxes;
|
458 |
+
if (!bboxes[idx]) return;
|
459 |
+
|
460 |
+
const div = bboxes[idx][0];
|
461 |
+
const boxRect = div.getBoundingClientRect();
|
462 |
+
const mouseX = e.clientX;
|
463 |
+
const mouseY = e.clientY;
|
464 |
+
|
465 |
+
const boxCenterX = boxRect.left + boxRect.width / 2;
|
466 |
+
const rotateAreaLeft = boxCenterX - ROTATE_BORDER;
|
467 |
+
const rotateAreaRight = boxCenterX + ROTATE_BORDER;
|
468 |
+
const rotateAreaTop = boxRect.top + ROTATE_BORDER;
|
469 |
+
const rotateAreaBottom = boxRect.top - ROTATE_BORDER;
|
470 |
+
|
471 |
+
const resizeLeft = mouseX >= boxRect.left && mouseX <= boxRect.left + RESIZE_BORDER;
|
472 |
+
const resizeRight = mouseX >= boxRect.right - RESIZE_BORDER && mouseX <= boxRect.right;
|
473 |
+
const resizeTop = mouseY >= boxRect.top && mouseY <= boxRect.top + RESIZE_BORDER;
|
474 |
+
const resizeBottom = mouseY >= boxRect.bottom - RESIZE_BORDER && mouseY <= boxRect.bottom;
|
475 |
+
const rotateTop = mouseX >= rotateAreaLeft && mouseX <= rotateAreaRight && mouseY >= rotateAreaBottom && mouseY <= rotateAreaTop; //mouseX >= rotateAreaLeft && mouseX <= rotateAreaRight &&
|
476 |
+
|
477 |
+
|
478 |
+
// if (rotateTop) {
|
479 |
+
// div.style.cursor = 'crosshair';
|
480 |
+
// } else
|
481 |
+
if ((resizeLeft && resizeTop) || (resizeRight && resizeBottom)) {
|
482 |
+
div.style.cursor = 'nwse-resize';
|
483 |
+
} else if ((resizeLeft && resizeBottom) || (resizeRight && resizeTop)) {
|
484 |
+
div.style.cursor = 'nesw-resize';
|
485 |
+
} else if (resizeLeft || resizeRight) {
|
486 |
+
div.style.cursor = 'ew-resize';
|
487 |
+
} else if (resizeTop || resizeBottom) {
|
488 |
+
div.style.cursor = 'ns-resize';
|
489 |
+
} else {
|
490 |
+
div.style.cursor = 'move';
|
491 |
+
}
|
492 |
+
}
|
493 |
+
|
494 |
+
// ↓↓↓ auto called event listeners ↓↓↓
|
495 |
+
|
496 |
+
function updateBoxes() {
|
497 |
+
// This function redraw all bounding boxes
|
498 |
+
let bboxes = null;
|
499 |
+
let canvas = null;
|
500 |
+
|
501 |
+
bboxes = t2i_bboxes;
|
502 |
+
canvas = gradioApp().querySelector('#MD-bbox-rect-t2i img');
|
503 |
+
|
504 |
+
if (!canvas) return;
|
505 |
+
|
506 |
+
for (let idx = 0; idx < bboxes.length; idx++) {
|
507 |
+
if (!bboxes[idx]) continue;
|
508 |
+
const [div, bbox, shower] = bboxes[idx];
|
509 |
+
if (div.style.display === 'none') { return; }
|
510 |
+
|
511 |
+
displayBox(canvas, bboxes[idx]);
|
512 |
+
}
|
513 |
+
}
|
514 |
+
|
515 |
+
window.addEventListener('resize', _ => {
|
516 |
+
updateBoxes(true);
|
517 |
+
updateBoxes(false);
|
518 |
+
});
|
519 |
+
|
520 |
+
//// ======== Gradio Bug Fix ========
|
521 |
+
//// For Gradio versions > 3.16.0 and < 3.29.0, the accordion DOM will be deleted when it is closed.
|
522 |
+
//// We need to judge the versions and listen to the accordion open event, rerender the bbox at that time.
|
523 |
+
//// This silly bug fix is only for compatibility, we recommend to update the gradio version to 3.29.0 or higher.
|
524 |
+
//try {
|
525 |
+
// const GRADIO_VERSIONS = window.gradio_config["version"].split(".");
|
526 |
+
// const gradio_major_version = parseInt(GRADIO_VERSIONS[0]);
|
527 |
+
// const gradio_minor_version = parseInt(GRADIO_VERSIONS[1]);
|
528 |
+
// if (gradio_major_version == 3 && gradio_minor_version > 16 && gradio_minor_version < 29) {
|
529 |
+
// let listener = e => {
|
530 |
+
// if (!e) { return; }
|
531 |
+
// if (!e.target) { return; }
|
532 |
+
// if (!e.target.classList) { return; }
|
533 |
+
// if (!e.target.classList.contains('label-wrap')) { return; }
|
534 |
+
// for (let tab of ['t2i']) {
|
535 |
+
// const div = gradioApp().querySelector('#MD-bbox-control-' + tab +' div.label-wrap');
|
536 |
+
// if (!div) { continue; }
|
537 |
+
// updateBoxes(tab === 't2i');
|
538 |
+
// }
|
539 |
+
// };
|
540 |
+
// window.addEventListener('DOMNodeInserted', listener);
|
541 |
+
// }
|
542 |
+
//} catch (ignored) {
|
543 |
+
// // If the above code failed, the gradio version shouldn't be in the range of 3.16.0 to 3.29.0, so we just return.
|
544 |
+
//}
|
545 |
+
//// ======== Gradio Bug Fix ========
|
546 |
+
|
547 |
+
//// 由于python程序中的所有bbox都绑定了点击事件,并且在点击后才会在前端中渲染,所以需要提前在js中初始化指定数量的bbox
|
548 |
+
//for (let i = 0; i < 4; i++) {
|
549 |
+
// onBoxEnableClick(i, true)
|
550 |
+
//}
|
requirements.txt
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
absl-py==2.1.0
|
2 |
+
accelerate==0.31.0
|
3 |
+
addict==2.4.0
|
4 |
+
aiofiles==23.2.1
|
5 |
+
aiohttp==3.9.5
|
6 |
+
aiosignal==1.3.1
|
7 |
+
aliyun-python-sdk-core==2.15.1
|
8 |
+
aliyun-python-sdk-kms==2.16.3
|
9 |
+
altair==5.3.0
|
10 |
+
annotated-types==0.7.0
|
11 |
+
anyio==4.4.0
|
12 |
+
async-timeout==4.0.3
|
13 |
+
attrs==23.2.0
|
14 |
+
blinker==1.8.2
|
15 |
+
boto3==1.34.125
|
16 |
+
botocore==1.34.125
|
17 |
+
cachetools==5.3.3
|
18 |
+
certifi==2024.6.2
|
19 |
+
cffi==1.16.0
|
20 |
+
charset-normalizer==3.3.2
|
21 |
+
click==8.1.7
|
22 |
+
colorama==0.4.6
|
23 |
+
config==0.5.1
|
24 |
+
contourpy==1.2.1
|
25 |
+
controlnet-aux==0.0.9
|
26 |
+
crcmod==1.7
|
27 |
+
cryptography==42.0.8
|
28 |
+
cycler==0.12.1
|
29 |
+
datasets==2.18.0
|
30 |
+
diffusers==0.28.2
|
31 |
+
dill==0.3.8
|
32 |
+
distro==1.9.0
|
33 |
+
dnspython==2.6.1
|
34 |
+
einops==0.8.0
|
35 |
+
email_validator==2.1.1
|
36 |
+
et-xmlfile==1.1.0
|
37 |
+
exceptiongroup==1.2.1
|
38 |
+
fastapi==0.111.0
|
39 |
+
fastapi-cli==0.0.4
|
40 |
+
ffmpy==0.3.2
|
41 |
+
filelock==3.14.0
|
42 |
+
Flask==3.0.3
|
43 |
+
flatbuffers==24.3.25
|
44 |
+
fonttools==4.53.0
|
45 |
+
frozenlist==1.4.1
|
46 |
+
fsspec==2024.2.0
|
47 |
+
gast==0.5.4
|
48 |
+
gradio==3.50.0
|
49 |
+
gradio_client==0.6.1
|
50 |
+
h11==0.14.0
|
51 |
+
httpcore==1.0.5
|
52 |
+
httptools==0.6.1
|
53 |
+
httpx==0.27.0
|
54 |
+
huggingface-hub==0.23.2
|
55 |
+
idna==3.7
|
56 |
+
imageio==2.34.1
|
57 |
+
importlib_metadata==7.1.0
|
58 |
+
importlib_resources==6.4.0
|
59 |
+
intel-openmp==2021.4.0
|
60 |
+
itsdangerous==2.2.0
|
61 |
+
jax==0.4.30
|
62 |
+
jaxlib==0.4.30
|
63 |
+
Jinja2==3.1.4
|
64 |
+
jmespath==0.10.0
|
65 |
+
jsonschema==4.22.0
|
66 |
+
jsonschema-specifications==2023.12.1
|
67 |
+
kiwisolver==1.4.5
|
68 |
+
lazy_loader==0.4
|
69 |
+
lightning-utilities==0.11.2
|
70 |
+
linkify-it-py==2.0.3
|
71 |
+
markdown-it-py==2.2.0
|
72 |
+
MarkupSafe==2.1.5
|
73 |
+
matplotlib==3.9.0
|
74 |
+
mdit-py-plugins==0.3.3
|
75 |
+
mdurl==0.1.2
|
76 |
+
mediapipe==0.10.14
|
77 |
+
mkl==2021.4.0
|
78 |
+
ml-dtypes==0.4.0
|
79 |
+
modelscope==1.15.0
|
80 |
+
mpmath==1.3.0
|
81 |
+
multidict==6.0.5
|
82 |
+
multiprocess==0.70.16
|
83 |
+
networkx==3.3
|
84 |
+
numpy==1.26.4
|
85 |
+
openai==1.35.3
|
86 |
+
opencv-contrib-python==4.10.0.84
|
87 |
+
opencv-python==4.10.0.82
|
88 |
+
opencv-python-headless==4.10.0.82
|
89 |
+
openpyxl==3.1.5
|
90 |
+
opt-einsum==3.3.0
|
91 |
+
orjson==3.10.3
|
92 |
+
oss2==2.18.5
|
93 |
+
packaging==24.0
|
94 |
+
pandas==2.2.2
|
95 |
+
pillow==10.3.0
|
96 |
+
platformdirs==4.2.2
|
97 |
+
protobuf==4.25.3
|
98 |
+
psutil==5.9.8
|
99 |
+
pyarrow==16.1.0
|
100 |
+
pyarrow-hotfix==0.6
|
101 |
+
pycparser==2.22
|
102 |
+
pycryptodome==3.20.0
|
103 |
+
pydantic==2.7.3
|
104 |
+
pydantic_core==2.18.4
|
105 |
+
pydub==0.25.1
|
106 |
+
Pygments==2.18.0
|
107 |
+
PyJWT==2.8.0
|
108 |
+
pyparsing==3.1.2
|
109 |
+
python-dateutil==2.9.0.post0
|
110 |
+
python-dotenv==1.0.1
|
111 |
+
python-multipart==0.0.9
|
112 |
+
pytorch-lightning==2.3.0
|
113 |
+
pytz==2024.1
|
114 |
+
PyYAML==6.0.1
|
115 |
+
referencing==0.35.1
|
116 |
+
regex==2024.5.15
|
117 |
+
requests==2.32.3
|
118 |
+
rich==13.7.1
|
119 |
+
rpds-py==0.18.1
|
120 |
+
ruff==0.4.7
|
121 |
+
s3transfer==0.10.1
|
122 |
+
safetensors==0.4.3
|
123 |
+
scikit-image==0.23.2
|
124 |
+
scipy==1.13.1
|
125 |
+
semantic-version==2.10.0
|
126 |
+
shellingham==1.5.4
|
127 |
+
simplejson==3.19.2
|
128 |
+
six==1.16.0
|
129 |
+
sniffio==1.3.1
|
130 |
+
sortedcontainers==2.4.0
|
131 |
+
sounddevice==0.4.7
|
132 |
+
starlette==0.37.2
|
133 |
+
sympy==1.12.1
|
134 |
+
tbb==2021.12.0
|
135 |
+
tifffile==2024.5.22
|
136 |
+
timm==0.6.7
|
137 |
+
tokenizers==0.19.1
|
138 |
+
tomli==2.0.1
|
139 |
+
tomlkit==0.12.0
|
140 |
+
toolz==0.12.1
|
141 |
+
torch==2.3.1
|
142 |
+
torchmetrics==1.4.0.post0
|
143 |
+
torchvision==0.18.1
|
144 |
+
tqdm==4.66.4
|
145 |
+
transformers==4.41.2
|
146 |
+
typer==0.12.3
|
147 |
+
typing_extensions==4.12.1
|
148 |
+
tzdata==2024.1
|
149 |
+
uc-micro-py==1.0.3
|
150 |
+
ujson==5.10.0
|
151 |
+
urllib3==2.2.1
|
152 |
+
uvicorn==0.30.1
|
153 |
+
watchfiles==0.22.0
|
154 |
+
websockets==11.0.3
|
155 |
+
Werkzeug==3.0.3
|
156 |
+
xxhash==3.4.1
|
157 |
+
yapf==0.40.2
|
158 |
+
yarl==1.9.4
|
159 |
+
zhipuai==2.1.1.20240620.1
|
160 |
+
zipp==3.19.2
|
templates/1.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"visible": [true, true, true, false, false, false, false, false], "pos": [0.024161073825503594, 0.028187919463086675, 0.6295302013422815, 0.14966442953020198, 0.11476510067114097, 0.18187919463087276, 0.6060402684563758, 0.1395973154362417, 0.8268456375838927, 0.10134228187919483, 0.15973154362416148, 0.8140939597315439, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2], "font": ["CHN-\u5df4\u8700\u58a8\u8ff9", "CHN-\u5df4\u8700\u58a8\u8ff9", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977"], "text": ["\u5929\u7136\u6c27\u5427", "\u767b\u9ad8\u671b\u8fdc", "\u4fc3\u8fdb\u5faa\u73af \u5f3a\u5065\u8eab\u4f53", "", "", "", "", ""]}
|
templates/1.png
ADDED
![]() |
templates/2.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"visible": [true, true, false, false, false, false, false, false], "pos": [0.1885906040268458, 0.8302013422818793, 0.6496644295302016, 0.13624161073825505, 0.2026845637583891, 0.6590604026845638, 0.6161073825503363, 0.15302013422818816, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2], "font": ["RUS-Caveat", "CHN-\u6e05\u677e\u624b\u5199\u4f53", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977"], "text": ["\u043b\u0435\u043a\u0430\u0440\u0441\u0442\u0432", "\u89c4\u5f8b\u670d\u836f", "", "", "", "", "", ""]}
|
templates/2.png
ADDED
![]() |
templates/3.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"visible": [true, true, true, false, false, false, false, false], "pos": [0.13825503355704757, 0.0476510067114097, 0.2838926174496645, 0.11946308724832223, 0.43422818791946327, 0.05100671140939635, 0.44832214765100653, 0.11946308724832207, 0.1382550335570471, 0.19865771812080546, 0.7402684563758394, 0.12281879194630875, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2], "font": ["CHN-\u6e05\u677e\u624b\u5199\u4f53", "JPN-GlTsukiji", "ENG-Filthyrich", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977"], "text": ["\u4f60\u597d", "\u3053\u3093\u306b\u3061\u306f", "It's showtime", "", "", "", "", ""]}
|
templates/3.png
ADDED
![]() |
templates/4.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"visible": [true, true, true, false, false, false, false, false], "pos": [0.5449664429530201, 0.05436241610738259, 0.4281879194630869, 0.15973154362416114, 0.43355704697986586, 0.7959731543624167, 0.5489932885906045, 0.18657718120805372, 0.024161073825503712, 0.037583892617449835, 0.20335570469798664, 0.46845637583892613, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2], "font": ["RUS-Alice", "CHN-\u6f14\u793a\u590f\u884c\u6977", "KOR-ChosunGs", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977"], "text": ["\u0412\u043e\u0434\u043a\u0430", "\u8bf7\u9002\u91cf\u996e\u9152", "\uce90\uc8fc\uc5bc \ubc14", "", "", "", "", ""]}
|
templates/4.png
ADDED
![]() |
templates/5.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"visible": [true, true, false, false, false, false, false, false], "pos": [0.3201342281879193, 0.017449664429530044, 0.364429530201342, 0.14966442953020143, 0.13825503355704727, 0.19194630872483293, 0.74026845637584, 0.13624161073825514, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2], "font": ["CHN-\u6e05\u677e\u624b\u5199\u4f53", "JPN-Aoyagireisyosimo", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977"], "text": ["\u73ab\u7470", "\u6c17\u3092\u6674\u3089\u3057\u307e\u3059", "", "", "", "", "", ""]}
|
templates/5.png
ADDED
![]() |
templates/6.json
ADDED
@@ -0,0 +1 @@
|
|
|
|
|
1 |
+
{"visible": [true, true, true, true, false, false, false, false], "pos": [0.010738255033557227, 0.23892617449664466, 0.6060402684563759, 0.12617449664429542, 0.06107382550335593, 0.383892617449664, 0.3409395973154365, 0.10268456375838927, 0.06442953020134237, 0.500671140939596, 0.3375838926174498, 0.09597315436241619, 0.4637583892617447, 0.8637583892617449, 0.5053691275167783, 0.11946308724832194, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2, 0.4, 0.4, 0.2, 0.2], "font": ["CHN-\u6e05\u677e\u624b\u5199\u4f53", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "ENG-Okesip", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977", "CHN-\u534e\u6587\u884c\u6977"], "text": ["\u71ac\u591c\u6709\u5bb3\u5065\u5eb7", "\u4f11\u606f\u65e9", "\u7cbe\u795e\u597d", "Good Night", "", "", "", ""]}
|
templates/6.png
ADDED
![]() |