Skip to content

Instantly share code, notes, and snippets.

@lynzrand
Created October 25, 2020 11:33
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 lynzrand/5e1c5085156f72d0ed1dafd80ea6beed to your computer and use it in GitHub Desktop.
Save lynzrand/5e1c5085156f72d0ed1dafd80ea6beed to your computer and use it in GitHub Desktop.
from typing import List, Tuple
from PIL import Image, ImageDraw, ImageColor
import math
import random
from PIL.Image import new
from PIL.ImageDraw import Draw
def gen_saturated_color() -> Tuple[int, int, int]:
random.seed()
if random.uniform(0, 1) > 0.4:
return (0, 0, 0)
else:
hue = random.uniform(0, 1)
saturation = random.triangular(0, 1)**0.1
value = random.gauss(0.5, 0.2)
value = min(max(value, 0), 1)
return ImageColor.getrgb("hsl({},{}%,{}%)".format(
int(hue * 360), saturation * 100, value * 100))
def gen_saturated_color_alpha() -> Tuple[int, int, int, int]:
random.seed()
if random.uniform(0, 1) > 0.4:
return (0, 0, 0, 0)
else:
hue = random.uniform(0, 1)
saturation = random.triangular(0, 1)**0.1
value = random.gauss(0.5, 0.2)
value = min(max(value, 0), 1)
(r, g, b) = ImageColor.getrgb("hsl({},{}%,{}%)".format(
int(hue * 360), saturation * 100, value * 100))
return (r, g, b, 255)
def draw_glitch_line(image: Image.Image, line_height: int):
line_num = math.ceil(image.height / line_height)
total_width = line_num * image.width
lines = gen_glitch_lines(total_width, line_height / 2,
math.sqrt(image.width) / line_height, 2.3)
cur_width = 0
draw = ImageDraw.Draw(image)
for line in lines:
new_width = cur_width + line[0]
cur_line_num = int(cur_width / image.width)
end_line_num = int(new_width / image.width)
if end_line_num != cur_line_num:
# draw multi-line glitch
# line 0
x0 = cur_width % image.width
y0 = cur_line_num * line_height
x1 = image.width
y1 = (cur_line_num + 1) * line_height
draw.rectangle([x0, y0, x1, y1], fill=line[1])
if end_line_num - cur_line_num > 1:
# line 2--n-1
x0 = 0
y0 = (cur_line_num + 1) * line_height
x1 = image.width
y0 = end_line_num * line_height
draw.rectangle([x0, y0, x1, y1], fill=line[1])
# line n
x0 = 0
y0 = (end_line_num) * line_height
x1 = new_width % image.width
y1 = (end_line_num + 1) * line_height
draw.rectangle([x0, y0, x1, y1], fill=line[1])
else:
# draw single-line glitch
x0 = cur_width % image.width
y0 = cur_line_num * line_height
x1 = new_width % image.width
y1 = (cur_line_num + 1) * line_height
draw.rectangle([x0, y0, x1, y1], fill=line[1])
cur_width = new_width
def gen_glitch_lines(
total_width: int, cell_size: int, expected_width: float,
width_fluctuate: float) -> List[Tuple[int, Tuple[int, int, int]]]:
current_width = 0
lines = []
while current_width < total_width:
line_width = round(
round(
math.exp(
random.normalvariate(math.log(expected_width),
width_fluctuate)) / cell_size) *
cell_size)
if line_width == 0: continue
line_color = gen_saturated_color()
current_width += line_width
lines.append((line_width, line_color))
return lines
def draw_glitch_units(img: Image.Image, unit_size: int, density: float):
unit_per_line = math.ceil(img.width / unit_size)
unit_count = unit_per_line * math.ceil(img.height / unit_size)
draw_unit_count = int(unit_count * density)
for i in range(draw_unit_count):
unit_graph = Image.new("RGBA", (unit_size, unit_size))
for x in range(unit_size):
for y in range(unit_size):
unit_graph.putpixel((x, y), gen_saturated_color_alpha())
consecutive_units = max(1, min(int(random.gauss(2, 3)), 32))
base_unit_pos = round(random.uniform(0, unit_count))
for i1 in range(consecutive_units):
unit_pos = base_unit_pos + i1
unit_left = int(unit_pos % unit_per_line) * unit_size
unit_top = int(unit_pos / unit_per_line) * unit_size
img.paste(unit_graph, (unit_left, unit_top), unit_graph)
dpi = 150
real_size = (210.0, 297.0)
# size = (int(real_size[0] / 2.54 * dpi), int(real_size[1] / 2.54 * dpi))
size = (2560, 1440)
for i in range(50):
print("Drawing image {}".format(i))
img = Image.new('RGB', size)
draw_glitch_line(img, 16)
draw_glitch_units(img, 16, 0.007)
img.save("glitch-{:04}.png".format(i), "png")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment