Generator of custom Falchats identicons to be used as icons. https://cfbrk.de/static/falchicon-today.png
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 

226 lines
6.4 KiB

from PIL import Image, ImageDraw, ImageOps
import os
import re
SIZE = 512
RASTER = 8
SCALE = SIZE/RASTER
full = int(SIZE)
half = int(SIZE/2)
quarter = int(SIZE/4)
eight = int(SIZE/8)
bib_file = os.path.join(os.path.split(__file__)[0], "resources/bib.png")
bib_img = Image.open(bib_file)
bib_img_8 = bib_img.resize((full, full))
bib_img_4 = bib_img.resize((half, half))
bib_img_2 = bib_img.resize((quarter, quarter))
bib_img_1 = bib_img.resize((eight, eight))
def get_image():
return Image.new('RGB', (SIZE, SIZE), color='#ddd')
def to_binary(dhash, pad=256):
return bin(int(dhash, 16))[2:].zfill(pad)
def horizontal(point):
return (RASTER-point[0]-1, point[1])
def vertical(point):
return (point[0], RASTER-point[1]-1)
def diagonal(point):
return horizontal(vertical(point))
def scale(point, offset=0, reverse=False):
if reverse:
return (int(float(point[0])/SCALE - offset), int(float(point[1])/SCALE - offset))
return (int((point[0] + offset) * SCALE), int((point[1] + offset) * SCALE))
def square(img, draw, point, color='#666', secondary='#000', kind=None):
draw.rectangle([scale(point), scale(point,1)], fill=color, outline=None)
def bib(img, draw, point, color='#666', secondary='#000', kind=None, source=bib_img_1, raster=1):
op = None
if kind == None:
pass
elif kind == horizontal:
op = Image.FLIP_LEFT_RIGHT
point = (point[0] - raster + 1, point[1])
elif kind == vertical:
op = Image.FLIP_TOP_BOTTOM
point = (point[0], point[1] - raster + 1)
elif kind == diagonal:
op = Image.TRANSPOSE
point = (point[0] - raster + 1, point[1] - raster + 1)
bib_i = source
if op != None:
bib_i = source.transpose(op)
bib_i_col = ImageOps.colorize(bib_i.split()[0], secondary, color)
img.paste(bib_i_col, tuple(x+1 for x in scale(point)), mask=bib_i)
def bib_1(img, draw, point, color='#666', secondary='#000', kind=None):
bib(img, draw, point, color, secondary, kind, bib_img_1, 1)
def bib_2(img, draw, point, color='#666', secondary='#000', kind=None):
bib(img, draw, point, color, secondary, kind, bib_img_2, 2)
def bib_4(img, draw, point, color='#666', secondary='#000', kind=None):
bib(img, draw, point, color, secondary, kind, bib_img_4, 4)
def bib_8(img, draw, point, color='#666', secondary='#000', kind=None):
bib(img, draw, point, color, secondary, kind, bib_img_8, 8)
def mirror(img, draw, point, func, kind, color='#666', secondary='#000', dhash = "".zfill(64)):
func(img, draw, point, color=color, secondary=secondary)
if kind == diagonal and func in [bib_1, bib_2, bib_4, bib_8] and int(dhash[19], 16) > 4:
func(img, draw, kind(point), color=secondary, secondary=color, kind=kind)
else:
func(img, draw, kind(point), color=color, secondary=secondary, kind=kind)
def rectangle_gradient(img, draw, center, color, secondary, kind=None, dhash = "".zfill(64), func=abs):
col1 = color
col2 = secondary
if re.match('#[0-9a-fA-F]{3}', color):
col1 = [int(color[1], 16) * 16, int(color[2], 16) * 16, int(color[3], 16) * 16]
if re.match('#[0-9a-fA-F]{3}', secondary):
col2 = [int(secondary[1], 16) * 16, int(secondary[2], 16) * 16, int(secondary[3], 16) * 16]
s = img.size
for x in range(s[0]):
for y in range(s[1]):
d = func(min(abs(x-SIZE), x, abs(y-SIZE), y) / (SIZE/2.0))
r = col1[0] * d + col2[0] * (1-d)
g = col1[1] * d + col2[1] * (1-d)
b = col1[2] * d + col2[2] * (1-d)
img.putpixel((x,y), (int(r), int(g), int(b)))
def get_color_primary(dhash):
return f"#{dhash[:3]}"
def get_color_secondary(dhash):
return f"#{dhash[3:6]}"
def get_color_background(dhash):
return "#ddd"
def get_kind_primary(dhash):
n = int(dhash[6], 16)
if n < 6:
return horizontal
elif n < 13:
return vertical
else:
return diagonal
def get_kind_secondary(dhash):
return get_kind_primary(dhash)
def get_kind_bib(dhash):
n = int(dhash[7], 16)
if n < 5:
return horizontal
elif n < 10:
return vertical
else:
return diagonal
def get_bib_size(dhash, i=0):
n = int(dhash[14+i*2:16+i*2], 16)
if n == 0:
return 0
elif n <= 16*(i+1):
return 1 - i
elif n <= 128*(i+1):
return 2 - i
elif n <= 228*(i+1):
return 4 - i*2
else:
return 8 - i*4
def bib_func_for_size(size):
if size == 0:
return None
elif size == 1:
return bib_1
elif size == 2:
return bib_2
elif size == 4:
return bib_4
elif size == 8:
return bib_8
else:
return None
def get_colors(dhash):
return (f(dhash) for f in [get_color_primary, get_color_secondary, get_color_background])
def put_hash(img, dhash):
draw = ImageDraw.Draw(img)
primary, secondary, background = get_colors(dhash)
primary_kind, secondary_kind = (get_kind_primary(dhash), get_kind_secondary(dhash))
grad = int(dhash[24], 16)
if grad & 0b1110:
if grad & 0b0001:
rectangle_gradient(img, draw, (4,4), primary, secondary)
elif grad & 0b1000:
rectangle_gradient(img, draw, (4,4), secondary, primary)
pattern = []
for i in range(4):
bits = dhash[8+i*2:10+i*2]
pattern.append([c == '1' for c in to_binary(bits, RASTER)])
pos_x = 0
pos_y = 0
for row in pattern:
for x in row:
if x:
mirror(img, draw, (RASTER-pos_x-1, RASTER-pos_y-1), square, secondary_kind, color=secondary, secondary=background)
pos_x += 1
pos_y += 1
pos_x = 0
pos_x = 0
pos_y = 0
for row in pattern:
for x in row:
if x:
mirror(img, draw, (pos_x, pos_y), square, primary_kind, color=primary, secondary=secondary)
pos_x += 1
pos_y += 1
pos_x = 0
bs2 = get_bib_size(dhash, i=1)
if bs2 != 0:
bf = bib_func_for_size(bs2)
mirror(img,draw, (int(dhash[19], 16) % (4-bs2), int(dhash[20], 16) % (4-bs2)), bf, secondary_kind,
color=secondary, secondary=primary, dhash=dhash)
bs = get_bib_size(dhash)
if bs != 0:
bf = bib_func_for_size(bs)
#mirror(img, draw,(0,0), bib_2, diagonal, color=primary, secondary=secondary)
mirror(img, draw,(int(dhash[17], 16) % (12-bs), int(dhash[18], 16) % (12-bs)), bf, primary_kind, color=primary, secondary=secondary, dhash=dhash)