asc2svg

asc2svg was intended to be an ASCII diagrams to SVG, like `ditaa` and Svgbob
Log | Files | Refs

commit 3053fb05850ba451985b2563b54f2f22abbdb29e
Author: bkopf <vetlehaf@stud.ntnu.no>
Date:   Sat, 17 Nov 2018 04:29:35 +0100

Initial commit with basic rectangle detector

Diffstat:
Aa2svg.py | 230+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Aascii.txt | 30++++++++++++++++++++++++++++++
2 files changed, 260 insertions(+), 0 deletions(-)

diff --git a/a2svg.py b/a2svg.py @@ -0,0 +1,230 @@ +#!/bin/python + + +class Figure: + def __init__(self, ascii_text): + self._elements = [] + self._ascii_text = [line.strip('\n') for line in ascii_text] + self._height = len(ascii_text) + self._width = max([len(line) for line in ascii_text]) + + # NEW KNOWLEDGE: Using [[' ']*width]*height just makes `height` number of *copies* (!) of the inner list + # In other words, every change you make to one of the lists will be applied to *all* of them.. :( + # Using append instead, to avoid this + + # Make a '2d list' to keep track of processed characters + self._processed = [[False]*self._width] + for y in range(self._height - 1): + self._processed.append([False]*self._width) + + # Make a '2d list' of the asci figure + self._figarray = [[' ']*self._width] + for y in range(self._height - 1): + self._figarray.append([' ']*self._width) + + for y, line in enumerate(self._ascii_text): + for x, cell in enumerate(line): + self._figarray[y][x] = cell + + def process(self): + for y in range(self._height): + for x in range(self._width): + if not self._processed[y][x]: + self.process_char(y, x) + + def get_elements(self): + return self._elements + + def get_array(self): + return self._figarray + + def process_char(self, y, x): + symbol = self._figarray[y][x] + if symbol == '+': + new_element = Joint((y, x)) + rect = self.rectangle(y, x) + if rect: + rect.extract_text(self) + self._elements.append(rect) + if symbol == '-': + new_element = Line((y, x)) + if symbol == '|': + new_element = Line((y, x), vertical=True) + + #new_element.process() + self._processed[y][x] = True + + + """ + Checks if a joint belongs to a rectangle. + If it does, the rectangle is added as an element + """ + def rectangle(self, y_start, x_start): + if x_start + 1 >= self._width: + return None + y = y_start + 1 + # 1. Find the vertical stop of the rectangle, if any + y_stop = None + while not y_stop and y < self._height: + cell = self._figarray[y][x_start] + if cell == '|': + y += 1 + continue + elif cell == '+' and self._figarray[y][x_start+1]: + y_stop = y + break + else: + break + + if not y_stop: + return None + + # 2. Find the horisontal stop, if any + x_stop = None + x = x_start + 1 + while not x_stop and x < self._width: + upper_cell = self._figarray[y_start][x] + lower_cell = self._figarray[y_stop][x] + if upper_cell == '+' and lower_cell == '+': + x_stop = x + # Check that there's a line from upper cell to lower + for y_test in range(y_start+1, y_stop): + cell = self._figarray[y_test][x] + if cell != '|' and cell != '+': + x_stop = None + break + if x_stop: + break + else: + continue + if upper_cell != '-' and upper_cell != '+': + break + if lower_cell != '-' and lower_cell != '+': + break + x += 1 + + if not x_stop: + return None + + # By this point, we know we have a rectangle + return Rectangle((x_start, y_start), (x_stop, y_stop)) + + + """Return SVG text of the entire figure""" + # <rect x="80" y="3" width="80" height="12" fill="white" stroke="black"></rect> + def draw_svg(self): + svg_text = "" + for el in self._elements: + svg_text += el.draw() + "\n" + return svg_text + +class Rectangle: + def __init__(self, pos_start, pos_stop): + (self._x_start, self._y_start) = pos_start + (self._x_stop, self._y_stop) = pos_stop + self._text_lines = [None] + + def extract_text(self, fig): + self._text_lines = [] + figarray = fig.get_array() + for y in range(self._y_start+1, self._y_stop): + line = ''.join(figarray[y][self._x_start+1:self._x_stop]) + self._text_lines.append(line) + + def __str__(self): + return_string = "Rect, ({}, {}) to ({}, {}):".format( + self._y_start, + self._x_start, + self._y_stop, + self._x_stop, + ) + for line in self._text_lines: + return_string += line + "\n" + + return return_string + + def draw(self): + font_size = 12 + svg_text = "\t<rect x=\"{}\" y=\"{}\" ".format( + self._x_start * font_size, + self._y_start * font_size) + rect_width = (self._x_stop - self._x_start) * font_size + rect_height = (self._y_stop - self._y_start) * font_size + svg_text += "width=\"{}\" height=\"{}\" ".format( + rect_width/2, + rect_height) + svg_text += "fill=\"white\" stroke=\"black\"></rect>\n" + + for ln, line in enumerate(self._text_lines): + svg_text += "\t<text x=\"{}\" y=\"{}\" font-family=\"Arial\" font-size=\"{}\" fill=\"black\">{}</text>\n".format( + self._x_start*font_size+15, + (self._y_start+ln)*font_size+15, + font_size, + line + ) + + return svg_text + + +class Joint: + def __init__(self, position): + # (pos should be a tuple) + (self._x, self._y) = position + + + + pass + + def get_position(self): + return (self._x, self._y) + + def process(self): + pass + + def find_connected(self, figure): + self._connected = [] + #if self._x > 0 and + + def get_connected(self): + return self._connected + +class Line: + def __init__(self, start_pos, vertical=False): + self._start = start_pos + self._end = None#end_pos + pass + + def process(): + pass + + def draw(): + pass + +class Arrow(): + pass + +def print_farray(figure_array): + for row in figure_array: + for cell in row: + print(cell, end="") + print() + + +with open("ascii.txt") as f: + ascii_text = f.readlines() + f.close() + +drawing = Figure(ascii_text) +drawing.process() +for el in drawing.get_elements(): + el.extract_text(drawing) + print(el) + +svg_text = "<svg xmlns=\"http://www.w3.org/2000/svg\">\n" +svg_text += drawing.draw_svg() +svg_text += "</svg>" + +#file:///home/vh/nextcloud/git/general/snippets/test.svg +with open("test.svg", "w+") as f: + f.write(svg_text) + f.close() diff --git a/ascii.txt b/ascii.txt @@ -0,0 +1,30 @@ + + + + +----------------+ + | |<----+ + | | | + +----------------+ | + | + | + +---------------------+ + +----->| unexpected | + | +---------------------+ + | ++----------------+ +----------------------+ +| Block 1 | | Additional block | ++----------------+ +----------+-----------+ + | | + | +----------------------+ + +--------->| Second block | + +----------------------+ + | | + | - List of stuff here | + | - Good stuff too, | + | I'd say | + | | + | | + | | + | | + | | + +----------------------+