Last active
May 12, 2021 08:32
-
-
Save shpaker/2679cc6c8f13e315d8cf52a113b6f580 to your computer and use it in GitHub Desktop.
userpic_as_gh_generator
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import random | |
from typing import List | |
from jinja2 import Template | |
SVG_TEMPLATE = Template("""<?xml version="1.0"?> | |
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> | |
<svg xmlns="http://www.w3.org/2000/svg" width="467" height="462"> | |
{% for y_i, dots in enumerate(dots_data) %}{% for x_i, dot in enumerate(dots) %} | |
<rect x="{{ x_i * w_size }}" | |
y="{{ y_i * h_size }}" | |
width="{{ w_size }}" | |
height="{{ h_size }}" | |
style="fill:#{% if dot == True %}{{ first_color }}{% else %}{{ second_color }}{% endif %}" />{% endfor %} | |
{% endfor %} | |
</svg> | |
""") | |
def random_bool() -> bool: | |
return bool(random.randint(0, 1)) | |
def generate_line(width: int): | |
line = [random_bool() for i in range(width)] | |
if len(set(line)) == 1: | |
line = generate_line(width) | |
return line | |
def generate_part(width: int, height: int): | |
part = [generate_line(width) for j in range(height)] | |
return part | |
def reverse_part(part): | |
return [reversed(i) for i in part] | |
def concatenate_parts(left_part, spacer, right_part): | |
result = list() | |
for i, left_line in enumerate(left_part): | |
right_line = right_part[i] | |
spacer_line = spacer[i] | |
line = [*left_line, *spacer_line, *right_line] | |
result.append(line) | |
return result | |
def generate_userpic_data(width, height): | |
left = generate_part(width // 2, height) | |
spacer = generate_part(width % 2, height) | |
right = reverse_part(left) | |
return concatenate_parts(left, spacer, right) | |
def encode_userpic_data(data: List[List[bool]]) -> str: | |
bytes_data = 0 | |
width = len(data[0]) | |
encoded_len = width // 2 + width % 2 | |
for line in data: | |
for value in line[:encoded_len]: | |
bytes_data = bytes_data << 1 | int(value) | |
encoded_as_int: int = int(f"{bytes_data}{encoded_len:0>2}") | |
return f"{encoded_as_int:x}" | |
def decode_userpic_data(encoded_as_hex: str) -> List[List[bool]]: | |
encoded_as_int = int(encoded_as_hex, 16) | |
width = encoded_as_int % 100 | |
encoded_data = encoded_as_int // 100 | |
width_is_odd = width % 2 == 0 | |
lines = list() | |
while encoded_data: | |
line = list() | |
for i in range(width): | |
line.append(bool(encoded_data & 1)) | |
encoded_data = encoded_data >> 1 | |
reversed_left = line if width_is_odd else line[1:] | |
lines.insert(0, [*reversed(reversed_left), *line]) | |
return lines | |
def write_svg_data(data, h_size: int, w_size: int, first_color: str, second_color: str, filename: str): | |
svg_data = SVG_TEMPLATE.render(enumerate=enumerate, | |
dots_data=data, | |
h_size=h_size, | |
w_size=w_size, | |
first_color=first_color, | |
second_color=second_color) | |
with open(filename, "w") as file: | |
file.write(svg_data) | |
def main(): | |
width = 8 | |
height = 8 | |
h_size = 12 | |
w_size = 12 | |
first_color = "000000" | |
second_color = "aaaaff" | |
userpic_data = generate_userpic_data(width, height) | |
write_svg_data(userpic_data, h_size, w_size=w_size, first_color=first_color, second_color=second_color, | |
filename="test.svg", ) | |
encoded = encode_userpic_data(userpic_data) | |
print(userpic_data) | |
print(encoded) | |
print(decode_userpic_data(encoded)) | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment