Skip to content

Commit

Permalink
Merge pull request AUTOMATIC1111#2 from xiehust/master
Browse files Browse the repository at this point in the history
add xyz plot
  • Loading branch information
xieyongliang authored Mar 21, 2023
2 parents 4a085ec + 7f76339 commit 5447455
Show file tree
Hide file tree
Showing 5 changed files with 798 additions and 1 deletion.
1 change: 1 addition & 0 deletions localizations/zh_CN.json
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@
"Prompt matrix": "提示词矩阵",
"Prompts from file or textbox": "从文本框或文件载入提示词",
"X/Y plot": "X/Y 图表",
"X/Y/Z plot": "X/Y/Z 图表",
"Source embedding to convert": "用于转换的源 Embedding",
"Embedding token": "Embedding 的 token (关键词)",
"Output directory": "输出目录",
Expand Down
92 changes: 91 additions & 1 deletion modules/images.py
Original file line number Diff line number Diff line change
Expand Up @@ -124,8 +124,98 @@ def __init__(self, text='', is_active=True):
self.is_active = is_active
self.size = None

def draw_grid_annotations(im, width, height, hor_texts, ver_texts, margin=0):
def wrap(drawing, text, font, line_length):
lines = ['']
for word in text.split():
line = f'{lines[-1]} {word}'.strip()
if drawing.textlength(line, font=font) <= line_length:
lines[-1] = line
else:
lines.append(word)
return lines

def get_font(fontsize):
try:
return ImageFont.truetype(opts.font or Roboto, fontsize)
except Exception:
return ImageFont.truetype(Roboto, fontsize)

def draw_texts(drawing, draw_x, draw_y, lines, initial_fnt, initial_fontsize):
for i, line in enumerate(lines):
fnt = initial_fnt
fontsize = initial_fontsize
while drawing.multiline_textsize(line.text, font=fnt)[0] > line.allowed_width and fontsize > 0:
fontsize -= 1
fnt = get_font(fontsize)
drawing.multiline_text((draw_x, draw_y + line.size[1] / 2), line.text, font=fnt, fill=color_active if line.is_active else color_inactive, anchor="mm", align="center")

if not line.is_active:
drawing.line((draw_x - line.size[0] // 2, draw_y + line.size[1] // 2, draw_x + line.size[0] // 2, draw_y + line.size[1] // 2), fill=color_inactive, width=4)

draw_y += line.size[1] + line_spacing

fontsize = (width + height) // 25
line_spacing = fontsize // 2

fnt = get_font(fontsize)

color_active = (0, 0, 0)
color_inactive = (153, 153, 153)

pad_left = 0 if sum([sum([len(line.text) for line in lines]) for lines in ver_texts]) == 0 else width * 3 // 4

cols = im.width // width
rows = im.height // height

assert cols == len(hor_texts), f'bad number of horizontal texts: {len(hor_texts)}; must be {cols}'
assert rows == len(ver_texts), f'bad number of vertical texts: {len(ver_texts)}; must be {rows}'

calc_img = Image.new("RGB", (1, 1), "white")
calc_d = ImageDraw.Draw(calc_img)

for texts, allowed_width in zip(hor_texts + ver_texts, [width] * len(hor_texts) + [pad_left] * len(ver_texts)):
items = [] + texts
texts.clear()

for line in items:
wrapped = wrap(calc_d, line.text, fnt, allowed_width)
texts += [GridAnnotation(x, line.is_active) for x in wrapped]

for line in texts:
bbox = calc_d.multiline_textbbox((0, 0), line.text, font=fnt)
line.size = (bbox[2] - bbox[0], bbox[3] - bbox[1])
line.allowed_width = allowed_width

hor_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing for lines in hor_texts]
ver_text_heights = [sum([line.size[1] + line_spacing for line in lines]) - line_spacing * len(lines) for lines in ver_texts]

pad_top = 0 if sum(hor_text_heights) == 0 else max(hor_text_heights) + line_spacing * 2

result = Image.new("RGB", (im.width + pad_left + margin * (cols-1), im.height + pad_top + margin * (rows-1)), "white")

for row in range(rows):
for col in range(cols):
cell = im.crop((width * col, height * row, width * (col+1), height * (row+1)))
result.paste(cell, (pad_left + (width + margin) * col, pad_top + (height + margin) * row))

d = ImageDraw.Draw(result)

for col in range(cols):
x = pad_left + (width + margin) * col + width / 2
y = pad_top / 2 - hor_text_heights[col] / 2

draw_texts(d, x, y, hor_texts[col], fnt, fontsize)

for row in range(rows):
x = pad_left / 2
y = pad_top + (height + margin) * row + height / 2 - ver_text_heights[row] / 2

draw_texts(d, x, y, ver_texts[row], fnt, fontsize)

return result

def draw_grid_annotations(im, width, height, hor_texts, ver_texts):
def draw_grid_annotations_old(im, width, height, hor_texts, ver_texts):
def wrap(drawing, text, font, line_length):
lines = ['']
for word in text.split():
Expand Down
9 changes: 9 additions & 0 deletions modules/scripts.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import os
import sys
import traceback
import re
from collections import namedtuple

import gradio as gr
Expand Down Expand Up @@ -116,7 +117,15 @@ def after_component(self, component, **kwargs):
def describe(self):
"""unused"""
return ""

def elem_id(self, item_id):
"""helper function to generate id for a HTML element, constructs final id out of script name, tab and user-supplied item_id"""

need_tabname = self.show(True) == self.show(False)
tabname = ('img2img' if self.is_img2img else 'txt2txt') + "_" if need_tabname else ""
title = re.sub(r'[^a-z_0-9]', '', re.sub(r'\s', '_', self.title().lower()))

return f'script_{tabname}{title}_{item_id}'

current_basedir = paths.script_path

Expand Down
58 changes: 58 additions & 0 deletions modules/ui_components.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import gradio as gr


class ToolButton(gr.Button, gr.components.FormComponent):
"""Small button with single emoji as text, fits inside gradio forms"""

def __init__(self, **kwargs):
super().__init__(variant="tool", **kwargs)

def get_block_name(self):
return "button"


class ToolButtonTop(gr.Button, gr.components.FormComponent):
"""Small button with single emoji as text, with extra margin at top, fits inside gradio forms"""

def __init__(self, **kwargs):
super().__init__(variant="tool-top", **kwargs)

def get_block_name(self):
return "button"


class FormRow(gr.Row, gr.components.FormComponent):
"""Same as gr.Row but fits inside gradio forms"""

def get_block_name(self):
return "row"


class FormGroup(gr.Group, gr.components.FormComponent):
"""Same as gr.Row but fits inside gradio forms"""

def get_block_name(self):
return "group"


class FormHTML(gr.HTML, gr.components.FormComponent):
"""Same as gr.HTML but fits inside gradio forms"""

def get_block_name(self):
return "html"


class FormColorPicker(gr.ColorPicker, gr.components.FormComponent):
"""Same as gr.ColorPicker but fits inside gradio forms"""

def get_block_name(self):
return "colorpicker"


class DropdownMulti(gr.Dropdown):
"""Same as gr.Dropdown but always multiselect"""
def __init__(self, **kwargs):
super().__init__(multiselect=True, **kwargs)

def get_block_name(self):
return "dropdown"
Loading

0 comments on commit 5447455

Please sign in to comment.