Skip to content

Instantly share code, notes, and snippets.

@shpaker
Last active May 12, 2021 08:32
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shpaker/2679cc6c8f13e315d8cf52a113b6f580 to your computer and use it in GitHub Desktop.
Save shpaker/2679cc6c8f13e315d8cf52a113b6f580 to your computer and use it in GitHub Desktop.
userpic_as_gh_generator
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