Commit 1fe1af27 authored by wanglch's avatar wanglch
Browse files

Initial commit

parent 4cfcf972
"""
Donut
Copyright (c) 2022-present NAVER Corp.
MIT License
"""
from collections import OrderedDict
import numpy as np
from synthtiger import components
from elements.textbox import TextBox
from layouts import GridStack
class TextReader:
def __init__(self, path, cache_size=2 ** 28, block_size=2 ** 20):
self.fp = open(path, "r", encoding="utf-8")
self.length = 0
self.offsets = [0]
self.cache = OrderedDict()
self.cache_size = cache_size
self.block_size = block_size
self.bucket_size = cache_size // block_size
self.idx = 0
while True:
text = self.fp.read(self.block_size)
if not text:
break
self.length += len(text)
self.offsets.append(self.fp.tell())
def __len__(self):
return self.length
def __iter__(self):
return self
def __next__(self):
char = self.get()
self.next()
return char
def move(self, idx):
self.idx = idx
def next(self):
self.idx = (self.idx + 1) % self.length
def prev(self):
self.idx = (self.idx - 1) % self.length
def get(self):
key = self.idx // self.block_size
if key in self.cache:
text = self.cache[key]
else:
if len(self.cache) >= self.bucket_size:
self.cache.popitem(last=False)
offset = self.offsets[key]
self.fp.seek(offset, 0)
text = self.fp.read(self.block_size)
self.cache[key] = text
self.cache.move_to_end(key)
char = text[self.idx % self.block_size]
return char
class Content:
def __init__(self, config):
self.margin = config.get("margin", [0, 0.1])
self.reader = TextReader(**config.get("text", {}))
self.font = components.BaseFont(**config.get("font", {}))
self.layout = GridStack(config.get("layout", {}))
self.textbox = TextBox(config.get("textbox", {}))
self.textbox_color = components.Switch(components.Gray(), **config.get("textbox_color", {}))
self.content_color = components.Switch(components.Gray(), **config.get("content_color", {}))
def generate(self, size):
width, height = size
layout_left = width * np.random.uniform(self.margin[0], self.margin[1])
layout_top = height * np.random.uniform(self.margin[0], self.margin[1])
layout_width = max(width - layout_left * 2, 0)
layout_height = max(height - layout_top * 2, 0)
layout_bbox = [layout_left, layout_top, layout_width, layout_height]
text_layers, texts = [], []
layouts = self.layout.generate(layout_bbox)
self.reader.move(np.random.randint(len(self.reader)))
for layout in layouts:
font = self.font.sample()
for bbox, align in layout:
x, y, w, h = bbox
text_layer, text = self.textbox.generate((w, h), self.reader, font)
self.reader.prev()
if text_layer is None:
continue
text_layer.center = (x + w / 2, y + h / 2)
if align == "left":
text_layer.left = x
if align == "right":
text_layer.right = x + w
self.textbox_color.apply([text_layer])
text_layers.append(text_layer)
texts.append(text)
self.content_color.apply(text_layers)
return text_layers, texts
"""
Donut
Copyright (c) 2022-present NAVER Corp.
MIT License
"""
import numpy as np
from synthtiger import components
from elements.content import Content
from elements.paper import Paper
class Document:
def __init__(self, config):
self.fullscreen = config.get("fullscreen", 0.5)
self.landscape = config.get("landscape", 0.5)
self.short_size = config.get("short_size", [480, 1024])
self.aspect_ratio = config.get("aspect_ratio", [1, 2])
self.paper = Paper(config.get("paper", {}))
self.content = Content(config.get("content", {}))
self.effect = components.Iterator(
[
components.Switch(components.ElasticDistortion()),
components.Switch(components.AdditiveGaussianNoise()),
components.Switch(
components.Selector(
[
components.Perspective(),
components.Perspective(),
components.Perspective(),
components.Perspective(),
components.Perspective(),
components.Perspective(),
components.Perspective(),
components.Perspective(),
]
)
),
],
**config.get("effect", {}),
)
def generate(self, size):
width, height = size
fullscreen = np.random.rand() < self.fullscreen
if not fullscreen:
landscape = np.random.rand() < self.landscape
max_size = width if landscape else height
short_size = np.random.randint(
min(width, height, self.short_size[0]),
min(width, height, self.short_size[1]) + 1,
)
aspect_ratio = np.random.uniform(
min(max_size / short_size, self.aspect_ratio[0]),
min(max_size / short_size, self.aspect_ratio[1]),
)
long_size = int(short_size * aspect_ratio)
size = (long_size, short_size) if landscape else (short_size, long_size)
text_layers, texts = self.content.generate(size)
paper_layer = self.paper.generate(size)
self.effect.apply([*text_layers, paper_layer])
return paper_layer, text_layers, texts
"""
Donut
Copyright (c) 2022-present NAVER Corp.
MIT License
"""
from synthtiger import components, layers
class Paper:
def __init__(self, config):
self.image = components.BaseTexture(**config.get("image", {}))
def generate(self, size):
paper_layer = layers.RectLayer(size, (255, 255, 255, 255))
self.image.apply([paper_layer])
return paper_layer
"""
Donut
Copyright (c) 2022-present NAVER Corp.
MIT License
"""
import numpy as np
from synthtiger import layers
class TextBox:
def __init__(self, config):
self.fill = config.get("fill", [1, 1])
def generate(self, size, text, font):
width, height = size
char_layers, chars = [], []
fill = np.random.uniform(self.fill[0], self.fill[1])
width = np.clip(width * fill, height, width)
font = {**font, "size": int(height)}
left, top = 0, 0
for char in text:
if char in "\r\n":
continue
char_layer = layers.TextLayer(char, **font)
char_scale = height / char_layer.height
char_layer.bbox = [left, top, *(char_layer.size * char_scale)]
if char_layer.right > width:
break
char_layers.append(char_layer)
chars.append(char)
left = char_layer.right
text = "".join(chars).strip()
if len(char_layers) == 0 or len(text) == 0:
return None, None
text_layer = layers.Group(char_layers).merge()
return text_layer, text
"""
Donut
Copyright (c) 2022-present NAVER Corp.
MIT License
"""
from layouts.grid import Grid
from layouts.grid_stack import GridStack
__all__ = ["Grid", "GridStack"]
"""
Donut
Copyright (c) 2022-present NAVER Corp.
MIT License
"""
import numpy as np
class Grid:
def __init__(self, config):
self.text_scale = config.get("text_scale", [0.05, 0.1])
self.max_row = config.get("max_row", 5)
self.max_col = config.get("max_col", 3)
self.fill = config.get("fill", [0, 1])
self.full = config.get("full", 0)
self.align = config.get("align", ["left", "right", "center"])
def generate(self, bbox):
left, top, width, height = bbox
text_scale = np.random.uniform(self.text_scale[0], self.text_scale[1])
text_size = min(width, height) * text_scale
grids = np.random.permutation(self.max_row * self.max_col)
for grid in grids:
row = grid // self.max_col + 1
col = grid % self.max_col + 1
if text_size * (col * 2 - 1) <= width and text_size * row <= height:
break
else:
return None
bound = max(1 - text_size / width * (col - 1), 0)
full = np.random.rand() < self.full
fill = np.random.uniform(self.fill[0], self.fill[1])
fill = 1 if full else fill
fill = np.clip(fill, 0, bound)
padding = np.random.randint(4) if col > 1 else np.random.randint(1, 4)
padding = (bool(padding // 2), bool(padding % 2))
weights = np.zeros(col * 2 + 1)
weights[1:-1] = text_size / width
probs = 1 - np.random.rand(col * 2 + 1)
probs[0] = 0 if not padding[0] else probs[0]
probs[-1] = 0 if not padding[-1] else probs[-1]
probs[1::2] *= max(fill - sum(weights[1::2]), 0) / sum(probs[1::2])
probs[::2] *= max(1 - fill - sum(weights[::2]), 0) / sum(probs[::2])
weights += probs
widths = [width * weights[c] for c in range(col * 2 + 1)]
heights = [text_size for _ in range(row)]
xs = np.cumsum([0] + widths)
ys = np.cumsum([0] + heights)
layout = []
for c in range(col):
align = self.align[np.random.randint(len(self.align))]
for r in range(row):
x, y = xs[c * 2 + 1], ys[r]
w, h = xs[c * 2 + 2] - x, ys[r + 1] - y
bbox = [left + x, top + y, w, h]
layout.append((bbox, align))
return layout
"""
Donut
Copyright (c) 2022-present NAVER Corp.
MIT License
"""
import numpy as np
from layouts import Grid
class GridStack:
def __init__(self, config):
self.text_scale = config.get("text_scale", [0.05, 0.1])
self.max_row = config.get("max_row", 5)
self.max_col = config.get("max_col", 3)
self.fill = config.get("fill", [0, 1])
self.full = config.get("full", 0)
self.align = config.get("align", ["left", "right", "center"])
self.stack_spacing = config.get("stack_spacing", [0, 0.05])
self.stack_fill = config.get("stack_fill", [1, 1])
self.stack_full = config.get("stack_full", 0)
self._grid = Grid(
{
"text_scale": self.text_scale,
"max_row": self.max_row,
"max_col": self.max_col,
"align": self.align,
}
)
def generate(self, bbox):
left, top, width, height = bbox
stack_spacing = np.random.uniform(self.stack_spacing[0], self.stack_spacing[1])
stack_spacing *= min(width, height)
stack_full = np.random.rand() < self.stack_full
stack_fill = np.random.uniform(self.stack_fill[0], self.stack_fill[1])
stack_fill = 1 if stack_full else stack_fill
full = np.random.rand() < self.full
fill = np.random.uniform(self.fill[0], self.fill[1])
fill = 1 if full else fill
self._grid.fill = [fill, fill]
layouts = []
line = 0
while True:
grid_size = (width, height * stack_fill - line)
text_scale = np.random.uniform(self.text_scale[0], self.text_scale[1])
text_size = min(width, height) * text_scale
text_scale = text_size / min(grid_size)
self._grid.text_scale = [text_scale, text_scale]
layout = self._grid.generate([left, top + line, *grid_size])
if layout is None:
break
line = max(y + h - top for (_, y, _, h), _ in layout) + stack_spacing
layouts.append(layout)
line = max(line - stack_spacing, 0)
space = max(height - line, 0)
spaces = np.random.rand(len(layouts) + 1)
spaces *= space / sum(spaces) if sum(spaces) > 0 else 0
spaces = np.cumsum(spaces)
for layout, space in zip(layouts, spaces):
for bbox, _ in layout:
x, y, w, h = bbox
bbox[:] = [x, y + space, w, h]
return layouts
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
This source diff could not be displayed because it is too large. You can view the blob instead.
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment