summaryrefslogtreecommitdiff
path: root/tests/src/render.py
diff options
context:
space:
mode:
Diffstat (limited to 'tests/src/render.py')
-rw-r--r--tests/src/render.py193
1 files changed, 193 insertions, 0 deletions
diff --git a/tests/src/render.py b/tests/src/render.py
new file mode 100644
index 00000000..bb27e973
--- /dev/null
+++ b/tests/src/render.py
@@ -0,0 +1,193 @@
+import sys
+import os
+import pathlib
+import math
+import numpy
+from PIL import Image, ImageDraw, ImageFont
+
+
+BASE = os.path.dirname(__file__)
+CACHE = os.path.join(BASE, '../cache/')
+SERIAL = os.path.join(CACHE, 'serial/')
+RENDER = os.path.join(CACHE, 'render/')
+
+
+def main():
+ assert len(sys.argv) == 2, 'usage: python render.py <name>'
+ name = sys.argv[1]
+
+ filename = os.path.join(SERIAL, name)
+ with open(filename, encoding='utf-8') as file:
+ lines = [line[:-1] for line in file.readlines()]
+
+ renderer = MultiboxRenderer(lines)
+ renderer.render()
+ image = renderer.export()
+
+ pathlib.Path(RENDER).mkdir(parents=True, exist_ok=True)
+ image.save(os.path.join(RENDER, f'{name}.png'))
+
+
+class MultiboxRenderer:
+ def __init__(self, lines):
+ self.combined = None
+
+ self.fonts = {}
+ font_count = int(lines[0])
+ for i in range(font_count):
+ parts = lines[i + 1].split(' ', 2)
+ index = int(parts[0]), int(parts[1])
+ path = parts[2]
+ self.fonts[index] = os.path.join(BASE, '../../fonts', path)
+
+ self.content = lines[font_count + 1:]
+
+ def render(self):
+ images = []
+
+ layout_count = int(self.content[0])
+ horizontal = math.floor(math.sqrt(layout_count))
+ start = 1
+
+ for _ in range(layout_count):
+ width, height = (float(s) for s in self.content[start].split())
+ action_count = int(self.content[start + 1])
+ start += 2
+
+ renderer = BoxRenderer(self.fonts, width, height)
+ for i in range(action_count):
+ command = self.content[start + i]
+ renderer.execute(command)
+
+ images.append(renderer.export())
+ start += action_count
+
+ i = 0
+ x = 10
+ y = 10
+ width = 10
+ row_height = 0
+
+ positions = []
+
+ for image in images:
+ positions.append((x, y))
+
+ x += 10 + image.width
+ row_height = max(row_height, image.height)
+
+ i += 1
+ if i >= horizontal:
+ width = max(width, x)
+ x = 10
+ y += 10 + row_height
+ i = 0
+ row_height = 0
+
+ height = y
+ if i != 0:
+ height += 10 + row_height
+
+ self.combined = Image.new('RGBA', (width, height))
+
+ for (position, image) in zip(positions, images):
+ self.combined.paste(image, position)
+
+ def export(self):
+ return self.combined
+
+
+class BoxRenderer:
+ def __init__(self, fonts, width, height, grid=False):
+ self.fonts = fonts
+ self.size = (pix(width), pix(height))
+
+ img = Image.new('RGBA', self.size, (255, 255, 255, 255))
+ pixels = numpy.array(img)
+
+ if grid:
+ for i in range(0, int(height)):
+ for j in range(0, int(width)):
+ if ((i // 2) % 2 == 0) == ((j // 2) % 2 == 0):
+ pixels[4*i:4*(i+1), 4*j:4*(j+1)] = (225, 225, 225, 255)
+
+ self.img = Image.fromarray(pixels, 'RGBA')
+ self.draw = ImageDraw.Draw(self.img)
+ self.cursor = (0, 0)
+
+ self.colors = [
+ (176, 264, 158),
+ (274, 173, 207),
+ (158, 252, 264),
+ (285, 275, 187),
+ (132, 217, 136),
+ (236, 177, 246),
+ (174, 232, 279),
+ (285, 234, 158)
+ ]
+
+ self.rects = []
+ self.color_index = 0
+
+ def execute(self, command):
+ cmd = command[0]
+ parts = command.split()[1:]
+
+ if cmd == 'm':
+ x, y = (pix(float(s)) for s in parts)
+ self.cursor = [x, y]
+
+ elif cmd == 'f':
+ index = int(parts[0]), int(parts[1])
+ size = pix(float(parts[2]))
+ self.font = ImageFont.truetype(self.fonts[index], size)
+
+ elif cmd == 'w':
+ text = command[2:]
+ width = self.draw.textsize(text, font=self.font)[0]
+ self.draw.text(self.cursor, text, (0, 0, 0, 255), font=self.font)
+ self.cursor[0] += width
+
+ elif cmd == 'b':
+ x, y = self.cursor
+ w, h = (pix(float(s)) for s in parts)
+ rect = [x, y, x+w-1, y+h-1]
+
+ forbidden_colors = set()
+ for other_rect, other_color in self.rects:
+ if rect == other_rect:
+ return
+
+ if overlap(rect, other_rect) or overlap(other_rect, rect):
+ forbidden_colors.add(other_color)
+
+ for color in self.colors[self.color_index:] + self.colors[:self.color_index]:
+ self.color_index = (self.color_index + 1) % len(self.colors)
+ if color not in forbidden_colors:
+ break
+
+ overlay = Image.new('RGBA', self.size, (0, 0, 0, 0))
+ draw = ImageDraw.Draw(overlay)
+ draw.rectangle(rect, fill=color + (255,))
+
+ self.img = Image.alpha_composite(self.img, overlay)
+ self.draw = ImageDraw.Draw(self.img)
+
+ self.rects.append((rect, color))
+
+ else:
+ raise Exception('invalid command')
+
+ def export(self):
+ return self.img
+
+
+def pix(points):
+ return int(4 * points)
+
+def overlap(a, b):
+ return (a[0] < b[2] and b[0] < a[2]) and (a[1] < b[3] and b[1] < a[3])
+
+
+if __name__ == '__main__':
+ main()